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;

  }
}




Parents
  • Hi

    I haven't looked closely at your code yet, but it sounds like you're trying to go to sleep within an interrupt or something so the power-down process is stopped halfway because something else starts before the device reaches system OFF mode.

    Either that, or the reason it keeps waking up is that the pin that signals critical low time also wakes up the circuit because it is configured as a wake-up pin for instance.

    Best regards,

    Simon

Reply
  • Hi

    I haven't looked closely at your code yet, but it sounds like you're trying to go to sleep within an interrupt or something so the power-down process is stopped halfway because something else starts before the device reaches system OFF mode.

    Either that, or the reason it keeps waking up is that the pin that signals critical low time also wakes up the circuit because it is configured as a wake-up pin for instance.

    Best regards,

    Simon

Children
  • 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.

  • It sounds like the flash write is perhaps not completing or failing. Perhaps there is a priority issue. 

    Have you looked at this sample?

    https://docs.nordicsemi.com/bundle/ncs-latest/page/zephyr/samples/boards/nrf/system_off/README.html

    It shows how to retain some RAM. The flash is only good for 10k write/erase cycles which could become an issue. Looking at the code, it enters deep sleep differently than your code. Perhaps this method includes some safeguards to prevent issues like what you are seeing.

Related