This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

FreeRTOS Race Condition with Tickless Idle and Suspending Tasks

Hi

We've recently added FreeRTOS to the firmware of an existing product (primarily to pre-empt big chunks of 3rd-party code over which we have no control and execute them in a well-timed fashion). The goal is to achieve almost the same low-power properties as before adding FreeRTOS.
We're using the SDK 14.0.0 and SoftDevice S132 v5 (I know, old project).
The firmware is not really FreeRTOS-aware and communicates from the interrupts to the main context by setting flag variables.
In order to achieve the low power mode in FreeRTOS, we did
1 suspending (vTaskSuspend) the main task instead of calling
2 configUSE_TICKLESS_IDLE 1 and configUSE_IDLE_HOOK 0
3 defined configPOST_SLEEP_PROCESSING to be a function

if (NVIC->ISPR[0] | NVIC->ISPR[1] | NVIC->ISPR[2])
{
    vTaskResume(m_main_task_handle);
}


This seems to work, the system remains responsive and the power consumption measurements are as low as we want them.

However, I was thinking about theoretical correctness of the code so that the system neither sleeps too little nor too much. This does not seem to be easy to achieve.
My thoughts are:
The first call to ssd_app_evt_wait after switching to the idle task from the main task always returns immediately because software interrupts are used in task switching and ssd_app_evt_wait does not sleep if an interrupt happend since it was last called.
Hence, if I remove the check for pended interrupts in the configPOST_SLEEP_PROCESSING handler, the system basically never sleeps.
Interrupts that happen during sleep are pended since the ssd_app_evt_wait inside port_cmsis_systick.c is called in a critical section and allows for subsequent inspection of the NVIC->ISPR register.
With this configuration, my code catches all the reasons to unsuspend the main task that happen during the second call to ssd_app_evt_wait. But if an interrupt happens before the first call to ssd_app_evt_wait, for example, we cannot know since it returns immediately and clears the event register.

In other words, the race condition that is not present in ssd_app_evt_wait (or in the sequence WFE, SEV, WFE) is present in my way of calling vTaskSuspend and vTaskResume. The system will not sleep too little, but it might sleep too much.
Is there some other condition that I can check and base resumption of the main task on?

Thanks

Parents
  • Generally I agree. Modifying all the interrupt handlers to modify an additional atomic variable is kind of a last resort solution, but probably the one I'll have to use.
    But I'm not yet sure that it is feasible to modify all the interrupt handlers. Some might be hidden in binary 3rd party code that I am unable to modify and some might be in Nordic SDK code, which I can change, but would like to do so as little as possible.

Reply
  • Generally I agree. Modifying all the interrupt handlers to modify an additional atomic variable is kind of a last resort solution, but probably the one I'll have to use.
    But I'm not yet sure that it is feasible to modify all the interrupt handlers. Some might be hidden in binary 3rd party code that I am unable to modify and some might be in Nordic SDK code, which I can change, but would like to do so as little as possible.

Children
Related