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

nRF52832 Rebootig once in a while - unknown reason

Hi,

I made a temperature logging device using nRF52832 (SDK 12.3.0). The temperature sensor is read over I2C every 5 minutes and data is sent over radio communication. There is also battery voltage reading on 12 hours. The software is rather simple. Here is a very simplified code:

while(1) {

__SEV();
__WFE();
__WFE();

if(temperature_reading time){

//read temperature sensor

nrf_drv_twi_rx(...

}

if(voltage_reading_time){

//read voltage;

nrf_drv_saadc_sample_convert(NRF_SAADC_INPUT_VDD, &adc_buf);

}

if(send_data_time){

//Radio send data;

}

}

The problem I have is that the device is rebooting once in a while. For example if I turn on 50 of these devices a few will reboot in the period of one day (every day different one will reboot). This reboot is random in general, but as far as I managed to debug it, it is always rebooting after sensor is read and data is sent. It seems like it reboots once it reach __SEV(); __WFE(); __WFE(); sequence, but as I wrote not always but once in a while. 

reset_reason = NRF_POWER->RESETREAS; after reset gives value zero (0). I triple checked the battery contact and possible hardware related issues and that is not the reason. If it is hardware it wouldn't reboot in n*5 minutes interval (after reading and sending data).

I am trying to solve this issue for over the two months now. Any help or hint would be appreciated very much.

Parents
  • Are you using a coin cell or a battery with more oomph? The coin cell is most susceptible to causing resets; if not using the DC-DC convertor, worth enabling it to see if it affects the frequency with which the problem occurs:

       // DC-DC power supply enable, saves over using internal LDO regulator
       nrf_power_dcdcen_set(true);

    If using a coin cell temporarily add 100uF to 150uF capacitor to the coin cell to see if it affects the issue. Unless there is already significant capacitance such as that then it may be effective regardless of battery type.

    There are two errata which may be relevant: 

          // Errata 220: CPU: RAM is not ready when written - Disable IRQ while using WFE
          // Enable SEVONPEND to disable interrupts so the internal events that generate the interrupt cause wakeuup in __WFE context and not in interrupt context
          // Before: ENABLE_WAKEUP_SOURCE -> __WFE -> WAKEUP_SOURCE_ISR -> CONTINUE_FROM_ISR  next line of __WFE
          // After:  ENABLE_WAKEUP_SOURCE -> SEVONPEND -> DISABLE_INTERRUPTS -> __WFE -> WAKEUP inside __WFE -> ENABLE_interrupts -> WAKEUP_SOURCE_ISR
          //
          // Errata 75: MWU: Increased current consumption
          // This has to be handled by turning off MWU but it is used in SoftDevice
          // see https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF52832_EngB%2FERR%2FnRF52832%2FEngineeringB%2Flatest%2Fanomaly_832_75.html
          //
          // Errata 220: Enable SEVONPEND
          SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
          __disable_irq();
          // Errata 75: MWU Disable
          uint32_t MWU_AccessWatchMask = NRF_MWU->REGIONEN & MWU_ACCESS_WATCH_MASK;
          // Handle MNU if any areas are enabled
          if (MWU_AccessWatchMask)
          {
             NRF_MWU->REGIONENCLR = MWU_AccessWatchMask; // Disable write access watch in region[0] and PREGION[0]
             __WFE();
             __NOP(); __NOP(); __NOP(); __NOP();
             // Errata 75: MWU Enable
             NRF_MWU->REGIONENSET = MWU_AccessWatchMask;
          }
          else
          {
             __WFE();
             __NOP(); __NOP(); __NOP(); __NOP();
          }
          __enable_irq();

    There is a VDD ramp issue which may be relevant, typical with insufficient gap between BLE and other events or lack of storage capacitance on the battery, see 18.10.2 Device startup times Note 10

    // Note 10: A step increase in supply voltage of 300 mV or more, with rise time
    // of 300 ms or less, within the valid supply range, may result in a system reset.

  • Also, I tried to add MWU Disable but MWU_ACCESS_WATCH_MASK is not defined. 

  • My car doesn't have a battery as powerful as that ..

    For MWU_ACCESS_WATCH_MASK I added this to ./components/libraries/util/sdk_common.h:

    // Errata 75: MWU: Increased current consumption
    //  This has to be handled by turning off MWU region 0 which is used in SoftDevice
    //  see https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF52832_EngB%2FERR%2FnRF52832%2FEngineeringB%2Flatest%2Fanomaly_832_75.html
    //
    // The Memory watch unit (MWU) can be used to generate events when a memory region is accessed
    // by the CPU. The MWU can be configured to trigger events for access to Data RAM and Peripheral
    // memory segments. The MWU allows an application developer to generate memory access events during
    // development for debugging or during production execution for failure detection and recovery
    //
    // SoftDevice is protecting memory area Write 0 PRGN 0  from 0x20000000-0x20002a97, PREGION[0].SUBS 0x4200f903 (0, 1, 11, 12, 13, 14, 15, 25, 30)
    #define MWU_ACCESS_WATCH_MASK (0x0F0000FF)

    Maybe add a dedicated error handler to override the default so a system assert doesn't cause a reset but allows you to track when they happen:

    // Define this as no action to override internal check
    void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
    {
        appErrorCounter++;
    }

    Initialise it in main() before anything else if this is the very first time power has been applied,  although even better put in SystemInit():

    #define I_AM_INITIALISED 0x12345678  // Any pattern will do here
    
    main()
    {
      if (appErrorCounterReady != I_AM_INITIALISED)
      {
        appErrorCounter = 0;
        appErrorCounterReady = I_AM_INITIALISED;
      }
      // Capture reset reason
      uint32_t WakeupReason = NRF_POWER->RESETREAS;
      ...
    }

    Ensure values are not cleared on a reset; In IAR:

    // Place following data in section .noinit so it doesn't get wiped on a reset
    #pragma default_variable_attributes = @ ".noinit"
    volatile uint32_t appErrorCounter;
    volatile uint32_t appErrorCounterReady;
    #pragma default_variable_attributes =
    // End - Place following data in section .noinit so it doesn't get wiped on a reset

    In SES:

    // Place following data in section .noinit so it doesn't get wiped on a reset
    volatile uint32_t appErrorCounter       __attribute__((section(".non_init")));
    volatile uint32_t appErrorCounterReady  __attribute__((section(".non_init")));
    // End - Place following data in section .noinit so it doesn't get wiped on a reset

    Ensure you have RAM always powered up, at least the areas where the counter above is stored:

       // Set RAM power modes in system off
       //
       //  RAM0 Section 0 0x2000 0000 - 0x2000 0FFF
       //       Section 1 0x2000 1000 - 0x2000 1FFF
       //  RAM1 Section 0 0x2000 2000 - 0x2000 2FFF
       //       Section 1 0x2000 3000 - 0x2000 3FFF
       //  RAM2 Section 0 0x2000 4000 - 0x2000 4FFF
       //       Section 1 0x2000 5000 - 0x2000 5FFF
       //  RAM3 Section 0 0x2000 6000 - 0x2000 6FFF
       //       Section 1 0x2000 7000 - 0x2000 7FFF
       //  RAM4 Section 0 0x2000 8000 - 0x2000 8FFF
       //       Section 1 0x2000 9000 - 0x2000 9FFF
       //  RAM5 Section 0 0x2000 A000 - 0x2000 AFFF
       //       Section 1 0x2000 B000 - 0x2000 BFFF
       //  RAM6 Section 0 0x2000 C000 - 0x2000 CFFF
       //       Section 1 0x2000 D000 - 0x2000 DFFF
       //  RAM7 Section 0 0x2000 E000 - 0x2000 EFFF
       //       Section 1 0x2000 F000 - 0x2000 FFFF
       NRF_POWER->RAM[7].POWERSET = (POWER_RAM_POWER_S0POWER_On     << POWER_RAM_POWER_S0POWER_Pos)      |
                                    (POWER_RAM_POWER_S1POWER_On     << POWER_RAM_POWER_S1POWER_Pos)      |
                                    (POWER_RAM_POWER_S0RETENTION_On << POWER_RAM_POWER_S0RETENTION_Pos)  |
                                    (POWER_RAM_POWER_S1RETENTION_On << POWER_RAM_POWER_S1RETENTION_Pos);
    

    Be aware the Nordic errata handlers will force unexpected resets the first few times code is run after a full erase, which messes up your expected reset reason, see system_nrf52.c. An example:

        /* Configure NFCT pins as GPIOs if NFCT is not to be used in your code. If CONFIG_NFCT_PINS_AS_GPIOS is not defined,
           two GPIOs (see Product Specification to see which ones) will be reserved for NFC and will not be available as
           normal GPIOs. */
        #if defined (CONFIG_NFCT_PINS_AS_GPIOS)
            if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){
                NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; // Write Enable
                while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
                NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;
                while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
                NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; // Read-only Enable
                while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
                // UICR changes require a reset to be effective
                NVIC_SystemReset();
            }
        #endif

Reply
  • My car doesn't have a battery as powerful as that ..

    For MWU_ACCESS_WATCH_MASK I added this to ./components/libraries/util/sdk_common.h:

    // Errata 75: MWU: Increased current consumption
    //  This has to be handled by turning off MWU region 0 which is used in SoftDevice
    //  see https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF52832_EngB%2FERR%2FnRF52832%2FEngineeringB%2Flatest%2Fanomaly_832_75.html
    //
    // The Memory watch unit (MWU) can be used to generate events when a memory region is accessed
    // by the CPU. The MWU can be configured to trigger events for access to Data RAM and Peripheral
    // memory segments. The MWU allows an application developer to generate memory access events during
    // development for debugging or during production execution for failure detection and recovery
    //
    // SoftDevice is protecting memory area Write 0 PRGN 0  from 0x20000000-0x20002a97, PREGION[0].SUBS 0x4200f903 (0, 1, 11, 12, 13, 14, 15, 25, 30)
    #define MWU_ACCESS_WATCH_MASK (0x0F0000FF)

    Maybe add a dedicated error handler to override the default so a system assert doesn't cause a reset but allows you to track when they happen:

    // Define this as no action to override internal check
    void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
    {
        appErrorCounter++;
    }

    Initialise it in main() before anything else if this is the very first time power has been applied,  although even better put in SystemInit():

    #define I_AM_INITIALISED 0x12345678  // Any pattern will do here
    
    main()
    {
      if (appErrorCounterReady != I_AM_INITIALISED)
      {
        appErrorCounter = 0;
        appErrorCounterReady = I_AM_INITIALISED;
      }
      // Capture reset reason
      uint32_t WakeupReason = NRF_POWER->RESETREAS;
      ...
    }

    Ensure values are not cleared on a reset; In IAR:

    // Place following data in section .noinit so it doesn't get wiped on a reset
    #pragma default_variable_attributes = @ ".noinit"
    volatile uint32_t appErrorCounter;
    volatile uint32_t appErrorCounterReady;
    #pragma default_variable_attributes =
    // End - Place following data in section .noinit so it doesn't get wiped on a reset

    In SES:

    // Place following data in section .noinit so it doesn't get wiped on a reset
    volatile uint32_t appErrorCounter       __attribute__((section(".non_init")));
    volatile uint32_t appErrorCounterReady  __attribute__((section(".non_init")));
    // End - Place following data in section .noinit so it doesn't get wiped on a reset

    Ensure you have RAM always powered up, at least the areas where the counter above is stored:

       // Set RAM power modes in system off
       //
       //  RAM0 Section 0 0x2000 0000 - 0x2000 0FFF
       //       Section 1 0x2000 1000 - 0x2000 1FFF
       //  RAM1 Section 0 0x2000 2000 - 0x2000 2FFF
       //       Section 1 0x2000 3000 - 0x2000 3FFF
       //  RAM2 Section 0 0x2000 4000 - 0x2000 4FFF
       //       Section 1 0x2000 5000 - 0x2000 5FFF
       //  RAM3 Section 0 0x2000 6000 - 0x2000 6FFF
       //       Section 1 0x2000 7000 - 0x2000 7FFF
       //  RAM4 Section 0 0x2000 8000 - 0x2000 8FFF
       //       Section 1 0x2000 9000 - 0x2000 9FFF
       //  RAM5 Section 0 0x2000 A000 - 0x2000 AFFF
       //       Section 1 0x2000 B000 - 0x2000 BFFF
       //  RAM6 Section 0 0x2000 C000 - 0x2000 CFFF
       //       Section 1 0x2000 D000 - 0x2000 DFFF
       //  RAM7 Section 0 0x2000 E000 - 0x2000 EFFF
       //       Section 1 0x2000 F000 - 0x2000 FFFF
       NRF_POWER->RAM[7].POWERSET = (POWER_RAM_POWER_S0POWER_On     << POWER_RAM_POWER_S0POWER_Pos)      |
                                    (POWER_RAM_POWER_S1POWER_On     << POWER_RAM_POWER_S1POWER_Pos)      |
                                    (POWER_RAM_POWER_S0RETENTION_On << POWER_RAM_POWER_S0RETENTION_Pos)  |
                                    (POWER_RAM_POWER_S1RETENTION_On << POWER_RAM_POWER_S1RETENTION_Pos);
    

    Be aware the Nordic errata handlers will force unexpected resets the first few times code is run after a full erase, which messes up your expected reset reason, see system_nrf52.c. An example:

        /* Configure NFCT pins as GPIOs if NFCT is not to be used in your code. If CONFIG_NFCT_PINS_AS_GPIOS is not defined,
           two GPIOs (see Product Specification to see which ones) will be reserved for NFC and will not be available as
           normal GPIOs. */
        #if defined (CONFIG_NFCT_PINS_AS_GPIOS)
            if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){
                NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; // Write Enable
                while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
                NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;
                while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
                NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; // Read-only Enable
                while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
                // UICR changes require a reset to be effective
                NVIC_SystemReset();
            }
        #endif

Children
No Data
Related