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

nRF52 does not wake from sleep when radio timeslot is active

Hi,

We use the nRF radio timeslot API to take control over the radio and other peripherals periodically. We have noticed that when the timeslot is active (we own the peripherals) and we call nrf_pwr_mgmt_run() to sleep, the system never wakes again. To solve it we have to do the following workaround:

static void IdleStateHandler(void)
{
  // Handle pending app events before going to sleep
  app_sched_execute();
  // NOTE: Dont sleep if radio timeslot active since it does not wake again
  // Likely related to the usage of radio timeslot
  if (!RadioTimeslotIsActive() && NRF_LOG_PROCESS() == false)
  {
#if NRF_MODULE_ENABLED(NRF_PWR_MGMT)
    nrf_pwr_mgmt_run();
#endif
  }
}

I would like to know how this is meant to work!

I understand that it may be an issue if the system goes to deep sleep since the wakeup time may introduce a jitter. However, it should be possible to go to shallow sleep (WFI) to save the power consumption of the MCU core. The workaround above means that the MCU core is spinning as long as the timeslot is active, which drains the battery faster.

We use:

nRF52840 DK

nRF5 SDK ver 16.0.0

Softdevice: s113_nrf52_7.0.1_softdevice.hex

BR / Björn

  • Have you tried to add a log message in NRF_RADIO_CALLBACK_SIGNAL_TYPE_START? I don't quite follow your LED logic, but I see that the NRF_RADIO_CALLBACK_SIGNAL_TYPE_START event occurs even if the LEDs are not toggling. Could it be that the issue is related to the LED logic or the timer?

    BR,

    Edvin

  • Hi Edvin,

    I dont understand why I should add a log message in NRF_RADIO_CALLBACK_SIGNAL_TYPE_START? I know that this signal is coming. In fact, all timeslot signals come as expected, so the whole function radio_callback() works as expected.

    The point is that nrf_pwr_mgmt_run() called from idle_state_handle() in main.c never returns, despite the fact that the timeslot signals (interrupts) are fired. Interrupts shall make the system wake up and hence make nrf_pwr_mgmt_run() return. This is the issue.

    So my sample show: Timeslot interrupts dont wake the system as expected meaning that nrf_pwr_mgmt_run() never returns. 

    I have simplified the sample to bare bone, see ts_sample_simple.c. Now it is supposed to toggle LED_1 with period 100 ms. You have the following configs in ts_sample_simple.c:

    // Set to toggle LED in main context instead of IRQ context
    // Will not work since Timeslot IRQ does not make
    // the power manager wake up
    #define TOGGLE_LED_IN_MAIN_CTX (1)
    
    // Set to wake the power manager after end of timeslot
    // Workaround to make processing in main context work
    #define TRIGGER_IRQ_AT_END_OF_TIMESLOT (0)
    

    Try the following combinations:

    1) Toggle in IRQ context => Works
    #define TOGGLE_LED_IN_MAIN_CTX (0)
    #define TRIGGER_IRQ_AT_END_OF_TIMESLOT (0)

    2) Toggle in main context => DOES NOT WORK (but should according to me)
    #define TOGGLE_LED_IN_MAIN_CTX (1)
    #define TRIGGER_IRQ_AT_END_OF_TIMESLOT (0)

    3) Toggle in main context with extra IRQ workaround => works
    #define TOGGLE_LED_IN_MAIN_CTX (1)
    #define TRIGGER_IRQ_AT_END_OF_TIMESLOT (1)

    BR / Björn

    ble_app_beacon_ts_simplified.zip

  • Oh, I thought that the issue was that your radio notifications wasn't working.

     

    Bjorn191023 said:
    2) Toggle in main context => DOES NOT WORK (but should according to me)
    #define TOGGLE_LED_IN_MAIN_CTX (1)
    #define TRIGGER_IRQ_AT_END_OF_TIMESLOT (0)

     So TsSampleMainHandler() should toggle leds if TOGGLE_LED_IN_MAIN_CTX == 1 whenever the main loop is run, but the main loop isn't run if TRIGGER_IRQ_AT_END_OF_TIMESLOT != 1. 

    So sd_app_evt_wait(), called by idle_state_handle() -> nrf_pwr_mgmt_init() -> sd_app_evt_wait(), will wake up whenever there is an application interrupt. I guess the timeslots are not counted as application interrupts, but pure softdevice interrupts. 

    sd_app_evt_wait() will not wake up the application at all softdevice events, such as an advertisement event, or connection event (events that occurs every connection interval, to maintain the connection). It will only wake up the application when there either is a peripheral event that the application has set up, or if there is a softdevice event that is sent to the application, such as if someone writes to one of the characteristics. 

    So if you enter sd_app_evt_wait(), the main context will not run again until you have an event. This is also why you see that it wakes up when you set the IRQ in your timeslot. This is something that the application should handle, and therefore it is woken up. 

    The reason it works when TOGGLE_LED_IN_MAIN_CTX(0) and TRIGGER_IRQ_AT_END_OF_TIMESLOT(0) is, as you probably know, that you toggle it in the TIMER0 callback. 

    If you want to e.g. toggle a led from your main context, you can use a timer for that purpose, pretty much like you do in the TIMER0 callback in your timeslot callback. If you want to propagate this to the application context, you can look into the EGU (event generator unit), or to have a callback function for the peripheral itself. 

    The reason this doesn't happen in the TIMER0 case is that the TIMER0 is handled by the softdevice. If you try to use for example TIMER1, and set up a callback in the application you should see it there, and it will run the main loop one more time after the callback.

    BR,

    Edvin

  • Thanks for the response Edvin. 

    So the conclusion is that nrf_pwr_mgmt_run() -> sd_app_evt_wait() only returns on app interrupts and not on softdevice interrupts even if they are routed to the timeslot signal handler.

    I think you should update the documentation of nrf_pwr_mgmt_run() and sd_app_evt_wait() and clarify how it works since it's not obvious.

    BR / Björn

Related