FreeRTOS for em::Blocks & STM32F4-Discovery
In the em::Blocks EDI, it is possible to create templates in order to create easily new projects.
This post describes the way to create a new template for em::Blocks containing:
- FreeRTOS V8.12
- STM32F4xx HAL Driver (the STM32CubeF4 new hardware abstraction layers)
- Specific configuration for the STM32F4-Discovery board
Installation of the downloaded template
As it is a bit long to create this template, you can install directly in em::Block the downloded version.
- Download the template here or in my GitHub repository
- Unzip the file to create the “STM32F4-Discovery-Template” directory
- Copy the “STM32F4-Discovery-Template” in the Windows AppData directory for em::Blocks by launching the following command:
xcopy /S /I STM32F4-Discovery-Template %APPDATA%\EmBlocks\2.00\UserTemplates\STM32F4-Discovery
To create a new project in em::Blocks, use the “File / New / From template…” menu and select the new template. Then enter the target directory and the project name.
How to create this template
Create a new project as described in the first part of the “Use em::Blocks with the STM32F4-Discovery” post.
Name your project “STM32F4-Discovery” and do not realize the “Adaptation for the “STM32F4-Discovery” part.
Add Files in this template
Create an STM32F4 directory in C:\
Unzip the stm32cube_fw_f4_v130.zip file in this directory (see previous post to download it)
Download and run the FreeRTOSV8.1.2.exe program to unzip file in this directory
The result for this STM32F4 directory is:
- FreeRTOSV8.1.2 : The free RTOS distribution
- STM32Cube_FW_F4_V1.3.0 : The STM32Cube F4
- STM32F4-Discovery : The new project created to realize the template
Go to the “STM32F4-Discovery” directory and remove the “SPL” directory that contains the old firmware.
Delete the content of the “Inc” directory. Files will be replaced by the HAL versions.
Creation of the RTOS part
– Go to the “c:\STM32F4\STM32F4-Discovery” (your new project directory) and create a “Firmware” directory.
– Go to this “Firmware” directory and create a “FreeRTOS” directory.
– Go in this new “FreeRTOS” directory.
– Copy the source files (*.c) from “c:\STM32F4\FreeRTOSV8.1.2\FreeRTOS\Source\*.c”.
– Copy the Header files (*.h) from “c:\STM32F4\FreeRTOSV8.1.2\FreeRTOS\Source\include\*.h”.
– Copy the content of “c:\STM32F4\FreeRTOSV8.1.2\FreeRTOS\Source\portable\GCC\ARM_CM4F\*.*” in this FreeRTOS directory.
Memory management source file must be added (5 files exist, check the documentation for details).
– The first version is ok for most of cases, so copy the “c:\STM32F4\FreeRTOSV8.1.2\FreeRTOS\Source\portable\MemMang\heap_1.c” file in the FreeRTOS directory.
– Copy the “c:\STM32F4\FreeRTOSV8.1.2\FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK\FreeRTOSConfig.h” file in the FreeRTOS directory.
One more file is needed.
– Create in the directory “FreeRTOS” a file named “FreeRTOS-hook.c”, edit it to append the following code:
#include "FreeRTOS.h" #include "task.h" #include "stm32f4xx_hal.h" void vApplicationTickHook( void ) { HAL_IncTick(); } /*-----------------------------------------------------------*/ void vApplicationMallocFailedHook( void ) { /* vApplicationMallocFailedHook() will only be called if configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook function that will get called if a call to pvPortMalloc() fails. pvPortMalloc() is called internally by the kernel whenever a task, queue, timer or semaphore is created. It is also called by various parts of the demo application. If heap_1.c or heap_2.c are used, then the size of the heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used to query the size of free heap space that remains (although it does not provide information on how the remaining heap might be fragmented). */ taskDISABLE_INTERRUPTS(); for( ;; ); } /*-----------------------------------------------------------*/ void vApplicationIdleHook( void ) { /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle task. It is essential that code added to this hook function never attempts to block in any way (for example, call xQueueReceive() with a block time specified, or call vTaskDelay()). If the application makes use of the vTaskDelete() API function (as this demo application does) then it is also important that vApplicationIdleHook() is permitted to return to its calling function, because it is the responsibility of the idle task to clean up memory allocated by the kernel to any task that has since been deleted. */ } /*-----------------------------------------------------------*/ void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) { ( void ) pcTaskName; ( void ) pxTask; /* Run time stack overflow checking is performed if configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is called if a stack overflow is detected. */ taskDISABLE_INTERRUPTS(); for( ;; ); } /*-----------------------------------------------------------*/
Creation of the STM32CubeF4 part
– Go up to the “c:\STM32F4\STM32F4-Discovery\Firmware”
– Copy the “STM32F4xx_HAL_Driver” directory located in “c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers”.
– Copy the “STM32F4-Discovery” directory located in “c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers\BSP”.
– Copy the “Components” directory located in “c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers\BSP”.
– Copy the “STM32_Audio” directory located in “c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Middlewares\ST”.
– Change to the “c:\STM32F4\STM32F4-Discovery\inc” directory
– Copy the “stm32f4xx_hal_conf.h” file located in “c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Projects\STM32F4-Discovery\Templates\Inc”.
– Copy the “stm32f407xx.h” file located in “c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers\CMSIS\Device\ST\STM32F4xx\Include”.
– Copy the “stm32f4xx.h” file located in “c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers\CMSIS\Device\ST\STM32F4xx\Include”.
– Copy the “system_stm32f4xx.h” file located in “c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers\CMSIS\Device\ST\STM32F4xx\Include”.
Configuration of the em::Blocks IDE
– In the Workspace window, right click on the STM32F4-Discovery project and select “Build options…”
– In the “Compiler settings” tab, select the “#define” sub-tab.
Add the two constants STM32F407xx and USE_HAL_DRIVER
– In the “Compiler settings” tab, select the “Other options” sub-tab.
Add the option -Wno-unused-but-set-variable and validate with the “Ok” button (to remove the warning: variable ‘xxx’ set but not used).
– Edit the “Source/src/system_stm32f4xx.c” file and at line 156 change the value of the #define PLL_M to 8 (The Quartz is a 8Mhz).
– Right click on the “STM32F4-Discovery” root name in the Workspace window. Select “Remove files…” and validate the 2 next dialog boxes to remove all files from the project tree.
– Right click on the “STM32F4-Discovery” root name and select “Add files recursively…” to re-create the new project structure:
* validate the first dialog box to include the “STM32F4-Discovery” directory content.
* in the second Dialog, scroll to the end of the file list and check the 2 files “stm32f407vg_flash.ld” and “stm32f407vg_sram.ld”. Then click “Ok”
* click “Ok” on the third dialog box.
(if you have a “D sources” directory on the project tree due to a previous compilation imported, open it, right click on the “obj” directory, and select “remove “obj\*”)
– Edit the “Headers/Firmware/STM32F4-Discovery/stm32f4_discovery_audio.h” file and at line 52 replace #include “..\..\..\Middlewares\ST\STM32_Audio\Addons\PDM\pdm_filter.h”
by #include “pdm_filter.h”
– Edit the “Header/Firmware/FreeRTOS/FreeRTOSConfig.h” file and move the line 85 outside the “#ifdef __ICCARM__”.
It must be:
#ifdef __ICCARM__ #include <stdint.h> #endif extern uint32_t SystemCoreClock;
– Edit the “main.c” to change the content to:
/* ** ** Main.c ** ** **********************************************************************/ #include "stm32f4xx.h" #include "stm32f4_discovery.h" #include "FreeRTOS.h" #include "task.h" #define TASK_PRIORITY (tskIDLE_PRIORITY + 1) #define STACK_SIZE (configMINIMAL_STACK_SIZE + 100) // Task prototypes void LedTaskFunction( void *pvParameters ); void BtnTaskFunction( void *pvParameters ); int main(void) { // Initialization HAL_Init(); // create the task xTaskCreate( LedTaskFunction, /* Pointer to the function that implements the task. */ "Flash Led", /* Text name for the task. This is to facilitate debugging only. */ STACK_SIZE, /* Stack depth */ NULL, /* We are not using the task parameter. */ TASK_PRIORITY, /* This task will run at priority 1. */ NULL ); /* We are not going to use the task handle. */ // Create the BTN task xTaskCreate( BtnTaskFunction, "BTN Task", STACK_SIZE, NULL, TASK_PRIORITY, NULL ); // Start the scheduler so the tasks start executing vTaskStartScheduler(); while(1) ; } void LedTaskFunction( void *pvParameters ) { BSP_LED_Init(LED6); for (;;) { BSP_LED_Toggle(LED6); vTaskDelay(500); // Delay 500 ms } } void BtnTaskFunction( void *pvParameters ) { BSP_LED_Init(LED3); BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_GPIO); for (;;) { if (BSP_PB_GetState(BUTTON_KEY)) BSP_LED_On(LED3); else BSP_LED_Off(LED3); } }
You can compile this project without error.
If you run it, a first task will flash the LED 6 with a 1s period and a second one will copy the state of the user button to the LED 3.
As this project is now ready (and takes long time to build 😉 ), save it as a template in em::Blocks.
Go to the “File / Save Project as Template…”
Change for the STM32CubeF4 V1.9.0
– Go to the directory “c:\STM32F4\STM32F4-Discovery\cmsis”.
– Delete the content
– Copy inside the content of the directory “c:\STM32F4\STM32Cube_FW_F4_V1.9.0\Drivers\CMSIS\Include”