Using ‘FreeRTOS’ in STM32 DISCOVERY board

Recently I have been learning bits about RTOS (Real Time Operating System). I decided to try one on the STM32-DISCOVERY board. There are many RTOSs that can be used for this task. But I wanted a very simple RTOS which could quickly get me started. I’ve heard about FreeRTOS and decided to use it as an experiment.


logo

FreeRTOS is a very well documented RTOS. It is also free and open. It has many demonstrations(examples) and it even has general steps required to port the system to different compilers, processors and evaluation kits. To get things started quickly I wanted a compiling Keil project. I found a full project here which is compiling and can be directly put to the DISCOVERY board.

But the version of RTOS used in the sample project above is not the latest. (At the time of writing the post the RTOS version is FreeRTOS V8.1.2) I wanted to use the latest FreeRTOS and wanted to learn how to develop the project from scratch. I believe following guidelines and steps would help anyone who would require to create a FreeRTOS project in Keil for the DISCOVERY board.st

Things you need to download. (Links are embedded and are working at the time of writing)

  1. FreeRTOS package.
  2. STM32F4 Standard Peripheral Driver Library
  3. DISCOVERY board GPIO library. (Used in the main.c)
  4. Keil uVision IDE ( I will soon post a GCC port as well )

Basic things to know about FreeRTOS. (More descriptive information is available at www.FreeRTOS.org)

  • The Kernel of the operating system is mainly in three files which are available in the FreeRTOS distribution. The files are tasks.c, queue.c and list.c. There are some other files which are also required if you want to use the functionality implemented by those. But the basic system needs only the mentioned three files as the kernel.
  • The processor and the compiler specific configurations and the source are available in the director named as ‘portable’. Inside that folder you can see folders for different compilers. (Note that Keil uses the RVDS which the standard arm compiler)
  • The other thing we require is the heap implementation which can be found within the portable\MemMang folder. There are many implementations (at the moment 5). Those five implementations have different functionality. For example heap_1 does not support memory freeing but heap_2 supports memory freeing. But the compiled binary size of heap_1 implementation is less the that of heap_2 implementation.
  • Final requirement is known as the configuration file (FreeRTOSConfig.h) which can be copied from the demo available for the STM32F4-CM4 processor at \FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK folder. I have modified the file slightly. But it is easier to use this file rather than creating that file from scratch since it is FreeRTOS specific configuration and we definitely don’t want to miss any.

Most important configuration in the above port I believe is the way that we configure the SysTick interrupt. If you are not familiar with the SysTick please read Section 4.5 of ‘STM32F3 and STM32F4 Series Cortex – M4 programming manual’. The document can be downloaded from here.

Following are the steps to create the Keil project from the scratch.

  1. Create a new project to use the STM32F407VG. Make sure to include the startup_stm32f4xx.s file too.
  2. Create folders named ‘Libraries’, ‘Source’, ‘Startup’ and ‘Include’ inside your project folder.
  3. Create the system_stm32f4xx.c file using the ‘STM32F4xx_Clock_Configuration_V1.1.0.xls’ file according to your clock requirement, copy and it to the ‘Startup’ folder.
  4. Copy the ‘STM32F4xx_StdPeriph_Driver’  folder to the ‘Libraries’ folder in the project location and add the source files to the project. This is available at STM32F4xx_DSP_StdPeriph_Lib_Vxxx\Libraries. (I did not add stm32f4xx_fmc.c source as it introduced errors)
  5. Copy the ‘CMSIS’ folder which is available at STM32F4xx_DSP_StdPeriph_Lib_Vxxx\Libraries to the ‘Libraries’ folder in the project folder.
  6. Copy the stm32f4xx_it.c file located at STM32F4xx_DSP_StdPeriph_Lib_V1.3.0\Project\STM32F4xx_StdPeriph_Templates  to the ‘Source’ folder.
  7. Copy the stm32f4xx_conf.h and stm32f4xx_it.h files located at STM32F4xx_DSP_StdPeriph_Lib_V1.3.0\Project\STM32F4xx_StdPeriph_Templates  to the ‘Include’ folder.
  8. Copy the FreeRTOS folder to the project folder. Following are the only required files. We can safely remove all the other files in this folder. Then add the following source files to the project.
    1. FreeRTOS\Source\croutine.c
    2. FreeRTOS\Source\event_groups.c
    3. FreeRTOS\Source\list.c
    4. FreeRTOS\Source\queue.c
    5. FreeRTOS\Source\tasks.c
    6. FreeRTOS\Source\timers.c.
    7.  FreeRTOS\Source\portable\RVDS\ARM_CM4F \port.c
    8. FreeRTOS\Source\portable\MemMang\heap_2.c ( For this example I’ll be using heap_2.c. But we can use any heap implementation )
  9. Copy the FreeRTOSConfig.h file from FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK location to the FreeRTOS\include folder.
  10. Copy the discoveryf4utils.h file to Include folder and discoveryf4utils.c file to Source directory. Add the source file to the project. These files needed to be downloaded from here.

Now all the files are added to the project. Note that you can group these source files into different groups such as Source, Libraries, Startup, Freertos within the Keil project such that they are well organized. Now we can add the following include paths to the project so the compiler will know where to look for the header files.

  1. .\Libraries\CMSIS\Include;
  2. .\Libraries\CMSIS\Device\ST\STM32F4xx\Include;
  3. .\Libraries\STM32F4xx_StdPeriph_Driver\inc;
  4. .\FreeRTOS\include;
  5. .\FreeRTOS\portable\RVDS\ARM_CM4F;
  6. .\Include

Now that we have included the header files we need to do a few configurations now to make this working.

  1. Goto Keil target options and define USE_STDPERIPH_DRIVER in the C/C++ tab.
  2. Edit the stm32f4xx.h which is available at Libraries\CMSIS\Device\ST\STM32F4xx\Include folder as follows. (Note that the file is originally a ReadOnly file and we need to clear the Read Only flag to edit the file)
    1. Remove the comment and enable ‘#define STM32F40_41xxx’ to select the device.
    2. If you are using HSE clock edit the HSE_VALUE definition to add the correct clock value.
  3. In the stm32f4xx_it.c file we need to comment out SVC_Handler, PendSV_Handler and SysTick_Handler as these functions are defined in the FreeRTOS source files.
  4. Remove the #include “main.h” line from the stm32f4xx_it.c file as we are not using a main.h file.
  5. In the FreeRTOSConfig.h file, change the following define values to ‘0’. If we enable these we need to add functions to support these configurations. To make the project simple I will be disabling them.
    1. configUSE_IDLE_HOOK
    2. configUSE_TICK_HOOK
    3. configCHECK_FOR_STACK_OVERFLOW
    4. configUSE_MALLOC_FAILED_HOOK

Add the following code to a new file and save it as main.c in the Source folder. This is currently available here.

//******************************************************************************
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
#include "discoveryf4utils.h"
//******************************************************************************

//******************************************************************************
#include "FreeRTOS.h"
#include "queue.h"
#include "task.h"
#include "croutine.h"
//******************************************************************************

void vLedBlinkBlue(void *pvParameters);
void vLedBlinkRed(void *pvParameters);
void vLedBlinkGreen(void *pvParameters);
void vLedBlinkOrange(void *pvParameters);
//void Delay(uint32_t val);

#define STACK_SIZE_MIN	128	/* usStackDepth	- the stack size DEFINED IN WORDS.*/

//******************************************************************************
int main(void)
{
	/*!< At this stage the microcontroller clock setting is already configured,
	   this is done through SystemInit() function which is called from startup
	   file (startup_stm32f4xx.s) before to branch to application main.
	   To reconfigure the default setting of SystemInit() function, refer to
	   system_stm32f4xx.c file
	 */
	
	/*!< Most systems default to the wanted configuration, with the noticeable 
		exception of the STM32 driver library. If you are using an STM32 with 
		the STM32 driver library then ensure all the priority bits are assigned 
		to be preempt priority bits by calling 
		NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); before the RTOS is started.
	*/
	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
	
	STM_EVAL_LEDInit(LED_BLUE);
	STM_EVAL_LEDInit(LED_GREEN);
	STM_EVAL_LEDInit(LED_ORANGE);
	STM_EVAL_LEDInit(LED_RED);
	
	xTaskCreate( vLedBlinkBlue, (const signed char*)"Led Blink Task Blue", 
		STACK_SIZE_MIN, NULL, tskIDLE_PRIORITY, NULL );
	xTaskCreate( vLedBlinkRed, (const signed char*)"Led Blink Task Red", 
		STACK_SIZE_MIN, NULL, tskIDLE_PRIORITY, NULL );
	xTaskCreate( vLedBlinkGreen, (const signed char*)"Led Blink Task Green", 
		STACK_SIZE_MIN, NULL, tskIDLE_PRIORITY, NULL );
	xTaskCreate( vLedBlinkOrange, (const signed char*)"Led Blink Task Orange", 
		STACK_SIZE_MIN, NULL, tskIDLE_PRIORITY, NULL );
	
	vTaskStartScheduler();
   
}
//******************************************************************************


//******************************************************************************
void vLedBlinkBlue(void *pvParameters)
{
	for(;;)
	{
		STM_EVAL_LEDToggle(LED_BLUE);
		vTaskDelay( 1000 / portTICK_RATE_MS );
	}
}

void vLedBlinkRed(void *pvParameters)
{
	for(;;)
	{
		STM_EVAL_LEDToggle(LED_RED);
		vTaskDelay( 500 / portTICK_RATE_MS );
	}
}

void vLedBlinkGreen(void *pvParameters)
{
	for(;;)
	{
		STM_EVAL_LEDToggle(LED_GREEN);
		vTaskDelay( 200 / portTICK_RATE_MS );
	}
}

void vLedBlinkOrange(void *pvParameters)
{
	for(;;)
	{
		STM_EVAL_LEDToggle(LED_ORANGE);
		vTaskDelay( 300 / portTICK_RATE_MS );
	}
}
//******************************************************************************

Now everything is set. Compile the project and put it to the DISCOVERY board. You should see all four LEDs blinking in different rates if you did everything correctly.

You can find the full project here in the github.

If you have come across any issue make sure to put it in a comment.

Thank you.

Advertisements

13 comments

  1. I am facing an error with ‘SystemCoreClock’ being undefined in port.c during build.
    I did not quite understand the third step in creating the project:

    “Create the system_stm32f4xx.c file using the ‘STM32F4xx_Clock_Configuration_V1.1.0.xls’ file according to your clock requirement, copy and it to the ‘Startup’ folder.”

    Keil uvision 5.15 already included a system_stm32f4xx.c for me when I included the Device Startup files, which I thought defined ‘SystemCoreClock’.

    So, can you tell me what this .xls file is supposed to do?

    1. The excel file is used to generate the system_stm32f4xx.c file in my case. Excel file provides a nice and easy GUI to configure ST clocks. If you don’t have the excel file I can send it to you.

      This file was needed because, in Keil 4.17 which I use, it does not include the system_stm32f4xx.c file as a Startup file. It only includes the startup_stm32f4xx.s file.

      In your case, check whether the system_stm32f4xx.c file is added to the project. Because, ideally the SystemCoreClock variable should be defined in that file.

      Thanks.

    2. grey,

      I have the same issue. Did you figure out what the issue was? My system_stm32f4xx.c was added manually, and since I defined STM32F446xx as a custom symbol it should find the core clock already at 180000000. But no such luck!

      1. Hello,

        SystemCoreClock variable is defined in system_stm32f4xx.c. You should be able to access it outside the file by putting,

        extern uint32_t SystemCoreClock;

        in whatever source file you need.

        Can you try this?

        I will look into this issue too.

      2. The top of my FreeRTOSConfig.h has a conditional extern declaration of SystemCoreClock if the symbol __ICCARM__ is defined. So I forced inclusion of stm32f4xx.h at the top of FreeRTOSConfig.h.

        #include “stm32f4xx.h”

        #ifdef __ICCARM__
        #include
        extern uint32_t SystemCoreClock;
        #endif

        This causes the linker to fail immediately. Error: L6218E: Undefined symbol vTaskDelay (referred from main.o). If I go straight into port.c and replace “SystemCoreClock” with 180000000, the same linker errors appear. Defining __CCARM__ as a custom symbol also causes this. Something still isn’t linked or included right.

        .. vTaskStartScheduler (referred from main.o)
        .. vTaskGenericCreate (referred from main.o)
        .. uxTaskResetEventItemValue (referred from event_groups.o)
        ..
        .. 23 of these errors total

        I’m using V8.2.3 and Keil 5.16. These versions are hardly different from what you used. File system looks identical to your git repo too..

        I hope I can get this working. This guide is exactly what I’ve been looking for for months now.

      3. I never did get this project working. I left it with the 23 errors described above. Did you have the same errors appear as well?

      4. Hello Tyler,

        Can you send me your project files? I can try it here and let you know. In my build there are no errors. Did you clone my git repo and tried building there?

      5. Check the FreeRTOSConfig.h file.

        Check whether following #define is there,

        #define configCPU_CLOCK_HZ ( SystemCoreClock )

        In the top of the file you should put the following line,

        extern uint32_t SystemCoreClock;

        Then all the files of RTOS library should be able to find this variable.

        Thank you.

      6. When I dig deeper into the code I found that the

        extern uint32_t SystemCoreClock;

        is already defined in “system_stm32f4xx.h”.

        If you include “#include “stm32f4xx.h”” within your “FreeRTOSConfig.h” file then that should give RTOS library full visibility of the SystemCoreClock variable.

        Please follow any of these methods.

        Thank you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s