2019-04-22 04:00 AM
Hello,
During my development I came across this (sort of) bug which will require manual code modification if a specific FreeRTOS function is to be used.
** Definition of the problem **
FreeRTOS V9 has a feature to define the TCB of a task in compile time instead of run time in order to eliminate the need to Malloc the required RAM space in run-time and prevent any forthcoming problems that may arise if the RAM cannot be allocated.
STM32CubeMX defines the TCB block inside the MX_FREERTOS_Init() function. using this pattern :
#define osThreadStaticDef(name, thread, priority, instances, stacksz, buffer, control)
osThreadStaticDef(task_name, task_start_function, osPriority, 0, stack_size, Task_buffer, &task_TCB);
the place for this definition has no problem unless we were to delete a statically created task and then recreate it using "THE SAME TCB" (which is usually the case).
if we were to use the same TCB , we must be able to extern the TCB definitions in other files where that task creation function is called but since the definition is inside a function , that is not possible.
The same problem exists for other RTOS objects like mutex, semaphore, etc.
** Possible Solution **
one quick solution is to move
osThreadStaticDef(task_name, task_start_function, osPriority, 0, stack_size, Task_buffer, &task_TCB);
outside of the
MX_FREERTOS_Init()
function, preferably where the task_handle , Task_controlBlock and task buffer are defined. this way the developer can easily extern those without having to modify the code.
right now , one has to comment or delete the CubeMX generated code and rewrite it outside the function which is automatically undone if the project is regenerated with CubeMX.
2019-04-29 06:46 AM
Hi @Daniel Hassanian
Could you please tell me which MCU do you use ?
Please send me your .ioc file to check the problem.
Best regards,
Nesrine
2019-04-29 07:04 AM
Dear @Nesrine.JLASSI
This is not a MCU specific problem. this is how CubeMX code generation template is for FreeRTOS.
ST has to fix it at the template level. that is if they think this is actually a problem which I think it is, because it forces the deveoper to modify the CubeMX generated code and those modifications are lost upon project code regeneration.
Edit : you can select any MCU and see that the TCB definition is inside MX_FREERTOS_Init() , which is not extern-able from outside that file.
Edit 2: I also have to say that osThreadStaticDef is a Macro itself and cannot be exterened. however having it outside the function makes it possible to extern the 'macro generated const name' in other files.
2019-04-29 07:19 AM
Another thing i forgot to mention is that , another possible solution is to use osThreadStaticDef in other files and extern task_handle , Task_controlBlock and task buffer to create another instance of the same osThreadStaticDef, however this causes additional "const" variables which will occupy unnecessary code space.(not to mention extern-ing 3 variabes instead of one)
this method will not require the CubeMX template to change but is definitly not recommended.
2019-05-06 04:58 AM
Hi @Daniel Hassanian
In the generated code, we do not have the function MX_FREERTOS_Init().
For Freertos, CubeMX gives the possibility that the user adds his code (in the freertos.c).
Best regards,
Nesrine
2019-05-06 10:12 AM
@Nesrine.JLASSI
I don't quite understand what you mean you don't have the function MX_FREERTOS_Init().
I understand that CubeMX let's the user add his own code. the problem is that the code the user is going to add, conflicts with the one CubeMX generates.
I'm going to demonstrate this issue using pictures.
1- I Select a random MCU from the list of CubeMX , (STM32F103C8Tx). then i enable FreeRTOS and in the option I select "Dynamic/Static" for memory allocation.
2- then I add a random task but I change the allocation to Static.
3- I select generate Peripheral init as pair of '.c/.h' files.
4- all other CubeMx options and Freertos options are left as their default. now I generate the project for MDK-ARM V5.
5- I open freertos.c in the project and as you can see the function MX_FREERTOS_Init() is there. (note that if you don't select generate as a pair of '.c/.h' this function is not generated this might have caused the confusion, however, the nature of the problem remains the same)
6- as you can see the function is called from the main function to configure FreeRTOS and Initialize the tasks and mutexes etc.
7- the macro
osThreadStaticDef(myTask02, StartTask02, osPriorityIdle, 0, 128, myTask02Buffer, &myTask02ControlBlock);
is inside that function. if you open the definition of the macro , you'll see it's just a wrapper to define different
const osThreadDef_t os_thread_def_##name
variables according to the tasks name. this variable holds everything about the task including the task buffer and task control block which is important to us.
8- the task buffer and task block and other memory units are defined outside this function here :
which are possible to be extern-ed (declared) from other files (which we don't want to do.) however the
osThreadStaticDef(myTask02, StartTask02, osPriorityIdle, 0, 128, myTask02Buffer, &myTask02ControlBlock);
which translates into
const osThreadDef_t os_thread_def_myTask02 = \
{ myTask02, (StartTask02), (osPriorityIdle), (0), (128), (myTask02Buffer), (myTask02ControlBlock) }
cannot be extern-ed (declared) because of two reasons.
first , it's inside a function
and second because it's a macro defining a variable.
this is the tricky part.
9- Now if I were to delete the task I can do it easily using the task handle. but what If i want to create it again using the same task buffer ?
to over come this we can extern all the needed information including the 3 needed variables to create a static task which is mentioned in number 8.
BUT this causes 2 problems.
first in every file we need to extern (declare) 3 variables plus other needed variables, which means more unnecessary code.
and second and most important we need to define the task definition again which is
osThreadStaticDef(myTask02, StartTask02, osPriorityIdle, 0, 128, myTask02Buffer, &myTask02ControlBlock);
and this means the one that was already defined inside the MX_FREERTOS_Init() is now totally wasted ! and we are losing code space.
10 - to solve this issue the user has to comment line 116 in file freertos.c in this example and move it outside the function.
doing so causes the CubeMX generated code to be modified and then lost again after a code regeneration !
11 - if the "osThreadStaticDef" is moved outside the function the problem of losing code space is solved however referencing it from outside needs manual name referring which is acceptable but that can be solved with another macro as well.
I hope I explained the issue better this time.
edit: fixed images
2019-05-22 04:04 AM
Hi @Daniel Hassanian
I did not understand the problem, please correct it and send me your project to take it as an example.
Regards,
Nesrine