nrf5340 System ON sleep current

Hi,

We are trying to optimize our sleep current on a product based on the nrf5340.  When the product is off, the nrf5340 needs to continue servicing a 1 second RTC interrupt to keep track of calendar time.

We've confirmed that the current draw from the battery is correct when completely powering down the micro in System Off mode.  However, in System ON mode, with the watchdog, RTC and SRAM enabled, we seeing about 10uA more current than expected.  If we power down sections of SRAM on the application core that are not used while the product is powered off, the current drops to the expected value.

The below code changes are required to reduce the product current consumption by 10uA.

NRF_VMC->RAM[0].POWER = 0x0001;
NRF_VMC->RAM[1].POWER = 0;
NRF_VMC->RAM[2].POWER = 0x8000;
NRF_VMC->RAM[3].POWER = 0xFFFF;
NRF_VMC->RAM[4].POWER = 0;
NRF_VMC->RAM[5].POWER = 0;
NRF_VMC->RAM[6].POWER = 0x8000;
NRF_VMC->RAM[7].POWER = 0;

Does SRAM consume this much current?

Thank you
Parents
  • Hi Kurt, 

    Our expert in supporting current consumption measurement is currently away and will be back in about 10 days.

    In the mean time could you please let us know what's the actual current consumption you measured ? 
    Also if you can send us your test code to take a look, that would be nice. I assume you are using nRF Connect SDK, could you tell the version ? 

    I don't have the measurement for nRF53 but on the nRF52, as far as I know, turning of 4kB block of RAM can reduce current consumption from 20nA to 40nA. 
    If you take a look at this case: Turning off unused RAM to get minimum power consumption. 

    I got about 1.6uA dropped when turned off most parts of the 256kB RAM of the nRF52840. In the case of nRF53 it's 512kB but 10uA seems to be quite high. 

Reply
  • Hi Kurt, 

    Our expert in supporting current consumption measurement is currently away and will be back in about 10 days.

    In the mean time could you please let us know what's the actual current consumption you measured ? 
    Also if you can send us your test code to take a look, that would be nice. I assume you are using nRF Connect SDK, could you tell the version ? 

    I don't have the measurement for nRF53 but on the nRF52, as far as I know, turning of 4kB block of RAM can reduce current consumption from 20nA to 40nA. 
    If you take a look at this case: Turning off unused RAM to get minimum power consumption. 

    I got about 1.6uA dropped when turned off most parts of the 256kB RAM of the nRF52840. In the case of nRF53 it's 512kB but 10uA seems to be quite high. 

Children
  • The current consumption dropped from 31 uA to 21 uA of which 18uA is powering external circuitry.  I have attached the routine which is putting the 5340 into low power mode and periodically waking up once a second to service calendar time.

    void iohdw_enter_backup_mode( void )
    {
       UINT8_T temp8;
       ERRCODE_T iodig_error;
    
       /* Disable QSPI */
       //NRF_CACHE->ENABLE = 0x00000000;
    
       nrf_qspi_xip_set(NRF_QSPI, false);
       nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_ACTIVATE);
       nrfx_qspi_uninit();
       NRF_QSPI->PSEL.SCK = 0x80000000;
       NRF_QSPI->PSEL.CSN = 0x80000000;
       NRF_QSPI->PSEL.IO0 = 0x80000000;
       NRF_QSPI->PSEL.IO1 = 0x80000000;
       NRF_QSPI->PSEL.IO2 = 0x80000000;
       NRF_QSPI->PSEL.IO3 = 0x80000000;
       NRF_QSPI->ENABLE = 0;
    
    
       iohdw_cpu_cache_disable( );
       iohdw_sys_clock_driver_deinit();
    
    
       //IOLCD_DISP_OFF_M();
    
       IOINTS_DISABLE_GLOBAL_INT_M();
    
       IODIG_CONFIG_BACKUP_POWERMODE_M( );
    
       /* Configure the IO Expander for button interrupts and set the io expander interrupt output signal to the MCU
        * as a GPIO wakeup source
        *
        * The IO Expander will generate an interrupt signal whenver an input pin changes state.  To avoid erroneous pin state
        * changes on the non-button port, configure all of those pins as outputs set to their default state
        *
        * */
       if( ( iodig_error = IOEXP_CONFIG_IO_M(IOCHAN_DIO_LCDRST_, IOEXP_PORT_CFG_INPUT, IOEXP_PUPD_NO_PULL, (IOEXP_DRIVE_STRENGTH_CFG_T)NULL) ) )
       {
       }
       else if( ( iodig_error = IOEXP_CONFIG_IO_M(IOCHAN_DIO_MFGEEPROMWP, IOEXP_PORT_CFG_INPUT, IOEXP_PUPD_NO_PULL, (IOEXP_DRIVE_STRENGTH_CFG_T)NULL) ) )
       {
       }
       else if( ( iodig_error = IOEXP_SET_DIG_OUT_M(IOCHAN_DIO_VOLTSEL, FALSE) ) )
       {
       }
       else if( ( iodig_error = IOEXP_CONFIG_IO_M(IOCHAN_DIO_VOLTSEL, IOEXP_PORT_CFG_OUTPUT, IOEXP_PUPD_NO_PULL, (IOEXP_DRIVE_STRENGTH_CFG_T)NULL) ) )
       {
       }
       else if( ( iodig_error = IOEXP_SET_DIG_OUT_M(IOCHAN_DIO_SFEBUFEN, FALSE) ) )
       {
       }
       else if( ( iodig_error = IOEXP_CONFIG_IO_M(IOCHAN_DIO_SFEBUFEN, IOEXP_PORT_CFG_OUTPUT, IOEXP_PUPD_NO_PULL, (IOEXP_DRIVE_STRENGTH_CFG_T)NULL) ) )
       {
       }
       else if( ( iodig_error = IOEXP_SET_DIG_OUT_M(IOCHAN_DIO_SFEPWREN_, TRUE) ) )
       {
       }
       else if( ( iodig_error = IOEXP_CONFIG_IO_M(IOCHAN_DIO_SFEPWREN_, IOEXP_PORT_CFG_OUTPUT, IOEXP_PUPD_NO_PULL, (IOEXP_DRIVE_STRENGTH_CFG_T)NULL) ) )
       {
       }
       else if( ( iodig_error = IOEXP_CONFIG_IO_M(IOCHAN_DIO_PMDET, IOEXP_PORT_CFG_INPUT, IOEXP_PUPD_PD_ENABLED, (IOEXP_DRIVE_STRENGTH_CFG_T)NULL) ) )
       {
       }
       else if( ( iodig_error = IOEXP_SET_DIG_OUT_M(IOCHAN_DIO_PMDETON, FALSE) ) )
       {
       }
       else if( ( iodig_error = IOEXP_CONFIG_IO_M(IOCHAN_DIO_PMDETON, IOEXP_PORT_CFG_OUTPUT, IOEXP_PUPD_NO_PULL, (IOEXP_DRIVE_STRENGTH_CFG_T)NULL) ) )
       {
       }
       else if( ( iodig_error = IOEXP_SET_DIG_OUT_M(IOCHAN_DIO_TACHCBLTSTEN, FALSE) ) )
       {
       }
       else if( ( iodig_error = IOEXP_CONFIG_IO_M(IOCHAN_DIO_TACHCBLTSTEN, IOEXP_PORT_CFG_OUTPUT, IOEXP_PUPD_NO_PULL, (IOEXP_DRIVE_STRENGTH_CFG_T)NULL) ) )
       {
       }
    
       /* Mask the IO Expander Pin Input Interrupts that are not needed in sleep mode*/
       IOEXP_WRITE_INT_PORTS_M(IOEXP_EXP_DEVICE_0_ID, 0x00, 0xFF);
    
       /* Read the input registers to clear the interrupt status */
       IOEXP_GET_DIG_IN_M(IOCHAN_DIO_KEY0_, &temp8);
       IOEXP_GET_DIG_IN_M(IOCHAN_DIO_LCDRST_, &temp8);
    
       /*Configure the gpio wakeup for the pin connected to the IO Expander interrupt signal*/
    
    
       /* Enable the Wakeup pin (which is powered by the backup domain) */
       iohdw_config_wakeup_pin( STATE_ENABLE );
    
       // Disable all IRQ interrupt enable masks
       NVIC->ICER[0] = 0xFFFFFFFF;
       NVIC->ICER[1] = 0xFFFFFFFF;
       NVIC->ICER[2] = 0xFFFFFFFF;
       NVIC->ICER[3] = 0xFFFFFFFF;
       NVIC->ICER[4] = 0xFFFFFFFF;
       NVIC->ICER[5] = 0xFFFFFFFF;
       NVIC->ICER[6] = 0xFFFFFFFF;
       NVIC->ICER[7] = 0xFFFFFFFF;
       __DSB();
       __ISB();
       // Clear all IRQ interrupt pending flags
       NVIC->ICPR[0] = 0xFFFFFFFF;
       NVIC->ICPR[1] = 0xFFFFFFFF;
       NVIC->ICPR[2] = 0xFFFFFFFF;
       NVIC->ICPR[3] = 0xFFFFFFFF;
       NVIC->ICPR[4] = 0xFFFFFFFF;
       NVIC->ICPR[5] = 0xFFFFFFFF;
       NVIC->ICPR[6] = 0xFFFFFFFF;
       NVIC->ICPR[7] = 0xFFFFFFFF;
       __DSB();
       __ISB();
       IODIG_SET_OUT_DIRECT_M(MODEL_D, FALSE);
    
       /* Turn off Vsyssw and deassert the model D selector signal*/
       IODIG_SET_OUT_DIRECT_M(VSYSSWEN_, TRUE);
    
       /* Delay to allow the power supply voltage to decay */
       IOTIMER_DELAY_USEC_M(5000);
    
    
       IOTIMER_DELAY_USEC_M(100000);
    
       /*Shutdown the network core and disable the IPC*/
    
       bt_disable();
    
       iohdw_network_core_reset_enable();
    
       /*Disable all peripherals that are used by the applicatoin*/
    
    
       iosci_deinit_port(IOSCI_UART_RS485);
       UART_RS485_ADDR->ENABLE = 0;
    
       iotimer_deinit_timer(TACHPULS_ADDR);
       TACHPULS_ADDR->TASKS_STOP = 1;
    
       iotimer_deinit_timer(FREERUN_USEC_TIMER_ADDR);
       NRF_TIMER0->TASKS_STOP = 1;
    
       /* Stop the PWM instances*/
       iotimer_deinit_timer(ADC_TIMER);
       ADC_TIMER->ENABLE = 0;
    
       iotimer_deinit_timer(BATCHGPWM_TIMER);
       BATCHGPWM_TIMER->ENABLE = 0;
       BATCHGPWM_TIMER->PSEL.OUT[0] = 0xFFFFFFFF;
       BATCHGPWM_TIMER->PSEL.OUT[1] = 0xFFFFFFFF;
       BATCHGPWM_TIMER->PSEL.OUT[2] = 0xFFFFFFFF;
       BATCHGPWM_TIMER->PSEL.OUT[3] = 0xFFFFFFFF;
    
       iotimer_deinit_timer(BKLEDPWM_TIMER);
       BKLEDPWM_TIMER->ENABLE = 0;
       BKLEDPWM_TIMER->PSEL.OUT[0] = 0xFFFFFFFF;
       BKLEDPWM_TIMER->PSEL.OUT[1] = 0xFFFFFFFF;
       BKLEDPWM_TIMER->PSEL.OUT[2] = 0xFFFFFFFF;
       BKLEDPWM_TIMER->PSEL.OUT[3] = 0xFFFFFFFF;
    
       /*Disable USB*/
       iousb_deinit();
       NRF_USBD->ENABLE = 0;
    
    
       /* Disable I2C */
       ioi2c_channel_deinit(IOI2C_EEPROM_CHANNEL);
       MFGEEPROM_I2C_ADDR->ENABLE = 0;
    
       /*Disable SPI*/
       iospi_deinit( IOSPI_SPIFLASH_CHANNEL );
       FLASH_SPI_ADDR->ENABLE = 0;
    
       iospi_deinit( IOSPI_LCDCONTROLLER_CHANNEL );
       LCDCONTROLLER_SPI_ADDR->ENABLE = 0;
    
       /*Disable the ADC*/
       ioadc_uninit();
    
       /* Clear out all DPPI Configurations */
       nrfx_dppi_free();
    
    
       for(UINT8_T i = 0; i < 5; i++){
          NRF_DPPIC->CHENCLR = 0xFFFFFFFF;
       }
    
       /* Uninitialize the GPIOTE peripheral */
       nrfx_gpiote_uninit();
       *((UINT32_T *)0x5000D50C) = 0x00000000;
       for(UINT8_T i = 0; i < 8; i++){
          NRF_GPIOTE->PUBLISH_IN[i] = 0x00000000;
          NRF_GPIOTE->SUBSCRIBE_CLR[i] = 0x00000000;
          NRF_GPIOTE->SUBSCRIBE_OUT[i] = 0x00000000;
          NRF_GPIOTE->SUBSCRIBE_SET[i] = 0x00000000;
          NRF_GPIOTE->CONFIG[i] = 0x00000000;
          NRF_GPIOTE->CONFIG[i] = 0x00000000;
       }
    
       NRF_GPIOTE->INTENCLR = 0x800000FF;
    
       /* HW Version >= 123 do not have the tach pulse input to the wake circuit populated.  Instead, the tach pulse
        * signal directly into the micro is used as the wake source.  See ECO #4835
       */
       if ( APGLOBALS_GET_HWREVISIONNUM_M() >= (IOHDW_HWREVISION_OFFSET + 123) )
       {
          /* The GPIOTE de-initialization disconnects the tach input buffer from the pin.  This needs to be reverted. */
          IOGPIO_CFG_PIN_M(TACHPULS_BIT, IOGPIO_PIN_DIR_INPUT, IOGPIO_PIN_INPUT_CONNECT, IOGPIO_PIN_PULL_NOPULL, IOGPIO_PIN_DRIVE_S0S1, IOGPIO_PIN_SENSE_NONE);
       }
    
       /* Uninitialize the RTC */
       uint32_t mask = NRF_RTC_INT_TICK_MASK     |
                       NRF_RTC_INT_OVERFLOW_MASK |
                       NRF_RTC_INT_COMPARE0_MASK |
                       NRF_RTC_INT_COMPARE1_MASK |
                       NRF_RTC_INT_COMPARE2_MASK |
                       NRF_RTC_INT_COMPARE3_MASK;
       nrf_rtc_task_trigger(NRF_RTC1, NRF_RTC_TASK_STOP);
       nrf_rtc_event_disable(NRF_RTC1, mask);
       nrf_rtc_int_disable(NRF_RTC1, mask);
    
    
    
       // Running quick test to determine peripheral circuitry current consumption.
       NRF_POWER->TASKS_CONSTLAT = 0x00000000;
       NRF_POWER->EVENTS_POFWARN = 0x00000000;
       NRF_POWER->EVENTS_SLEEPENTER = 0x00000000;
       NRF_POWER->EVENTS_SLEEPEXIT = 0x00000000;
       NRF_POWER->PUBLISH_POFWARN = 0x00000000;
       NRF_POWER->PUBLISH_SLEEPENTER = 0x00000000;
       NRF_POWER->PUBLISH_SLEEPEXIT = 0x00000000;
       NRF_POWER->INTENCLR = 0x00000064;
       NRF_POWER->GPREGRET[0] = 0x00000000;
       NRF_POWER->GPREGRET[1] = 0x00000000;
    
       NRF_CLOCK->HFCLKSRC = 0x00000000;
       NRF_CLOCK->HFCLK192MSRC = 0x00000000;
    
    
    
       /* Disable Instruction and Data Caching */
       NRF_CACHE->ENABLE = 0x00000000;
    
       /* Disable the external crystal as the HF oscillator source */
       NRF_OSCILLATORS->XOSC32MCAPS = 0x00000000;
       NRF_OSCILLATORS->XOSC32KI.BYPASS = 0x00000000;
       NRF_OSCILLATORS->XOSC32KI.INTCAP = 0x00000000;
    
       /* Enable System ON Sleep mode in its lowest power state */
       NRF_POWER->TASKS_LOWPWR = 1;
    
       /* Disable the internal DC-DC regulators */
       NRF_REGULATORS->VREGMAIN.DCDCEN = 0x00000000;
       NRF_REGULATORS->VREGRADIO.DCDCEN = 0x00000000;
       NRF_REGULATORS->VREGH.DCDCEN = 0x00000000;
       NRF_REGULATORS->POFCON = 0x00000000;
    
          /* Disable SysTick */
       SysTick->CTRL &= ~(1 << SysTick_CTRL_ENABLE_Pos);
    
       __DSB();
    
       SCB->SCR = 0x00000000;
    
       // Disable all IRQ interrupt enable masks
       NVIC->ICER[0] = 0xFFFFFFFF;
       NVIC->ICER[1] = 0xFFFFFFFF;
       NVIC->ICER[2] = 0xFFFFFFFF;
       NVIC->ICER[3] = 0xFFFFFFFF;
       NVIC->ICER[4] = 0xFFFFFFFF;
       NVIC->ICER[5] = 0xFFFFFFFF;
       NVIC->ICER[6] = 0xFFFFFFFF;
       NVIC->ICER[7] = 0xFFFFFFFF;
       __DSB();
       __ISB();
       // Clear all IRQ interrupt pending flags
       NVIC->ICPR[0] = 0xFFFFFFFF;
       NVIC->ICPR[1] = 0xFFFFFFFF;
       NVIC->ICPR[2] = 0xFFFFFFFF;
       NVIC->ICPR[3] = 0xFFFFFFFF;
       NVIC->ICPR[4] = 0xFFFFFFFF;
       NVIC->ICPR[5] = 0xFFFFFFFF;
       NVIC->ICPR[6] = 0xFFFFFFFF;
       NVIC->ICPR[7] = 0xFFFFFFFF;
       __DSB();
       __ISB();
    
       //nrf_clock_lf_src_set(NRF_CLOCK, NRF_CLOCK_LFCLK_RC);
       /* Turn off the High Frequency Clocks */
       nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLK);
       nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLK192M);
       nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLKAUDIO);
       /* Clear out the High Frequency Clock divider.  Even if the clock is stopped, a divider other than 4 will result in higher
        * power consumption in sleep mode*/
       nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4);
    
     //  nrf_regulators_system_off(NRF_REGULATORS);
    
       /* Set Up the GPIO Wake Sources */
       iodig_config_wake_sources_lpwr_powermode( IODIG_POWERMODE_PORTPIN_ACTIVE );
    
       //nrf_regulators_system_off(NRF_REGULATORS);
    
    
       /* Configure the NFC Field Detected Event as a wake up sourece */
       iohdw_cfg_nfc_interrupt();
    
       /* Set up the RTC to wake up at 1 Hz to maintain Date and Time.
        * Interrupts are needed when setting up the RTC for sleep mode
        * */
       NVIC_EnableIRQ(RTC_CLOCK_IRQN);
       IOINTS_ENABLE_GLOBAL_INT_M();
       iortc_cfg_sleep_mode_functionality();
    
       IOINTS_DISABLE_GLOBAL_INT_M();
    
    
    
       /* Power down SRAM to reduce battery current at 3v by 10uA */
       NRF_VMC->RAM[0].POWER = 0x0001;
       NRF_VMC->RAM[1].POWER = 0;
       NRF_VMC->RAM[2].POWER = 0x8000;
       NRF_VMC->RAM[3].POWER = 0xFFFF;
       NRF_VMC->RAM[4].POWER = 0;
       NRF_VMC->RAM[5].POWER = 0;
       NRF_VMC->RAM[6].POWER = 0x8000;
       NRF_VMC->RAM[7].POWER = 0;
    
       /* Go To Sleep */
       while(1)
       {
          __SEV();
          __WFI();
          __WFI();
          TKHDW_DEBUG1_TOG();
          /*If the USB Detect, RS485 Detect, and Push-button detect have not triggered but the RTC has, just service the RTC
            and go back to sleep
          */
    
          /*First, check for the RTC compare event.  If that is set, service the RTC before potentially resetting due to other wake sources being
           * active*/
          IOHDW_PET_WDOG_M();
    
          if(iortc_check_peripheral_event( IORTC_WAKE_SOURCE_COMPARE_EVENT ) )
          {
             iortclock_capture_on_sleep_wake();
             NVIC_ClearPendingIRQ(RTC_CLOCK_IRQN);
             iortc_clear_peripheral_event( IORTC_WAKE_SOURCE_COMPARE_EVENT );
          }
    
          /* Make sure all of the other RTC events are cleared to avoid spurrious interrupts */
          if(iortc_check_peripheral_event(NRF_RTC_EVENT_COMPARE_1)){
             iortc_clear_peripheral_event( NRF_RTC_EVENT_COMPARE_1 );
          }
          if(iortc_check_peripheral_event(NRF_RTC_EVENT_COMPARE_2)){
             iortc_clear_peripheral_event( NRF_RTC_EVENT_COMPARE_2 );
          }
          if(iortc_check_peripheral_event(NRF_RTC_EVENT_COMPARE_3)){
             iortc_clear_peripheral_event( NRF_RTC_EVENT_COMPARE_3 );
          }
          if(iortc_check_peripheral_event(NRF_RTC_EVENT_TICK)){
             iortc_clear_peripheral_event( NRF_RTC_EVENT_TICK );
          }
          if(iortc_check_peripheral_event(NRF_RTC_EVENT_OVERFLOW)){
             iortc_clear_peripheral_event( NRF_RTC_EVENT_OVERFLOW );
          }
    
          /*If NFC Field Detected, reset and boot into operational mode */
          if(NRF_NFCT->EVENTS_FIELDDETECTED == 1)
          {
             __ASM("nop");
             break;
          }
          /* If it was a GPIOTE Port Event, reset and boot into operational mode....this covers USB Detect, RS485, Push-Button, and Tach*/
          else if(NRF_GPIOTE->EVENTS_PORT == 1)
          {
             __ASM("nop");
             break;
          }
          /* The GPIO Latch registers should be looked at.  If any of the latch bits are set and the EVENTS_PORT event is not triggered, it is indicating
           * that the Latch bits were set prior to enabling the GPIOTE Port event and interrupt.  In this scenario, none of the button push, USB, or RS-485
           * wakeups will work properly.  
           */
          else if( (NRF_P0->LATCH !=0) || (NRF_P1->LATCH != 0) )
          {
             __ASM("nop");
             break;
          }
       }
    
       /* Turn off the watchdog timer */
       iohdw_wdog_stop();
    
       /* SRAM needs to be re-enabled before executing system reset.  NVIC reset does not appear to re-enable SRAM */
       NRF_VMC->RAM[0].POWER = 0xFFFF;
       NRF_VMC->RAM[1].POWER = 0xFFFF;
       NRF_VMC->RAM[2].POWER = 0xFFFF;
       NRF_VMC->RAM[3].POWER = 0xFFFF;
       NRF_VMC->RAM[4].POWER = 0xFFFF;
       NRF_VMC->RAM[5].POWER = 0xFFFF;
       NRF_VMC->RAM[6].POWER = 0xFFFF;
       NRF_VMC->RAM[7].POWER = 0xFFFF;
    
    
       /* At this point, the unit has been awakened, reset the unit so that it boots into normal mode */
       NVIC_SystemReset();
    
       return;
    
            // Should never reach this line - device will jump to backup vector on exit from background mode.
    }
    .

  • Hi Kurt, 

    Do you have a Dev Kit to do cross check if the current consumption on the DK is the same. 

    I did a quick test with the blinky example (NCS v2.4.0) which use RTC and I can see that if I don't turn off RAM it will be around 2.8 uA sleep current. 
    And if I turn off RAM retention using

    NRF_VMC->RAM[0].POWER = 0x00FF;
       NRF_VMC->RAM[1].POWER = 0;
       NRF_VMC->RAM[2].POWER = 0;
       NRF_VMC->RAM[3].POWER = 0;
       NRF_VMC->RAM[4].POWER = 0;
       NRF_VMC->RAM[5].POWER = 0;
       NRF_VMC->RAM[6].POWER = 0;
       NRF_VMC->RAM[7].POWER = 0;

    I can see the current consumption dropped down to 1.4uA which matched with the calculation in my last reply. 

    blinky_ram.zip

  • Hi Hung,

    Are you running this example on the nrf5340 dev kit?

  • Hi Kurt, 
    Yes, it was tested on nRF5340 devkit. 

Related