Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Going low power in freertos app

Hi, 

I have an app based on freertos_hrs example (nRF52832, SDK14.2)

I'm trying to get it into low power(sleep) mode, however the idle task keep on running and the system consumes ~4.5mA constantly (ble is off most of the time)

I tried the following:

  • Setting #define configUSE_TICKLESS_IDLE   1 in freeRTOSConfig.h but is does not seem to help.
  • Disabled NRF_Log options in sdk_config.h as several posts suggested
  • Verified that none of my app's tasks is running (All are blocked), neither is the timer task. The only task that seem to run is the idle task.
  • Verified that the idle task handler portTASK_FUNCTION() (part of freertos port) do get to the line portSUPPRESS_TICKS_AND_SLEEP() that eventually calls sd_app_evt_wait()

  • I tried to forcefully call sd_app_evt_wait() from within  the applications idle hook (vApplicationIdleHook(), #define configUSE_IDLE_HOOK  1)
    It does lower the consumed power to few uA, but I keep getting hard faults when ble activity is encountered (not sure exactly what is the cause) - e.g. advertising goes well but when connection is established ble_evt_handler() crashes in case BLE_GAP_EVT_CONNECTED block

Reading the doc it seems that implementing the 1st bullet above should take care of lowering the power but apparently something else is not set correctly.

Any help will be highly appreciated

Thanks in advance

Parents
  • which device are you running this on? 

    instead of calling sd_app_evt_wait in vApplicationIdleHook, can you try to call below

                    do{
                        __WFE();
                    } while (0 == (NVIC->ISPR[0] | NVIC->ISPR[1]));
                    

    instead of 

                if (nrf_sdh_is_enabled())
                {
                    uint32_t err_code = sd_app_evt_wait();
                    APP_ERROR_CHECK(err_code);
                }

  • Hi Susheel, 

    Thanks for your response. 

    your 2nd code snippet is in the 'heart' of vPortSuppressTicksAndSleep() in port_cmsys_systick.c which is part of the freertos package (sort of 'system file' in higher OSes)

    Do you mean to replace this in place (vPortSuppressTicksAndSleep()) or add the 1st snippet to vApplicationIdleHook() which is in the application file (main.c)

  • This seems to be due to the fact that we did not handle any floating point exceptions.

    We can do one experiment

    Can you implement the FPU_IRQHandler and see if the power consumption goes low. Add below to your code and make sure that your vector table has FPU_IRQHandler in its FPU IRQ address

    void FPU_IRQHandler(void)
    {
        uint32_t *fpscr = (uint32_t *)(FPU->FPCAR+0x40);
        (void)__get_FPSCR();
    
        *fpscr = *fpscr & ~(FPU_EXCEPTION_MASK);
    }

  • Hi Susheel, 

    Do you feel that this may be the problem ?

    I can see that PWR_MGMT_FPU_SLEEP_PREPARE macro (that seems to workaround PAN87) is called in nrf_pwr_mgmt_run() just before sd_app_evt_wait() in 'standard' app but NOT in freertos based app....

    Will update as soon as I get back to the office...

    Thanks

    btw, 

    I feel silly to ask, but how do I register an ISR? (so it appears in the vector table)

    I only used event handlers in Nordic SDK so far. 

  • eyalasko said:
    how do I register an ISR? (so it appears in the vector table)

     make sure that that there is an entry in startup.s files in your project where we populate the vector table and it DOES NOT have default do nothiing logic with it. Since those entry in startup files are weak declaration any new declaration of the same function will override those implemenation.

  • Hi Susheel, 

    For the sake of other fellow developers here is a summary of the issue and the solution that worked for me.

    The problem stems from the FPU generating an exception when doing floating point math. This interrupt can not be masked out as described in Errata 87

    As the FPU interrupt is pending, the 'go to sleep' call sd_app_evt_wait() which DO get called when freertos goes idle (in tickles mode), does practically nothing as it wakes up immediately due to the pending FPU interrupt.

    To tackle this you should clear pending interrupt before calling sd_app_evt_wait()

    There are 3 ways  to do so:

    1. Clear the FPU interrupt immediately by hooking on FPU_IRQHandler() as described in your post above; OR
    2. Clear it before idle task calls sd_app_evt_wait() the way described in Errata 87 in port_cmsis_systick.c in vPortSuppressTicksAndSleep() just before calling sd_app_evt_wait(); OR
    3. Mimic the powering down sequence of non-freertos applications. This is done in nrf_power_mgmt_run() in nrf_pwr_mgmt.c

    I choose to go with option 3 and add the PWR_MGMT_FPU_SLEEP_PREPARE() macro (with its 'implementation') to vPortSuppressTicksAndSleep() just before calling sd_app_evt_wait().

    It worked extremely well for me, hopefully for other fellow developers.

    I would highly recommend Nordic to implement this/similar fix on future version of the SDK\freertos examples

    THANK YOU for your ongoing support.

  • Thanks for coming back with good suggestions. We really value users like you who do care for others and help them to avoid similar problems. One upvote to you from my side :)

Reply Children
No Data
Related