Using Native FreeRTOS in STM32 Microcontrollers

STM32CubeMX is a very easy to use configuration and code generation tool for STM32 microcontrollers. It comes with middleware packages, like FreeRTOS. By default, FreeRTOS is indirectly invoked via CMSIS-OS wrapper APIs which are designed to switch between different underlying OSes such as FreeRTOS, RTX Kernel. However, employing CMSIS-OS wrapper APIs is not succinct, causing difficulties for using FreeRTOS documents and libraries.

In this article, I will show how to use native FreeRTOS in my STM32F0Discovery board. Tools involved are STM32CubeMX and STM32CubeIDE, both of which are provided for free by STMicro.

Configuration and Code Generation

STM32CubeMX is used to configure the MCU and generate initialization code.

First, click File -> New Project, then in the opened dialog, select STM32F0Discovery, and click Start Project.

Select STM32F0Discovery
Select STM32F0Discovery

In FREERTOS tab of Pinout & Configuration view, select CMSIS-V1 as FreeRTOS interface.

Configure timebase source
Configure timebase source

In SYS tab of Pinout & Configuration view, select TIM1 as timebase source. It is recommended to use a HAL timebase source (TIM1, in this case) other than systick.

Configure FreeRTOS interface
Configure FreeRTOS interface

In Project tab of Project Manager view, fill in a project name and a toolchain/IDE (STM32CubeIDE, in this case).

Configure project name and IDE
Configure project name and IDE

After the above steps, click GENERATE CODE, and wait for a few seconds. Then open the project in STM32CubeIDE.

Removing CMSIS-OS Wrapper

To get rid of CMSIS-OS wrapper, we need to copy FreeRTOS headers to main.h first.

In main.c of the opened project, find the following line (it can be deleted after copying FreeRTOS headers to main.h):

#include "cmsis_os.h"

Right click on the file name “cmsis_os.h”, and choose Open Declaration.

In cmsis_os.h, find the following lines:

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"

Copy the 6 lines above to main.h, put them below the following line:

#include "stm32f0xx_hal.h"

Then we can delete example code generated by STM32CubeMX.

In main.c, find and delete the following lines:

#include "cmsis_os.h"
// ...
osThreadId defaultTaskHandle;
// ...
void StartDefaultTask(void const * argument);
// ...
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
// ...
osKernelStart();
// ...
void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN 5 */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END 5 */ 
}

Blinking LEDs

The STM32F0Discovery board comes with two user LEDs, green LD3 and red LD4. To verify whether the native FreeRTOS works, I create two dummy tasks, each toggling one of the LEDs every 1000 microseconds.

First, declare prototypes of two task functions after /* USER CODE BEGIN 0 */.

void vTask1(void *pvParameters);
void vTask2(void *pvParameters);

Create two tasks after /* USER CODE BEGIN RTOS_THREADS */.

xTaskCreate(vTask1, "Task 1", 256, NULL, 1, NULL);
xTaskCreate(vTask2, "Task 2", 256, NULL, 1, NULL);

Start the FreeRTOS scheduler after /* Start scheduler */.

vTaskStartScheduler(); 

Then implement the two task functions after /* USER CODE BEGIN 4 */.

void vTask1(void *pvParameters)
{
	for(;;)
	{
		HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
		vTaskDelay(1000);
	}

}

void vTask2(void *pvParameters)
{
	for(;;)
	{
		HAL_GPIO_TogglePin(LD4_GPIO_Port, LD4_Pin);
		vTaskDelay(1000);
	}
}

Finally, build the project, upload it to the STM32F0Discovery board. The two user LEDs blink as expected.

Leave a Reply

Your email address will not be published. Required fields are marked *