This post is more about some suggestions for review rather than a question.
I've been looking at implementing a project using the nRF52840, SDK 14.0.0 and FreeRTOS in a low power application. The release note for SDK 14.0.0. indicates that FreeRTOS is not supported on the nRF52840, however I see no reason why FreeRTOS shouldn't work on this platform.
I ported the example ble_app_hrs_freertos app for ARM GCC to pca10056 and found that current consumption was very high even with tickless idle enabled. Upon profiling the idle code, I found that sd_app_event_wait() was being called and then exiting immediately on every iteration of the idle loop.
There were what seemed to be a number of improvements that could be made. Please see the attached port_cmsis_systick.c files for my suggested changes.
They include:
- Don't turn off app interrupts when going into idle. Instead only turn off RTC timing interrupts. This should improve interrupt latency while sleeping since interrupt handlers will run directly after return from WFE events. This also allows interrupt handlers to make FreeRTOS API calls which could potentially set tasks to running.
- Stay as long as possible in the inner tickless idle loop if there is no reason to exit. That is, the only reason to exit idle is if a task has been scheduled to run, or the maximum time to wait has elapsed.
- Don't rely solely on RTC capture compare interrupt to wake from WFE. Instead, use a counter comparison check to determine if wait time has elapsed.
- Clear pending CPU event using SEV/WFE before testing for idle exit and going to sleep. This prevents any event prior to going to idle from waking the CPU immediately on a call to sd_app_event_wait().
There are likely some improvements to make to this code, however I have found that these changes result in a significant reduction in consumed power.
The attached port_cmsis_systick_with_profiling.c contains a set of counters which are ticked at various points of the idle loop to try and gain an understanding of how often events occur. eg We can determine how often the code requests idle, how many times we wake CPU from idle but the conditions for FreeRTOS are not met to exit idle (eg as a result of a BLE interrupt).
I'd be interested in feedback on this approach and to know if there are any holes in my reasoning with the proposed changes.
I've attached the ble_app_hrs_freertos app ported to pca10056. This also includes an FPU_IRQHandler to address issues with CPU not sleeping with FPU interrupt pending.
ble_app_hrs_freertos_pca10056.tgz
port_cmsis_systick_with_profiling.c
UPDATED 16th Oct 2018:
See the updated port_cmsis_systick.c which includes important changes including the following:
- Fixes a bug which could result in infinite sleep in idle. Ensure that pending RTC wake interrupt is cleared before entry to sleep.
- Ensures pending FPU interrupts are cleared before entry to sleep.
- Support GPIO profiling of time spent asleep. Use critical section around WFE instruction when profiling to ensure that GPIO pins are set to show CPU asleep/awake state prior to interrupt handlers running.