Current draw jumps ~187 uA after 10 min for no apparent reason.

We are using the legacy 17.1 nrf sdk with the nrf52840 MCU in tickless idle mode and notice that after about 10.5 minutes the current draw jumps from ~90uA to ~277 uA.

There is no obvious change in our firmware behavior and no unusual activity when the jump happens (that we can see so far, but still looking).

The system is just in idle mode the whole time.

In other versions of our firmware the time can be anywhere from 25.5 minutes to 35 minutes depending on the firmware version. But it's always a consistent time (ex: always 35 min).

We suspect it's a gpio being turned on (like a gpio input with a pullup) but so far we haven't found the culprit. 

We are going to apply errata 246 fix:
https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_246.html

but this should only save 40 uA.

What would cause a jump like this?

  • Following on from Edvin's suggestion, which can take a lot of time to test when the fault is intermittent, you could instead simply power down any peripheral that you disable or are not using, provided you power the peripheral back up prior to initialising. I use this for reliability, and although not fully documented in the data sheets some of the information is published in Nordic Devzone responses.

    Perhaps choose appropriate peripherals from this list, copied from one of my projects:

    // Calculate index for Power Control field
    #define POWER_INDEX (0xFFC/sizeof(uint32_t))
    STATIC_ASSERT( (NRF_SPIM0_BASE+0xFFC) == 0x40003FFC, "POWER_INDEX calculation does not match compiler");
    
    // Comment out peripherals actually in use by the application
    void PowerOnPeripherals(uint32_t PowerBit)
    {
       uint32_t Setting = 0;  // 0 is power off
       if (PowerBit > 0) Setting = 1;
    
       // Power Enables - Sorted by Peripheral address
    // *(volatile uint32_t *)( NRF_CLOCK_BASE+0xFFC) = Setting; //  CLOCK Power off    shared address, no register
    // *(volatile uint32_t *)( NRF_POWER_BASE+0xFFC) = Setting; //  POWER Power off    shared address, no register
       *(volatile uint32_t *)( NRF_RADIO_BASE+0xFFC) = Setting; //  RADIO Power Enable
       *(volatile uint32_t *)(NRF_UARTE0_BASE+0xFFC) = Setting; //  UARTE Power Enable
       *(volatile uint32_t *)( NRF_SPIM0_BASE+0xFFC) = Setting; //  SPIM0 Power Enable shared address
    // *(volatile uint32_t *)( NRF_SPIS0_BASE+0xFFC) = Setting; //  SPIS0 Power Enable shared address
    // *(volatile uint32_t *)( NRF_TWIM0_BASE+0xFFC) = Setting; //  TWIM0 Power Enable shared address
    // *(volatile uint32_t *)( NRF_TWIS0_BASE+0xFFC) = Setting; //  TWIS0 Power Enable shared address
       *(volatile uint32_t *)( NRF_SPIM1_BASE+0xFFC) = Setting; //  SPIM1 Power Enable shared address
    // *(volatile uint32_t *)( NRF_SPIS1_BASE+0xFFC) = Setting; //  SPIS1 Power Enable shared address
    // *(volatile uint32_t *)( NRF_TWIM1_BASE+0xFFC) = Setting; //  TWIM1 Power Enable shared address
    // *(volatile uint32_t *)( NRF_TWIS1_BASE+0xFFC) = Setting; //  TWIS1 Power Enable shared address
       *(volatile uint32_t *)(  NRF_NFCT_BASE+0xFFC) = Setting; //   NFCT Power Enable
       *(volatile uint32_t *)(NRF_GPIOTE_BASE+0xFFC) = Setting; // GPIOTE Power Enable
       *(volatile uint32_t *)( NRF_SAADC_BASE+0xFFC) = Setting; //  SAADC Power Enable
       *(volatile uint32_t *)(NRF_TIMER0_BASE+0xFFC) = Setting; // TIMER0 Power Enable
       *(volatile uint32_t *)(NRF_TIMER1_BASE+0xFFC) = Setting; // TIMER1 Power Enable
       *(volatile uint32_t *)(NRF_TIMER2_BASE+0xFFC) = Setting; // TIMER2 Power Enable
       *(volatile uint32_t *)(  NRF_RTC0_BASE+0xFFC) = Setting; //   RTC0 Power Enable
       *(volatile uint32_t *)(  NRF_TEMP_BASE+0xFFC) = Setting; //   TEMP Power Enable
       *(volatile uint32_t *)(   NRF_RNG_BASE+0xFFC) = Setting; //    RNG Power Enable
       *(volatile uint32_t *)(   NRF_ECB_BASE+0xFFC) = Setting; //    ECB Power Enable
       *(volatile uint32_t *)(   NRF_AAR_BASE+0xFFC) = Setting; //    AAR Power Enable
       *(volatile uint32_t *)(   NRF_CCM_BASE+0xFFC) = Setting; //    CCM Power Enable
       *(volatile uint32_t *)(   NRF_WDT_BASE+0xFFC) = Setting; //    WDT Power Enable
       *(volatile uint32_t *)(  NRF_RTC1_BASE+0xFFC) = Setting; //   RTC1 Power Enable
       *(volatile uint32_t *)(  NRF_QDEC_BASE+0xFFC) = Setting; //   QDEC Power Enable
       *(volatile uint32_t *)(  NRF_COMP_BASE+0xFFC) = Setting; //   COMP Power Enable
       *(volatile uint32_t *)(NRF_LPCOMP_BASE+0xFFC) = Setting; // LPCOMP Power Enable
       *(volatile uint32_t *)(  NRF_EGU0_BASE+0xFFC) = Setting; //   EGU0 Power Enable
       *(volatile uint32_t *)(  NRF_EGU1_BASE+0xFFC) = Setting; //   EGU1 Power Enable
       *(volatile uint32_t *)(  NRF_EGU2_BASE+0xFFC) = Setting; //   EGU2 Power Enable
       *(volatile uint32_t *)(  NRF_EGU3_BASE+0xFFC) = Setting; //   EGU3 Power Enable
       *(volatile uint32_t *)(  NRF_EGU4_BASE+0xFFC) = Setting; //   EGU4 Power Enable
       *(volatile uint32_t *)(  NRF_EGU5_BASE+0xFFC) = Setting; //   EGU5 Power Enable
       *(volatile uint32_t *)(NRF_TIMER3_BASE+0xFFC) = Setting; // TIMER3 Power Enable
       *(volatile uint32_t *)(NRF_TIMER4_BASE+0xFFC) = Setting; // TIMER4 Power Enable
       *(volatile uint32_t *)(  NRF_PWM0_BASE+0xFFC) = Setting; //   PWM0 Power Enable
       *(volatile uint32_t *)(   NRF_PDM_BASE+0xFFC) = Setting; //    PDM Power Enable
       *(volatile uint32_t *)(   NRF_MWU_BASE+0xFFC) = Setting; //    MWU Power Enable
       *(volatile uint32_t *)(  NRF_PWM1_BASE+0xFFC) = Setting; //   PWM1 Power Enable
       *(volatile uint32_t *)(  NRF_PWM2_BASE+0xFFC) = Setting; //   PWM2 Power Enable
       *(volatile uint32_t *)( NRF_SPIM2_BASE+0xFFC) = Setting; //  SPIM2 Power Enable shared address
    // *(volatile uint32_t *)( NRF_SPIS2_BASE+0xFFC) = Setting; //  SPIS2 Power Enable shared address
       *(volatile uint32_t *)(  NRF_RTC2_BASE+0xFFC) = Setting; //   RTC2 Power Enable
       *(volatile uint32_t *)(   NRF_I2S_BASE+0xFFC) = Setting; //    I2S Power Enable
    #if defined(NRF52833_XXAA) || defined(NRF52840_XXAA) //|| defined(TESTING_ON_nRF52833DK)
       *(volatile uint32_t *)(  NRF_USBD_BASE+0xFFC) = Setting; //   USBD Power Enable
       *(volatile uint32_t *)(NRF_UARTE1_BASE+0xFFC) = Setting; // UARTE1 Power Enable
       *(volatile uint32_t *)(  NRF_PWM3_BASE+0xFFC) = Setting; //   PWM3 Power Enable
       *(volatile uint32_t *)( NRF_SPIM3_BASE+0xFFC) = Setting; //  SPIM3 Power Enable
    #endif
    }
    

  • Hi Edvin, 
    Yes, that's a good idea. We will try that.

    It's possible that it's some other IC but so far we haven't been able to find any indication that it is. The whole system is just in idle mode and periodically wakes up to service a task (like logging).

    One note, the extra current is the same amount of extra current that we see when enabling a gpio input with a pullup and then applying 0V to the input. About 180uA. 
    So it definitely seems like it could be a gpio. But like a said, we added code to periodically check if any of the 47 gpio on the board had a state change when the issue occurs and we don't see any.

  • Hi hmoleworth,

    Those are suggestions we will try out, thanks!
    Our mcu runs on 1.8V VDD. We'll test out the VDD jump.

    As a note: we are using an Otti 3 Power profiler, (DC energy analyzer and power supply) to measure the current. 

  • 1.8V VDD and internal pullup of typically 14k is about 128uA when driving input to 0v with pullup enabled; do you really see an extra 180uA? As an aside, I would recommend a secondary measurement - with the Otii 3 disconnected, ie not used - using a battery and (say) a PPK-II just to confirm findings.

    Perhaps also review Errata 78, 87, 122, 194, 195, 210, 241 in addition to 246. A better way to handle 246 is to place peripheral buffers in a separate RAM AHB bus area away from stack and other CPU variables.

    One other thought; if using (say) SPIM with the pullup enabled on MOSI the last bit transmitted may be usually '1' but maybe every 10 minutes that last bit is a '0' and if the SPIM is not disabled that leaves current flowing through the pullup (if there is a pullup set). The same type of issue applies with MISO; if using a pullup - usually the case for MISO - and the attached device happens to leave MISO at '0' on the last byte transmitted the same applies. Some designs power down the external device, though it would seem odd to do that after 10 minutes; however if the external device were powered down the MISO pullup would have to be disabled as simply disabling SPIM does not change the pullup setting on the MISO io pin and the MISO pullup would be phantom-powering the external device via that device's internal schottky protection diode.

  • Hi hmolesworth,
    Thank you for those suggestions. When we enter idle mode we disable our peripherals (like i2c, spi...etc) before hand. For spi we wait till spi is not busy and then call 

    - nrfx_qspi_uninit before going to idle

    and then right after wakeup we call 

    - nrfx_qspi_init

    we do not manually configure any gpio. So, you are saying we should configure the gpio before and after idle in the way you describe? 

Related