I have an FreeRTOS appication that is working in Debug mode. When i change my configuration to release mode, it compiles without errors & warnings. Then, when I flash the application to the MCU, it does not even go to the main() and ends up at the below mentioned line throwing an assert.
ASSERT: 0.0s: FreeRTOS-Kernel/tasks.c:vTaskSwitchContext:3063: (uint32_t)(( ( &( pxReadyTasksLists[ uxTopPriority ] ) )->uxNumberOfItems ) > 0) failed !!!
I have been debugging, but could not understand it.
Looking forward for an advice on this topic.
What is your platform, target, toolset and port? My suspicion is that release mode assumes a different memory layout and configures RAM to be in a different position.
it does not even go to the main()
The C startup code should call main(), and main starts the scheduler. So, unless the MCU is jumping into the weeds from the C startup code, main() will have been called.
Normally, after loading the program, the program should halt at the main. but in my case i don’t see it. I just see the assert displayed in my console.
Do you have any idea on how can i go forward regarding this topic?
I am using TI MCU - R5 Core, clang compiler from TI.
It’s normal for a breakpoint at main() to be skipped in optimised code as the startup code will most likely jump to the start of whichever function gets called by main first.
Again, compare the memory maps of your debug and release builds.
With full optimization like
-Os -flto (for GCC) the
main symbol might get optimized out. You might try to put a BP on
vTaskStartScheduler or another suitable symbol/function.
Another option is to decrease the optimization e.g. omit
-flto or add an
main to force keeping the symbol.
Is the TI project using the same linker script for both?
Many years ago I used a TI compiler that didn’t initialise variables correctly. Inspect a variable that should start with a non-zero value at program entry to see if it is initialised as expected. ulCriticalNesting would be a good candidate. What value does it have before any C code executes?
When I omit the flag
-flto in my linker options, the application is working.
But, I don’t understand it, because the above mentioned flag is used for switching on the
Link Time Optimization.
Does this have effect on the application?
There might be some issues when using the pretty good but also pretty aggressive LTO which could require some manual ‘help’ for the optimizer. Given the code is correct.
Often the optimizer reveals ‘undefined behaviour’ problems in application code, but sometimes in very rare corner cases I think also the optimizer fails. It’s just software after all
I’ve encountered a few cases where I THINK, I’m right with the C/C++ code but the resulting compiled (assembler) code was broken.
Unfortunately it’s not easy to find out where the code gets broken with full optimization.
I’ve selectively changed the optimization for some files and also functions (e.g. using the attribute((optimize(“-Og”))) and some trail and error to nail it.
Thanks all for the support.
The problem with Link Time Optimization is many versions of it are “broken” in that they will omit code if the only reference to it is from assembly. It also can very aggressively transform code that relied on not fully defined behavior, that “works” when not aggressively optimized.
We had to make updates to the Cortex-M port for it to work with link time optimisation - as I recall using compiler specific syntax telling the compiler not to remove variables or functions that are used, but perhaps not obviously. For example, interrupt handlers that are only referenced from a statically configured vector table. I note you are using the Cortex-R port - I presume, from your report, that has the same issues.
Thanks Richard for the explanation. This clarifies my question.