DRNadler / FreeRTOS_helpers

Helpers for some common problems when using FreeRTOS, GCC, and newlib.
140 stars 21 forks source link

Problems with HAL_getTick() after first call to _sbrk_r #13

Open sebrig opened 1 year ago

sebrig commented 1 year ago

I am currently using FreeRTOS with CMSIS-RTOS v2 interface directly in STM32CubeIDE 1.12.1 with my nucleo-F103RB. I am new to the thing and after getting systematic hardfault I found your article . After following all the steps it solve my problems ! I also added #define configISR_STACK_SIZE_WORDS (0x500) at the begining since it wasn't previously declared, as suggested in a previous issue.

Although adding the heap_useNewLib_ST.c file solved my problems I noticed that, before I start the os kernel, the HAL_getTick() and HAL_delay() functions were no longer working. After some investigation, it seems that after the first call to _sbrk_r, the TIM1 interrupt that I use as a Timebase source is no longer triggered. example of code that provoque the failure : `HAL_Init(); // first line in main()

HAL_delay( 1000 ); // working printf( "test" ); // will call _sbrk_r HAL_delay( 1000); // stay stuck`

My guess would be that the NVIC is overwritten in _sbrk_r, but I'm not quite sure... Could it be possible that my problem come from my #define configISR_STACK_SIZE_WORDS (0x500) ?

If further information is required, I will be happy to provide it to you.

DRNadler commented 1 year ago

I never call printf before starting the OS, as I use OS resources to handle redirected output, and IIRC any storage used in newlib reentrancy structures will be wasted once OS starts. IRC the ISR stack is used up until the OS is started, you could conceivably overrun it with printf though x500 words is not tiny, but normally stack overflow causes other kinds of symptoms. Is it possible HAL_delay uses interrupts and interrupts got disabled somewhere? Do 2 consecutive HAL_delay before printf work? I think you need to have a look at HAL_delay implementation... Hope that helps!

sebrig commented 1 year ago

Thank you for your answer ! After further investigation I found the source of the bug. The problem come from the calls to vTaskSuspendAll() and xTaskResumeAll() defined in DRN_ENTER_CRITICAL_SECTION and DRN_EXIT_CRITICAL_SECTION in heap_useNewLib_ST.c. This function will enter a critical section in port.c which will increment the variable uxCriticalNesting. When the critical section is exited this variable is decremented and only if uxCriticalNesting equals 0 are the interrupts reactivated. Since the function is called before the kernel is started the variable uxCriticalNesting is not set to 0 so the interrupts will no be reactivated before the start of the kernel.

I tried to solved the bug by adding a condition to the call to vTaskSuspendAll() and xTaskResumeAll() : if( IS_OS_RUNNING ) vTaskSuspendAll() if( IS_OS_RUNNING ) (void)xTaskResumeAll() with #define IS_OS_RUNNING ( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) at the beginning of heap_useNewLib_ST.c. Eventhough it solved my problem with _HALgetTick() and _HALDelay() that were based on the interrupt of TIM1, I got a new problem with osDelay() that stayed stuck.

I finally decided to put all my initializations before the infinite loop of my tasks and to add a barrier mutex before entering the loops.