I am rather new to FreeRTOS…
I have an embedded application running multiple tasks. One for the display, one for sensors, one for buttons, a main task that coordinates between buttons and the display (and a few other things not yet implemented) and one for a long calculation (the calculation is broken up into short chunks).
The application uses NXP’s FreeRTOS version (Amazon) and it’s running on an LPC54102 (Arm 4) processor.
I have implemented a low power mode that is entered by holding a button. When this is detected, I send a “SLEEP” notification to all tasks. The tasks do any housekeeping required to enter the low power mode. This includes powering down sensors, the display, etc. All the tasks uses xTaskNotifyWait to get the notifications. All notifications are sent with xTaskNotify with eSetBits.
The way NXP (it may the same in other ports, I don’t have the experience to know) implements low power is in the idle task:
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 )
{
__asm volatile( "dsb" ::: "memory" );
__asm volatile( "wfi" );
__asm volatile( "isb" );
}
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
The two macros config*_SLEEP_PROCESSING are defined by me in FreeRTOSConfig.h and they call functions that configure for deep sleep if required. In that case, I enable a wakeup source, call an SDK function to enable a Power Down mode and set xModifiableIdleTime is set to zero (so that the above doesn’t do anything). If power down is not required, the macros set xModifiableIdleTime to 1 and the processor enters a low power wait state (Sleep) as it should.
My assumption is that with the SLEEP notifications sent to all the tasks, the system doesn’t enter idle until all the tasks process the notifications. Is this a safe assumption? It appears to work as all power down code executes giving us a power down current of ~25 uA.
On processor wake, I send notifications to all tasks to WAKE which causes the tasks to reconfigure their associated hardware from power down to running (powering up the display, sensors, etc).
I do not stop/delete any tasks.
The problem I’m having is that the occasionally (1 out of 20 to 30 times) on wake, one task does not respond to the notification. The notification is sent and I have traced what I think is a symptom of the problem in the function xTaskGenericNotify(). The first part of this function does find the task, and set the pxTCB->ulNotifiedValue to the notification sent. The second part of this function has an IF statement:
/* If the task is in the blocked state specifically to wait for a
notification then unblock it now. */
if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
{
...
}
When the task doesn’t respond to the notification, this IF statement is not true and the code is never entered as if the task isn’t waiting for notifications, but I think it is - or last should be.
This task that doesn’t get the notification does have one interrupt that is from a timer - it sends a notification to take measurements. This timer is stopped during power down and is not active when the WAKE notification is sent.
I have gone through the FAQ and I don’t think I’m doing any of the things it says not to do. Unfortunately, I am limited on what code I can post.
Thanks!