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?

Parents
  • One possibility is one or more slow or floating inputs start to cause feedthrough leakage which can be of the order of the current observed. To avoid this often the best course is to drive all unused io pins as output low (this has no significant effect on power consumption). Worth checking other pins (such as analogue inputs) for levels which may lie on the threshold around VDD/2 when the SAADC is disabled. I have seen this effect hold for periods of time when the pin voltage rises slowly to the tiny window which causes feedthrough from internal VDD to internal GND which loads slightly the battery voltage and the pin voltage then stops rising and stays in the problem window.

    Description of feedthrough mechanism scba004e.pdf

    Maybe post a pdf of the schematic for review

  • So, it looks like there are no unused gpio. 

    Here are things we have tried:

    - reset all gpio to input / no pull on startup before configuring for actual use (didn't fix)

    - printed out any gpio config / states changes in a thread to see if the current draw corresponds to a gpio change (no changed detected)

    Do you have any suggestions for detecting what peripheral states might have changed that might be effecting this current draw jump?

  • Probing the io pins with a 'scope would be worth doing, though if there is no 'scope available simply touching each io pin connection with a sharp sewing needle held in a bare hand would indicate any pin voltage issues by a corresponding change in observed current. Your comment about unexpected pullup or pulldown or an input held in an unexpected state with pullup/down enabled would give somewhere close to the observed jump assuming 3V and 13k internal resistance.

    If not already doing so, adding timer overflow interrupt processing might catch an unexpected timer issue. If not already doing so, add an io pin toggle on sleep/wake to verify the mark:space ratio remains exactly as expected. Any io pin can be hijacked for that purpose provide it doesn't have a load - pushbutton input is ideal if no external pullup/down.

    What is the exact value VDD before and after the jump; is there a measurable difference? Are there any potential phantom power sources attached to io pins?

    A schematic is needed to provide more thoughts, either post here or email direct if the circuit is connfidential.

  • Hello,

    jthmp said:

    reset all gpio to input / no pull on startup before configuring for actual use (didn't fix)

    You shouldn't need this. By default, all pins are disconnected inputs, which is the state that draws the least amount of current. 

    I would try to remove one peripheral at the time (never enable it in the application) until the behavior goes away. That should help pinpointing where the issue is.

    Could it be other devices on your PCB that is drawing the current?

    Best regards,

    Edvin

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

Reply
  • 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
    }
    

Children
No Data
Related