The steps to create an empty PSoC 6 project and run FreeRTOS on the CM4 core. |
It's easy to set up a FreeRTOS project in ModusToolbox. The simplest way is to start from one of the examples of the IDE's Application Creator.
But adding FreeRTOS to a project is straightforward too. And it allows you to select the newest version. In my case 10.3.
Start an empty project
File > New > ModusToolbox Application
Select the PSoC empty project for your board:
I use the WiFi BT prototyping kit, so I selected that one. Press Next.
Look up and select the empty project. Rename it (I used PSoC6_FreeRTOS_10_3). Press Create.
Once the wizard generated the project, press Close and return to the IDE.
Add FreeRTOS 10.3
With the project active, select the Library Manager in the Quick Panel.
On the Libraries tab, select freertos, shared, and version 10.3.1 release (or the version you want to use).
Click Update, then Close when finished. Return to the IDE.
Then, add a FreeRTOSConfig.h file to your project. You do that by copying the one from the shared FreeRTOS area into your project:
Paste this in the root of your project.
Then open that copied file, and remove the "#warning This is a template. Copy this file to your project and remove this line" line.
As last step in the preparation, add this to the include section of your main.c file:
#include "FreeRTOS.h"
Edit the Make file
Now a step that was not needed for the rtos version 10.1xxx. But if you don't do it for 10.3, your build will fail:
Open the Makefile by double-clicking it. You find it in the root of your project.
Update the COMPONENTS section:
COMPONENTS=FREERTOS
Now that we are in the make file, let's also change the name of the output file. It's called mtb-example-psoc6-empty-app by default. See the orange part of the image above.
APPNAME=mtb-example-psoc6-freertos-10-3-app
When you change the output file name, you need to update the execution configuration.
You do that by, after saving the make file, clicking the Generate Launches option in the Quick Panel. See the blue part in the image.
This is a good time to do a first build. If it succeeds, you know you have a good start.
Add a Task and Start FreeRTOS
We're going to make a blinky (I tried to keep that a secret until the end of the post ).
Our project will have one FreeRTOS task that will toggle the led every time it's activated by the scheduler.
The Task
I will discuss the task first, and then the activities to configure the LED and schedule the task.
void task_blink(void* param) { /* Suppress warning for unused parameter */ (void) param; /* Repeatedly running part of the task */ for (;;) { cyhal_gpio_toggle(CYBSP_USER_LED); vTaskDelay(pdMS_TO_TICKS(1000)); } }
The task is very simple. A LED is toggled, and the task yields to the RTOS scheduler for one second. In an ever lasting loop.
The effect is that the led will blink every 2 seconds:
- LED toggle
- yield for a second
During the Delay, the task is inactive and the scheduler can execute other tasks.
This is different to delay mechanisms that use MCU ticks to burn time. Those occupy the MCU for a second. The FreeRTOS vTaskDelay() task frees the MCU for a second.
I've put the task in a separate header and source file:
task_blink.h
#ifndef SOURCE_TASK_BLINK_H_ #define SOURCE_TASK_BLINK_H_ #include "FreeRTOS.h" #include "task.h" void task_blink(void* param); #endif /* SOURCE_TASK_BLINK_H_ */
task_blink.c
#include "cybsp.h" #include "cyhal.h" #include "FreeRTOS.h" #include "cycfg.h" #include "task_blink.h" void task_blink(void* param) { /* Suppress warning for unused parameter */ (void) param; /* Repeatedly running part of the task */ for (;;) { cyhal_gpio_toggle(CYBSP_USER_LED); vTaskDelay(pdMS_TO_TICKS(1000)); } }
The Scheduler
In the main() function, create and register the task, then start the scheduler:
xTaskCreate(task_blink, "blink task", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 7, NULL); vTaskStartScheduler(); /* RTOS scheduler exited */ /* Halt the CPU if scheduler exits */ CY_ASSERT(0); for (;;) { }
The first call registers our task. The constants in the parameters are defined in the FreeRTOSConfig.h file you placed in the project root.
Then the scheduler is started. In a FreeRTOS project, this call is going to be active forever. Any line of code below that should never run.
The last thing to discuss here is that the hardware has to be initialised before it will be used. In our case, the LED:
/* Initialize the User LED */ result = cyhal_gpio_init(CYBSP_USER_LED, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, CYBSP_LED_STATE_OFF); /* GPIO init failed. Stop program execution */ if (result != CY_RSLT_SUCCESS) { CY_ASSERT(0); }
You may have to adapt this (and the task) to use an LED that's available on your board. I think that CYBSP_USER_LED is available on all evaluation kits, but I'm not sure.
main.c
#include "cy_pdl.h" #include "cyhal.h" #include "cybsp.h" #include "FreeRTOS.h" #include "task.h" #include "task_blink.h" int main(void) { cy_rslt_t result; /* Initialize the device and board peripherals */ result = cybsp_init(); if (result != CY_RSLT_SUCCESS) { CY_ASSERT(0); } /* Initialize the User LED */ result = cyhal_gpio_init(CYBSP_USER_LED, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, CYBSP_LED_STATE_OFF); /* GPIO init failed. Stop program execution */ if (result != CY_RSLT_SUCCESS) { CY_ASSERT(0); } __enable_irq(); xTaskCreate(task_blink, "blink task", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 7, NULL); vTaskStartScheduler(); /* RTOS scheduler exited */ /* Halt the CPU if scheduler exits */ CY_ASSERT(0); for (;;) { } }
This is it. Build the project, then execute it on your board.
The end result is a blinking LED.
The project I used for this post is attached.
Top Comments