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

SoftDevice preventing low-power state

I'm working on a BLE design for nRF52832, with SoftDevice S132 v5.0.0. The project uses FreeRTOS with Tickless Idle enabled. When the user powers the device off (from a UI perspective, not actually cutting power to the uP) there should be almost nothing happening and the device should go into System-on low-power for an extended period of time (seconds, if not longer). What I'm seeing, however, is that FreeRTOS calls sd_app_evt_wait() but that function returns very quickly (within about 5us) and there is no power saving.

When entering the device-off state, we call sd_ble_gap_disconnect(), ble_advertising_start(&m_advertising, BLE_ADV_MODE_IDLE), and sd_ble_gap_adv_stop() which I think should be enough to ensure the SoftDevice is completely idle.

If I *also* call nrf_sdh_disable_request() to disable the SoftDevice, then FreeRTOS calls __WFE() and the device sees significant power savings.

I would really prefer not to have to disable the SoftDevice in order to achieve useful power savings. Is there something I can do to figure out why it's not actually sleeping when I think it should be?

Thanks,
--Russ

  • In most SDK examples, the call to nrf_pwr_mgmt_run() inside the main for or while loop calls the sd_app_evt_wait() function & then afterwards calls the _WFE() function, which puts the CPU into a low power state. Take a look at the blinky central example inside the sdk/ble_central folder for example. You should not have to disable the softdevice in order to get power savings.

  • Bjorn - thanks for the quick response. I'm looking at nrf_pwr_mgmt.c in SDK 14.2.0, and it does NOT appear that _WFE() is called after sd_app_evt_wait(). Relevant code snippet:

    // Wait for an event.
    #ifdef SOFTDEVICE_PRESENT
    if (nrf_sdh_is_enabled())
    {
    ret_code_t ret_code = sd_app_evt_wait();
    ASSERT((ret_code == NRF_SUCCESS) || (ret_code == NRF_ERROR_SOFTDEVICE_NOT_ENABLED));
    UNUSED_VARIABLE(ret_code);
    }
    else
    #endif // SOFTDEVICE_PRESENT
    {
    // Wait for an event.
    __WFE();
    // Clear the internal event register.
    __SEV();
    __WFE();
    }

    Note the "else" before the block containing _WFE(). 

    Any other suggestions?

    Thanks,
    --Russ

  • I also saw this behaviour with nRF52840 and S140 where sd_app_evt_wait() would return immediately on the first call when entering tickless idle.  I proposed a different method for entry/exit to idle in this post.  The code attached to that post will stay in an inner loop around sd_app_evt_wait() until there is a runnable task or the idle time has expired.  From memory, the profiling counters in the inner loop show that sd_app_evt_wait() is almost always executed at least twice when entering idle, showing that the first sd_app_evt_wait() drops through.  There are some current consumption numbers listed which show the difference between normal tickless and my proposed changes.

  • Thanks Austin! That sounds very likely to be what I'm seeing as well. I'll give your code a try as soon as I'm able to.

  • You are of course correct. I read through the code a bit too fast & did not notice the else block.

Related