nRF52832 high current consumption after reset

Hi folks

We are facing an issue with occasionally ~240 uA added current consumption on our nRF52832 based custom board when it comes out of reset. We only see the problem on maybe 1-2% of the devices and even devices having this erratic behavior does not aways exhibit this issue. To narrow down the root cause of the problem we have tried various things, but so far only below "solutions" seems to solve the problem:

1. Replace the softreset with a watchdog reset seems to solve the problem.
2. Removing the secure bootloader from the solution and just let the device startup in our application from reset seems to solve the problem. We can softreset the device without having the extra current consumption after reset.

We have verified that just before softresetting the device the current consumption is normal (not the added ~230 uA), but just after reset the current is added an so far only if the secure bootloader is part of the solution.

Judging from the amount of added current consumption, I suspect it is a resource in the chip that has requested for the HF oscillator and forget to turn it off again. Is there any known issues regarding this with the secure bootloader? Any other clue that could cause this issue? 

We are using Softdevice S132 v5.0.0 / SDK 14.0.0 and its accompanying secure_bootloader_ble

Parents
  • Hi,

    Is the device using the LFXO or LFRC as low frequency clock soruce? The reason I ask is that there is a known issue in S132 version 5 where the HFXO may be left running after LFRC calibration. Thisis fixed in version 6.0.0.

  • Both the bootloader and the application are configured with "CLOCK_CONFIG_LF_SRC 1" in the sdk_config.h file, which means 32 kHz XTAL, we are not using the LFRC oscillator.

  • "A retained register is a register that will retain its value in System OFF mode and through a reset, depending on reset source" (quote from the link Einar provided). Now softreset retains registers including the port pins CNF register, which may have a pull-up or pull-down enabled. Watchdog reset clears the port CNF register, probably clearing any pull-up or pull-down settings. "The PIN_CNF registers are retained registers".

    Pull-up or pull-down resistance value is about 13k0 and 3.3V @ 13k = 250uA, merely a coincidence?

    If not a coincidence - and simple to test - clear all port CNF registers immediately before a softreset.

  • Sorry for not getting back on this topic, but had been away for a while. However I have now had the time to investigate this a bit further.

    My first assumptions around the HFXO not being turned off was wrong. The HFXO is indeed turned off. Further investigations however reveals that the problem is related to the Watchdog. We use the Watchdog in our application with a timeout of 120 sec and feeds the watchdog every 10 sec. We have it configured this way:

    void watchdog_init(uint32_t seconds)
    {
    if (NRF_WDT->RUNSTATUS & (WDT_RUNSTATUS_RUNSTATUS_Running << WDT_RUNSTATUS_RUNSTATUS_Pos)) {
    // Watchdog is already running which means that this was a soft reset and the watchdog
    // is already configured

    // Feed dog
    watchdog_feed();
    } else {
    // Not running, need to configure

    // Run watchdog in sleep mode, pause watchdog in debug halt mode
    NRF_WDT->CONFIG = (WDT_CONFIG_SLEEP_Run << WDT_CONFIG_SLEEP_Pos) | (WDT_CONFIG_HALT_Pause << WDT_CONFIG_HALT_Pos);

    // 120 second timeout
    NRF_WDT->CRV = seconds * 32768 - 1;

    // Require RR0 to feed watchdog
    NRF_WDT->RREN = (WDT_RREN_RR0_Enabled << WDT_RREN_RR0_Pos);

    // Go!
    NRF_WDT->TASKS_START = 1;
    }
    }

    So the Watchdog keeps running when the system is idling.

    What is seen to be consistent behavior is the following:

    1) Power On Reset -> Bootloader passes execution to application -> application configures the WDOG for the first and only time -> application feeds WDOG every 10 sec. (Power consumption is a couple of uA's OKAY).

    2) Next at some point in time, the application soft reset the device -> Bootloader passes execution to application -> application feeds watchdog every 10 sec. (Power consumption is now ~ 250 uA BAD).

    3) Application again soft reset device at some point in time -> Bootloader passes execution to application -> application feeds WDOG every 10 sec. (Power consumption is a couple of uA's OKAY).

     

    4) Application once again soft reset device at some point in time -> Bootloader passes execution to application -> application feeds WDOG every 10 sec. (Power consumption is a couple of uA's OKAY).

    5) Application once again soft reset device at some point in time and the device now behave as in 2) 

    This pattern repeats itself infinitely that is every third soft reset provokes the high current usage.

    I have then tried to reconfigure the watchdog so the watchdog is also stopped when CPU is idling like this:

    NRF_WDT->CONFIG = (WDT_CONFIG_HALT_Pause << WDT_CONFIG_HALT_Pos);

    Now the behavior changes a bit regarding the current consumption:

    1) Power On Reset -> Bootloader passes execution to application -> application configures the WDOG for the first and only time -> application feeds WDOG every 10 sec. (Power consumption is a couple of uA's OKAY).

    2) Next at some point in time, the application soft reset the device -> Bootloader passes execution to application -> application feeds watchdog every 10 sec. Power consumption is now ~ 2 uA for the first 30 sec (equal to 3 retriggering of the watchdog) and at the 3rd retriggering, the current jumps to ~250 uA and stays there until the next retriggering 10 sec. later where current falls back to ~2 uA. This pattern then repeats itself for every retriggering of the watchdog.

    Now at this point Power-On reset doesn't remove this problem.

    Apparently an issues with the Watchdog system (there are also a couple errata around the watchdog and I also see other users have reported similar issues). However could it also be an issues with the bootloader and application compatibility? I see that the bootloader de-initialize the clock system before passing execution to the application and for that to work with the an already enabled watchdog (after a soft reset) I had let the bootloader NOT stop the LFCLK which it normally does.

    Br Kim

  • I should add that completely stop using the watchdog in the application also solves the problem.

  • How is sleep related to the watchdog trigger, is it asynchronous? ok-ok-ok-high-ok-ok-ok-high-... looks suspicious if that is always the sequence. Any DMA transfers taking place, and if so and especially with multiple DMAs are the DMA buffers enforced to lie within different RAM blocks? That includes a single SPI with Rx and Tx buffers lying in separate RAM blocks. If common RAM, then worth enforcing separation just in case.

  • Well the systems wakes up from System ON Idle using a timer interrupt, in the timer callback function, an event is put on the schedulers event queue, which is then dequeued by the scheduler right after. This event is then propagated to the application out of the interrupt context and the watchdog is retriggered when application receives this event. So the answer to your question: Sleeping and retriggering the watchdog is working in a synchronous manner. We are not using the DMA.

    Just tested by NOT retriggering the watchdog. Test scenario 1 above behaves the same way, however test scenario 2 doesn't, that is the current jumps synchronous to the retriggering disappears.

Reply
  • Well the systems wakes up from System ON Idle using a timer interrupt, in the timer callback function, an event is put on the schedulers event queue, which is then dequeued by the scheduler right after. This event is then propagated to the application out of the interrupt context and the watchdog is retriggered when application receives this event. So the answer to your question: Sleeping and retriggering the watchdog is working in a synchronous manner. We are not using the DMA.

    Just tested by NOT retriggering the watchdog. Test scenario 1 above behaves the same way, however test scenario 2 doesn't, that is the current jumps synchronous to the retriggering disappears.

Children
  • Interesting .. perhaps try changing the 10 sec retrigger to (say) 11 sec to see if the cycle changes at all. Maybe there is some race condition or side effect with the system timer/scheduler.

  • I already tried that (5 sec) and the alternating current consumption follows the frequency of the retriggering.

  • Now tried without the bootloader involved at all (debug build but with same build switches) and optimization level as in the release build). In test scenario 1 it now works as expected with only ~2 uA standby current after each soft reset. However Test scenario 2 is the same, every retriggering of the watchdog causes the standby current to jump between 2 uA and 250 uA. 

  • I wrote some bare-metal code which doesn't exhibit the issue; how different is the code you have issues with? Sleep has a bunch of issues regarding power, so possibly it's some weird combination of sleep and WDT

    // Watchdog WDT
    // RR[0] register request reload access key value
    #define WATCHDOG_RELOAD_VALUE 0x6E524635
    // Set 60 second watchdog timeout
    #define WDT_TIMWOUT ((60UL * 32768UL) - 1UL)
    #define TYPICAL_INTERRUPT_PRIORITY  6
    // RTC ticks per second using 8 Hz
    #define RTC_TICKS_PER_SECOND 8UL
    // Retrigger watchdog, maybe every 10 seconds
    #define TRIGGER_COUNT_IN_TICKS (10UL*RTC_TICKS_PER_SECOND)
    // Throw in a soft reset every now and then, maybe every 90 seconds
    #define SOFT_RESET_COUNT_IN_TICKS (90UL*RTC_TICKS_PER_SECOND)
    // Throw in a watchdog reset every now and then, maybe every 900 seconds
    #define WATCHDOG_RESET_COUNT_IN_TICKS (900UL*RTC_TICKS_PER_SECOND)
    
    static NRF_RTC_Type *pSpiRTC  = NRF_RTC2;
    IRQn_Type SpiRTC_IRQn         = RTC2_IRQn;
    volatile bool mRTC_Tick = true;
    // Counter for how often the watchdog should be triggered, cleared on every reset
    uint32_t WDT_TriggerPeriodCounter = 0UL;
    // Counter for how often the soft reset should be issued, cleared on every reset
    uint32_t SystemResetCounter = 0UL;
    // Place following data in section .noinit (IAR) so it doesn't get wiped on a reset (.non_init SES & .noinit GCC)
    #pragma default_variable_attributes = @ ".noinit"
    static uint32_t SystemWatchdogTimer __attribute__((section(".noinit")));
    #pragma default_variable_attributes = // ends ".noinit"
    
    void RTC2_IRQHandler(void)
    {
        if (pSpiRTC->EVENTS_TICK == 1)
        {
            pSpiRTC->EVENTS_TICK = 0;
            mRTC_Tick = true;
        }
        // Clear any pending hardware register bus operations
        __DSB();
    }
    
    // Run this code from startup before SystemInit()
    static void TestWatchdog(void)
    {
       // Unless cleared, the RESETREAS register will be cumulative. A field is cleared by writing '1' to it. If none of
       // the reset sources are flagged, this indicates that the chip was reset from the on-chip reset generator, which
       // will indicate a power-on-reset or a brownout reset
       // Workaround for Errata 136: System: Bits in RESETREAS are set when they should not be
       if (1) //(errata_136())
       {
          if (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)
          {
             NRF_POWER->RESETREAS = ~POWER_RESETREAS_RESETPIN_Msk;
          }
       }
       // Check reset reasons - Watchdog
       if (NRF_POWER->RESETREAS & POWER_RESETREAS_DOG_Msk)
       {
       }
       // Check reset reasons - soft reset
       if (NRF_POWER->RESETREAS & POWER_RESETREAS_SREQ_Msk)
       {
       }
       // Watchdog and timer should be running if this is a repeated soft reset; also restart on watchdog reset
       if ((NRF_WDT->RUNSTATUS == 0) || ((NRF_POWER->RESETREAS & POWER_RESETREAS_SREQ_Msk) == 0) || (NRF_POWER->RESETREAS & POWER_RESETREAS_DOG_Msk))
       {
          // Tested if RTC safely starts a non-running LFCLK - it does not
          // Watchdog not running - assume power-on reset so init LFCLK and WDT
          SystemWatchdogTimer = 0UL;
          // Select 32kHz clock source
          //NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos;
          NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_RC << CLOCK_LFCLKSRC_SRC_Pos;
          //NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_Synth << CLOCK_LFCLKSRC_SRC_Pos;
          // Start 32kHz clock
          NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
          __DSB();
          NRF_CLOCK->TASKS_LFCLKSTART = 1;
          __DSB();
          while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) ;
          // Clear started event
          NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
          // Start RTC, enable TICK event
          // Select tick: 12 bit prescaler for COUNTER frequency (32768/(PRESCALER+1)). Must be written when RTC is stopped
          pSpiRTC->PRESCALER = 4095; // max prescaler 0xFFF -> 8 Hz "Tick"
          pSpiRTC->EVTENSET = RTC_EVTENSET_TICK_Msk;
          // Set interrupt priority higher than SWI/EGU priority and enable interrupt
          NVIC_SetPriority(SpiRTC_IRQn, TYPICAL_INTERRUPT_PRIORITY);
          NVIC_ClearPendingIRQ(SpiRTC_IRQn);
          NVIC_EnableIRQ(SpiRTC_IRQn);
          // Enable tick interrupt
          pSpiRTC->INTENSET = 0x00001;
          // The update of COUNTER relies on a stable LFCLK, TASKS_START while LFCLK is not running will start
          // LFCLK, but the update will be delayed by up to ~250 us
          pSpiRTC->TASKS_START = 1;
          // Set watchdog WDT mode
          NRF_WDT->CONFIG = 1UL;
          // Set timeout
          NRF_WDT->CRV = (uint32_t)WDT_TIMWOUT;
          // Enable channel 0
          NRF_WDT->RREN = 1UL;
          // Enable
          NRF_WDT->TASKS_START = 1UL;
       }
       // Clear all reset reasons
       NRF_POWER->RESETREAS = 0xFFFFFFFFUL;
       // Ensure reset timer is cleared
       SystemResetCounter = 0UL;
       while (1) {
          // Wakeup RTC_TICKS_PER_SECOND (8) times per second
          while(!mRTC_Tick)
          {
             //nrf_gpio_pin_set(X14_PIN);
             // 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();
             // Clear the internal event register and wait for event - note an interrupt is required
             __WFE(); __SEV(); __WFE(); __NOP(); __NOP(); __NOP(); __NOP();
             __enable_irq();
          }
          // Get here RTC_TICKS_PER_SECOND (8) times per second
          mRTC_Tick = false;
          // System ticks wake up frequently, retrigger watchdog every TRIGGER_COUNT_IN__TICKS seconds
          // Retrigger, technically only retrigger if trigger not already pending; hold off if waiting for watchdog reset
          WDT_TriggerPeriodCounter++;
          // Force a periodic watchdog reset
          SystemWatchdogTimer++;
          if ((NRF_WDT->REQSTATUS == 1UL) && (SystemWatchdogTimer < WATCHDOG_RESET_COUNT_IN_TICKS) &&  (WDT_TriggerPeriodCounter >= TRIGGER_COUNT_IN_TICKS))
          {
             NRF_WDT->RR[0] = WATCHDOG_RELOAD_VALUE;
             WDT_TriggerPeriodCounter = 0UL;
          }
          // Barrier to ensure register is set before sleep etc
          __DSB();
          // Throw in a soft reset every now and then, maybe every 90 seconds
          if (++SystemResetCounter > SOFT_RESET_COUNT_IN_TICKS)
          {
             // Clear all reset reasons
             NRF_POWER->RESETREAS = 0xFFFFFFFFUL;
             // Reset on next tick to ensure tick interrupt doesn't occur during a reset
             while(!mRTC_Tick) ;
             mRTC_Tick = false;
             NVIC_SystemReset();
          }
       }
    }

    Edits: Added periodic soft reset. Added only init watchdog and LFCLK if watchdog not running

    Maybe try running this code on a failing device; the code can run before errata in SystemInit().

  • Thanks for suggestions hmolesworth, however I now managed to pinpoint exactly where for some strange reason things goes wrong in Test Scenario 1 (which we use).

    In the bootloader code the nrf_drv_clock.c there is a function to start the LF CLK. In the SDK we use it looks like this:

    static void lfclk_start(void)
    {
      nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED);
      nrf_clock_int_enable(NRF_CLOCK_INT_LF_STARTED_MASK);
      nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
    }

    This is called during startup in the bootloader code.

    Running this code we experience the OK OK BAD OK OK BAD .... sequence when ever we soft reset the device.

    Now I discovered inserting a wait just before starting the LF CLK the current consumption is ~2 uA on each and every soft reset. So now I have modified the code to look like this:

    static void lfclk_start(void)
    {
      nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED);
      nrf_clock_int_enable(NRF_CLOCK_INT_LF_STARTED_MASK);
      nrf_delay_us(21);
      nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
    }

    Inserting 21 us delay or more before starting the LF CLK all is good. Below 21 us doesn't work.

    Can anyone explain why this is necessary and what is going on here?

    I will try test on more devices to see if this is consistent across nRF52832 chips.

    Above "solution" doesn't change the behavior for Test Scenario 2, it still jumps synchronous with the WDOG retriggering, so maybe we are facing two different problems. 

    /Br Kim

Related