ARM-software / CMSIS_5

CMSIS Version 5 Development Repository
http://arm-software.github.io/CMSIS_5/index.html
Apache License 2.0
1.33k stars 1.08k forks source link

HardFault in Timer RTX5 #239

Closed juliobc closed 7 years ago

juliobc commented 7 years ago

Hi, I am using RTX5.2 and ARM Keil compiler with STM32F4. I am using a simple osTimer, but I have a HardFault interrupt sometimes when the timer is expired, in the function:

void osRtxPostProcess (os_object_t *object) { if (isr_queue_put(object) != 0U) { if osRtxInfo.kernel.blocked == 0U) { SetPendSV(); } else { osRtxInfo.kernel.pendSV = 1U; } } else { osRtxErrorNotify(osRtxErrorISRQueueOverflow, object); } }

When the osRtxInfo.kernel.blocked = 1 is all rigth, but when osRtxInfo.kernel.blocked = 0 the code enters in a HardFault Exception. Any help?

Greetings

juliobc commented 7 years ago

I have a simple project with the Exception:

I have a main Thread:

#include "cmsis_os2.h" #include "Thread_2.h" osEventFlagsId_t evt_id_Thread_main_app; osThreadId_t id_Thread_main_app; void app_main (void *argument) { Init_Thread_2(); while (1) { osEventFlagsWait (evt_id_Thread_main_app, 0x7FFFFFFF, osFlagsWaitAny, osWaitForever); } } int Init_Thread_main_app (void) { tid_Thread_main_app = osThreadNew (app_main, NULL, NULL); if (!tid_Thread_main_app) return(-1); evt_id_Thread_main_app = osEventFlagsNew(NULL); if ( !evt_id_Thread_main_app ) return(-1); return(0); }

and a second Thread:

osThreadId_t tid_Thread_2; osEventFlagsId_t evt_id_Thread_2; osTimerId_t osTimerId_Test; uint16_t count; void Thread_2 (void *argument) { osTimerStart(osTimerId_Test, 1000); while (1) { osEventFlagsWait (evt_id_Thread_2, 0x7FFFFFFF, osFlagsWaitAny, osWaitForever); } } void ejecutar_sondeo_periodico(void) {count++;} int Init_Thread_2 ( void ) { tid_Thread_2 = osThreadNew (Thread_2, NULL, NULL); if (!tid_Thread_2) return(-1); osTimerId_Test = osTimerNew((osTimerFunc_t)&ejecutar_sondeo_periodico, osTimerPeriodic, NULL, NULL); if ( !osTimerId_Test ) return(-1); return(0); }

When the Timer is expired, then a HardFault Exception is executed.

Is there any wrong in this example? Greetings

JonatanAntoni commented 7 years ago

Hi @juliobc,

Thank you for providing a detailed description and the reproducer example.

Hard Faults may have a couple of reasons and are typically "hard" to analyze.

I'll take a look into the example you provided.

Cheers, Jonatan

JonatanAntoni commented 7 years ago

Hi @juliobc,

Unfortunately I cannot observe any faults with your example here. Can you please state in more details which environment you are exactly using? I.e. IDE, compiler version, which packs and which type of startup code? Is it possible that you provide a full MDK project causing the issue for instance?

Please find the one I created attached.

Cheers, Jonatan issue-239.zip

juliobc commented 7 years ago

Hi @JonatanAntoni

I think it must be a wrong configuration because it is a simple use of the timer. I attach a full project with the simple example. When the timer is expired then the code goes to a HardFault. Thanks HardFault_osRtxTimer_Error.zip

JonatanAntoni commented 7 years ago

Hi @juliobc,

I figured out what's going wrong. You configure the interrupt priority of PendSV to be 0 in your HAL_MspInit. This leads to dysfunction because PendSV is now able to preempt the SysTick interrupt which must not happen.

Please read the RTX5 Scheduler documentation if you are interested in the details.

As a rule of thumb SVC, PendSV and SysTick interrupts are tied to the RTOS and must never be touched by anyone else. So you can safely remove all the configuration for those interrupts. The RTX initialization handles this for you appropriately. Please be aware that your priority grouping configuration must be fixed before osKernelInitialize(). You must not change the priority grouping afterwards, i.e. while RTX is running.

The project you created does not use Arm MicroLib. Thus osKernelInitialize() is already called during library init, see rtx_lib.c:520. This is needed for multithreaded library integration with RTX. So actually your call to osKernelInitialize() is simply ignored because RTX has already been initialized. So if you now change the priority grouping in main() you need to assure that the RTX interrupt priorities are set appropriately as well.

Thank you for letting us know about real world issues; that's very valuable for us. I am going take your feedback as the trigger to enhance our documentation with respect to C library integration. Furthermore we think about solutions to make RTX slightly more robust against priority misconfiguration before osKernelStart().

Cheers, Jonatan

juliobc commented 7 years ago

Hi @JonatanAntoni

I couple of things that I do not understand.

Do you recomend to use Arm MicroLib? I do not use MicroLib because I use the fegetround() function witch is incompatible with MicroLib. Any idea for rounding with MicroLib?

In my project, the priority grouping configuration is created automatically by CubeMX software by ST, and I can not disable it, but I would put the same priorities as using RTX. What are the priorities that RTX use for PendSV and SysTick interrupts and where is it in the code?

At what point is the kernell initialized exactly? When is the library initialized? Before main()?

Thank you for your quickly response. Greetings

JonatanAntoni commented 7 years ago

Hi @juliobc,

You're welcome. I tend to use Microlib most of the time but would not generally recommend to do so. It depends on your application requirements. It should be fine using Arm C Library as well.

I am not familiar in detail with CubeMX but I know we have some different opinions what should be done and where. We are still discussing on how to get the integration between CMSIS and CubeMX better aligned. Please consider the ST community to discuss those issues as well.

The priorities of the interrupts are configured during osKernelInitialize(), for Cortex-M its in rtx_core_cm.h:583. PendSV and SysTick are assigned to the lowest priority group, SVC is assigned to one priority group (preemption priority) higher according to the active priority grouping. You have to assure that PendSV and SysTick never preempt each other. And an outstanding SVC should not be overtaken by SysTick.

In your case, using Arm C Library, the call to osKernelInitialize() is done before entering main using a library hook in rtx_lib.c:520. Microlib does not offer those hooks and thus you need to call osKernelInitialize() on your own during main.

Cheers, Jonatan

juliobc commented 7 years ago

Hi @JonatanAntoni

Could you tell me what is the NVIC configuration of PendSV, SysCall and Systick interrupts in RTX5 exactly? I saw that Systick interrupt has a high priority on start, is it correct?

JonatanAntoni commented 7 years ago

Hi @juliobc,

Your question cannot be answered in general because it depends on your device capabilities. As I already said the OS interrupts must be assigned to the lowest preemption priorities available. Please note that higher values are lower priorities on Cortex-M. You might want to read a in detail discussion here.

As far as I am aware of device details for an STM32F439 it offers 4 bits of programmable priority. Thus you should see priority 0xF0 (240) used for SysTick and PendSV. And the slightly higher priority 0xE0 (224) assigned to SVC. This only holds true if you use all 4 programmable priority bits as the preempt priority group (i.e. HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4)).

Cheers, Jonatan

juliobc commented 7 years ago

Hi @JonatanAntoni thanks. My doubt is resolved.

Greetings.

JonatanAntoni commented 7 years ago

@juliobc, May I ask you to close this issue if you don't have any further remarks on this topic, please?

juliobc commented 7 years ago

Hi @JonatanAntoni yes, I close this topic Thank you