-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CMSIS::RTOS2::FreeRTOS doesn't work if MicroLIB is not used #55
Comments
Hi, I briefly looked at the example structure and HAL_IncTick is called in startup_stm32h743xx.s where default weak reference to SysTick_Handler was modified and renamed to _SysTick_Handler. |
Hi @VladimirUmek |
In my previous response I was just searching for a reason that HAL_IncTick is never called. And if you would update startup_stm32h743xx.s then this could be one option - because with the update, modification in startup that calls HAL_IncTick would be gone. Unfortunately I cannot test the example because I don't have any appropriate board, but I'll investigate further and check what could go wrong. |
Hi @VladimirUmek Lines 266 to 267 in 3da3609
and it calls Line 279 in 3da3609
setting BASEPRI to 0x50 The problem is that when Line 318 in 3da3609
is called, this function is mapped to vPortExitCritical() CMSIS-FreeRTOS/Source/portable/GCC/ARM_CM7/r0p1/port.c Lines 415 to 424 in 3da3609
But variable uxCriticalNesting has not been set yet and it has the default value of
The reason is because it's initilized by
when FreeRTOS scheduler is started. Do you agree to my analysis? |
Many thanks again for the detailed analysis! This helps a lot and I understand the problem now. I don't think this is the problem of implementation in clib_arm.c but I would say that it is the problem of port (initialization) implementation in FreeRTOS:
the situation after the call of xSemaphoreCreateMutexStatic would be exactly the same as in your application: This means that any application that creates RTOS objects before the kernel is started has its interrupts blocked (up to BASEPRI). In case of our application, pre-main calls You can take a look at examples (Blinky is fine) in Keil.STM32H7xx_DFP for one possible solution to this problem (re-implement |
Thanks for your help.
Am I right? |
As I said, I think that such behavior is a design choice to keep the kernel state machine consistent until the kernel is started. FreeRTOS maintains the ports but I don't think this is a bug although in some cases it may represent a problem for application designer... |
You are correct that the FreeRTOS behaviour is intended. Every port behaves this way, and has done from very early versions of FreeRTOS where a primary cause of support requests were interrupts starting to use the FreeRTOS API before the kernel had been started - a particularly difficult issue to debug. See point 4 "Interrupts are not executing" on this page. A simple work around is to manually clear the primask register when necessary - but then you may need additional code to prevent the FreeRTOS API trying to context switch in the systick before the kernel is running - which will be inefficient as the additional code will run every time the systick executes. |
Hello @RichardBarry, I'm not sure I got your point: If this is the case, I understand that a "quick-and-dirty" workaround has been taken from very early versions of FreeRTOS: disabling interrupts at all until the kernel is started.
It seems that a normal function (not an interrupt) could use FreeRTOS API functions during system initialisation. Then you write:
This seems to me exactly what CMSIS-FreeRTOS adoption layer does here CMSIS-FreeRTOS/CMSIS/RTOS2/FreeRTOS/Source/cmsis_os2.c Lines 160 to 164 in 3da3609
It seems that CMSIS-FreeRTOS protects from the risk of "interrupts attempting to use FreeRTOS API functions during system initialisation" inside SysTick_Handler() and FreeRTOS itself protects with a heavy decision of disabling the interrupts.And so I get both the downsides:
Are you sure is not possible handling this risk in a different way? |
Maybe - but very effective. It has probably saved many weeks of frustration for FreeRTOS users that otherwise would experience crashes caused outside of their view of the program execution - which can be tricky to track down. This is rarely a problem for users who create all their RTOS objects then start the scheduler. Another common usage model is to create a task that performs the initialisation, then spawns the other tasks, so perform initialisation with the scheduler already running.
That is not a problem - although I would question why interrupts are used in __scatterload().
Yes it looks like that is the case. I also wrote:
So in the code you posted every tick interrupt has the overhead of an extra function call and an extra test. Looks like fixing the symptom rather than the cause.
In FreeRTOS we try and avoid additional code that checks the system state every time (for example, see https://freertos.org/FAQ_API.html#IQRAPI - there are trade offs made for every decision) - we would welcome any ideas for preventing interrupts using the API before the scheduler is running without needing any additional code that will then also be present for the lifetime of the application. |
Thank you a lot @RichardBarry I fully agree to the fact that every decision requires some trade offs. Based on what I learned from this lesson, I've been thinking on if/how something could be improved. The only idea to improve FreeRTOS side (if possible) is to inform the caller about the "side-effect" of the function call. I think this is a general best-practise. |
I don't think there is right or wrong answer in this case. One scenario that could happen in mentioned FTP demo application:
Now, application didn't start the kernel, but the kernel tick is already started and is incrementing. And we can start discussing why the kernel tick is incrementing if the kernel is not even started. Who started SysTick? Who should start SysTick? Why is SysTick used by both STM32Cube HAL and FreeRTOS? Etc, etc... There is A LOT of existing code that is wrong. That's why interrupts are disabled after RTOS objects get created. That's why there is a check And, in mentioned application, which function hangs because Trade offs... It is an ugly situation, I agree and can document it, but from my perspective, this is integration issue in application. |
Not directly related: I understand why C startup code enables interrupts before calling main(), but I don't understand why that happens inside __scatterload(). As far as I know __scatterload() is responsible for initialising memory. |
Yes and the only thing that happens inside |
Thank you @VladimirUmek. Now everything is clear, but what confuses me at the beginning was that:
|
I agree that reaching We will document this behavior also in CMSIS-FreeRTOS documentation. |
I apologize for asking as not part of the original conversation but I have had the same issue, in general. I have no problem with the reasoning of the start up procedure. It was just annoying having to trace down where there might be a an unstable irq or mutex state, especially when running into stack overflows/corruption. This is an old suggestion but I was reminded of it when I was going though some ddk function calls back in the Window 98 days where most functions had blank define annotations for function arguments. As a simple example #define __AQUIRED
#define __RELEASED
__USED void _mutex_acquire (__RELEASED mutex *m);
__USED void _mutex_release (__AQUIRED mutex *m); I hate to say, having the tags _HEAP_ONLY and _MUST_FREE has saved me many times in smaller projects where I had to do simple one off changes. With the almost mandatory need for IDE's to support IntelliSense, doing something like a full Doxygen implementation seems overkill. The point of the mark is not to notify somone who knows the deeper implementation, rather, somone having to do a quick stack trace with nothing other than a FUNCTION string. This is just an unsolicited comment, its just nice to come across an interesting conversation. Especially after 4 hours of debugging a stack corruption error to find the pointer to the heap was swaped. |
Sources and documentation were updated, hence closing the issue. Please reopen in case anything needs further attention. |
I found a problem while playing a little bit with FTP Server example from Oryx-Embedded on STM32H743I-EVAL board.
This example works out-of-the-box using RTOS2 interface, implemented through RTX5.
Since the example needs File System from Keil.MDK-Middleware, MicroLIB cannot be used.
If I change RTOS2 implementation from RTX5 to FreeRTOS (downloaded through its own CMSIS pack), the example doesn't work anymore.
The most visible issue is that
void HAL_IncTick(void)
is never called and the interrupt stays in pending state forever.Has someone an idea on what could be the reason?
For this reason I investigated deeper inside the sources to find the differences between RTX5 and FreeRTOS implementations behind RTOS2 interface.
I found some strange things inside clib_arm.c (used by CMSIS-FreeRTOS) compared to rtx_lib.c (used by RTX5).
I summarize what I see:
Point 1
This comes from
rtx_lib.c
https://github.com/ARM-software/CMSIS_5/blob/b0c7f1933926c805292b0368eb19e55b6646d18b/CMSIS/RTOS2/RTX/Source/rtx_lib.c#L623-L630
where I see
osKernelInitialize()
is called.This comes from
clib_arm.c
CMSIS-FreeRTOS/CMSIS/RTOS2/FreeRTOS/Source/ARM/clib_arm.c
Lines 45 to 54 in 3da3609
where I see that nothing is node (apart from Event Recording, which is NOT defined in the FTP Server example).
Point 2
This comes from
rtx_lib.c
https://github.com/ARM-software/CMSIS_5/blob/b0c7f1933926c805292b0368eb19e55b6646d18b/CMSIS/RTOS2/RTX/Source/rtx_lib.c#L690-L693
and the
define
is different from what I see fromclib_arm.c
CMSIS-FreeRTOS/CMSIS/RTOS2/FreeRTOS/Source/ARM/clib_arm.c
Line 71 in 3da3609
since
RTX_NO_MULTITHREAD_CLIB
is missing from this one.Point 3
This comes from
rtx_lib.c
https://github.com/ARM-software/CMSIS_5/blob/b0c7f1933926c805292b0368eb19e55b6646d18b/CMSIS/RTOS2/RTX/Source/rtx_lib.c#L701-L707
where I can see that the variables are placed in a
bss.os.libspace
region.This comes from
clib_arm.c
CMSIS-FreeRTOS/CMSIS/RTOS2/FreeRTOS/Source/ARM/clib_arm.c
Lines 75 to 79 in 3da3609
where no explicit placement is done.
Point 4
Functions from
rtx_lib.c
https://github.com/ARM-software/CMSIS_5/blob/b0c7f1933926c805292b0368eb19e55b6646d18b/CMSIS/RTOS2/RTX/Source/rtx_lib.c#L710-L794
call RTOS2 functions (
osKernelGetState()
,osThreadGetId()
, ...)On the other side, functions from
clib_arm.c
CMSIS-FreeRTOS/CMSIS/RTOS2/FreeRTOS/Source/ARM/clib_arm.c
Lines 81 to 198 in 3da3609
call a lot of native FreeRTOS functions (
xTaskGetSchedulerState()
,xTaskGetCurrentTaskHandle()
, ...) and I don't understand if the do exactly what is expected from them.Does clib_arm.c needs an upgrade to be aligned with rtx_lib.c?
The text was updated successfully, but these errors were encountered: