WDT continues to run while in deep sleep mode.

My project utilizes the deep sleep or systemOff() function to minimize battery consumption. I'm at the final stages of development and I've run into some strange behavior. There are two occasions where we want the device to go to sleep. It is important to note that the sleep function called is the same in both circumstances:

Inactivity timer expires: After 30 seconds of no user activity the device should go to sleep. This works fine. A timer is used and my sleep function is called where important data is first saved to the last page in FLASH memory and then the device goes to sleep. When the device wakes up, it reads the saved data and runs with the saved parameters. No problem.

Critical battery alert: Here's where the problem lies. I have an analog pin connected to the battery with a lower voltage threshold programmed to set a "critical battery flag" if the voltage drops below it. If the critical battery flag is set the program runs the same sleep function as before and the device seems to go to sleep, accept that the WDT seems to be running. The device repeatedly resets, sees the battery is still low and goes to sleep only to wake right back up. I can increase the time it stays asleep by increasing the WDT time. Furthermore, once battery voltage is restored, the device wakes up as if the FLASH was empty/erased. If it was indeed shutting down successfully after the critical battery flag then it should have stored the data.

I found a post with a similar issue here. I'm not quite sure how to get PWR_MGMT_FPU_SLEEP_PREPARE to call from the main function, though, and nrf_pwr_mgmt_run() isn't working either. Any insight on how the WTD might wake up the system from deep sleep in one instance but not the other?

void sleep_system(void){

  uint32_t new_data [3] = {combination, ble_flags, battery_vthresh};  //  Backup important data.
  
  flash_erase(p_flash_adr_base);

  flash_write(p_flash_adr_base, new_data);

  //pwr_mgmt_fpu_sleep_prepare();
  //PWR_MGMT_FPU_SLEEP_PREPARE();
  nrf_pwr_mgmt_run();

  nrf_delay_ms(100);  //  Make sure backup is complete before running systemOff() as it will reset the MCU and erase RAM memory.

  systemOff();

}




uint32_t flash_read(uint32_t * adr){

  NRF_LOG_INFO("Reading from FLASH memory...");

  NRF_LOG_INFO("Data: %x at address: %x", *adr, adr);

  return *adr;

}




void flash_erase(uint32_t * adr){

  uint32_t err_code;
  uint32_t evt = 0;

  NRF_LOG_INFO("Erasing last page in FLASH memory...");
  NRF_LOG_INFO("Page #: %x", flash_page);


  err_code = sd_flash_page_erase(flash_page);

  APP_ERROR_CHECK(err_code);

  while(!evt){

    sd_evt_get(&evt);

  }
  if(evt == NRF_EVT_FLASH_OPERATION_ERROR){

    NRF_LOG_INFO("Error erasing FLASH.");
    return;

  }

  if(evt == NRF_EVT_FLASH_OPERATION_SUCCESS){

    NRF_LOG_INFO("FLASH page erased.");
    return;

  }
}




void flash_write(uint32_t * adr, uint32_t * new_data){

  uint32_t err_code;
  uint32_t evt = 0;

  NRF_LOG_INFO("Writing to FLASH memory...");

  err_code = sd_flash_write(adr, new_data, sizeof(new_data));
  APP_ERROR_CHECK(err_code);

  while(!evt){

    sd_evt_get(&evt);

  }
  if(evt == NRF_EVT_FLASH_OPERATION_ERROR){

    NRF_LOG_INFO("Error writing to FLASH.");
    return;

  }

  if(evt == NRF_EVT_FLASH_OPERATION_SUCCESS){

    NRF_LOG_INFO("Success writing to FLASH.");
    return;

  }
}




  • I think you answered your own question; there will be no further timer event interrupt to exit sleep if the sleep was started in the timer event interrupt. If you want the same behaviour for the critical interrupt, have the critical interrupt either invoke the timer interrupt (thus blocking the timer interrupt) or better set a flag in the critical interrupt which the next timer interrupt will see and thus invoke sleep from the timer interrupt thus blocking the same ie not in main.

  • Okay, a bit of history. I modeled this project off of a tutorial which used the nrf_pwr_mgmt API. When I implemented this into my earlier code everything seemed to work with the BLE, but without a BLE connection it was going to sleep during my custom functions. I got frustrated and scrapped the nrf_pwr_mgmt API with the intent to manually engage the deep sleep mode. That was part of the problem. I have now switched back to using the nrf API (for some reason, something I've added prevents it from going to sleep with or without a BLE connection now, which is fine) and am using the nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF) to achieve the same ends.

    One more thing, I've changed my sleep function to this:

    void sleep_system(void){
    
      uint32_t new_data [3] = {combination, ble_flags, battery_vthresh};  //  Backup important data.
      
      flash_erase(p_flash_adr_base);
    
      flash_write(p_flash_adr_base, new_data);
    
      nrf_delay_ms(100);  //  Make sure backup is complete before running systemOff() as it will reset the MCU and erase RAM memory.
    
      nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
    
    }

    The call to the sleep function from the inactivity timer event handler still works but if I execute the critical battery shutdown like this:

     if(return_flag == flag_code_batt_crit){
    
          nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
    
        }

    the device sleeps like it should, but when I call it like this:

        if(return_flag == flag_code_batt_crit){
    
          sleep_system();
    
        }
    

    it reverts back to the earlier behavior that the FLASH write fails (no error, just evident upon the next startup that the FLASH is empty), and the system fails going to sleep presumably because the WDT still running though it's setup to pause during sleep and hault.

    Finally, I pulled the call to nrf_pwr_mgmt_shutdown() from the sleep_system() function and placed it after the call to sleep_system() in both the timer event handler and the main loop where it checks the battery flag. Same weird repeated FLASH write fail and reset. Still works from the timer event handler. Any ideas why a previous call to erase/write to flash should prevent a shutdown? Not as important but still curious, anyone know why the power management system doesn't sleep my board on timeout anymore? (Maybe this is all somehow tied up with the app timers I use.)

  • Running the code repeatedly shows that even when triggered by the inactivity timer event, a small percentage of the time it doesn't properly enter sleep and cannot be woken by the power button interrupt (currently the only way it's set up to wake). I've tried shutting off the timers at the beginning of the sleep function but still no change.

  • It seems like a race condition, or something. With the calls to erase and write to FLASH removed from the sleep_system() function it will behave as expected. I still don't understand why accessing the FLASH doesn't have an effect on functionality as long as the sleep_system() function is called from the timer event handler.

  • If I debug it I get a SOFTDEVICE: ASSERTION FAILED error.

Related