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;

  }
}




  • Good thinking. High-jacking the timer's event handler seems to be working so I'm going to call this closed but this feels very hacky. I'd still like to know what I'm missing; why I can't get this to work from my main function. I feel like this is going to come up again.

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

  • I will definitely look into Zephyr for future projects. For now, this project is expecting user interaction 4-5 times per day. Even on the outside, that gets us 5+ years of use. I'm afraid that's probably more life than we can expect from the tiny batteries that we're using.

  • Hi again Kenneth

    Why exactly do you write to flash in the sleep_system() call? From your snippet showing the sleep_system() function I think what happens is that the device tries going to sleep before the flash erase/write procedures are complete.

    Can you try increasing the delay to see if that helps? Or put these calls into a separate function that waits until the flash operations are complete before calling the shutdown function.

    Best regards,

    Simon

  • Simon,

    I just figured it would make sense to package them together since the data save and shutdown actions should always happen together, never apart. I have tried increasing that delay all the way as high as 1 second without a change in behavior. I had also tried separating the FLASH erase and write functions and the call to sleep without change. I am currently getting good results by switching the critical battery alert from a direct call to the sleep_system() function into a call to first stop the inactivity timer and then restart it with a starting value of 1. I figure there has to be something going on behind the scenes before the timer's event handler is fired that is helping. Just wish I knew what it was.

    It may be interesting to note that if either the call to erase or the call to write to FLASH remain, it fails. Both commands have to be removed for proper operation of the sleep_system() function when called from the main loop.

Related