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

nrf52832 sleep mode else if (DMP_acq == 0) { app_timer_start(m_timer, APP_TIMER_TICKS(1000), NULL); // timer one shoot - events will wake up the sensor // Put the CPU to sleep until an interrupt is detected.

Hi,

I have develop an application using the nrf52832 combined wit the ICM20948 sensor.  

The application use ESB communication between peripheral and central.  I have solder 10 ohm resistor between the nrf52 board  and the nominal 3V , and another one between the ICM20948 board and  the 3 V supply.

When the ICM is not in used,  I want to put the nrf52 in sleep mode for one second.  The nrf52 then wake up and send the battery level to the central to keep communication going and also pickup new instruction from the returning acknowledge.  This is the portion of the code use for the standby :

    else if (DMP_acq == 0)    
           {  app_timer_start(m_timer, APP_TIMER_TICKS(1000), NULL);  //  timer one shoot  - events will wake up the sensor 
          
            // Put the CPU to sleep until an interrupt is detected.   (data or timer)                    
            // Make sure any pending events are cleared
            __SEV();
            __WFE();
            // Enter System ON sleep mode
            __WFE();
               
       
            } 

When in standby, I measure about 47 mV across the nrf52 10 ohm resistor. That would give about 4.7 mA. The ICM chip is almost at 0 mA.     Number goes up approx to 7.5mA for the nrf52 board and 5 mA for the ICM board (12.5 mA) when sampling values at 56 Hz.  

I suspect that I am doing something wrong. I would expect low uA value when the nrf52 is in standby, no sampling going on, using the above code .

I have seen a post with the following calculation:

System ON, no RAM retention + RTC + LFRC = 1.2uA + 0.1uA + 0.6uA = 1.9uA

I have RTC and LFRC, working for timestamp and +,  nrf_clock for ESB


 What am I doing wrong ?

(Note : Not sure what is no ram retention, should I clear the memory before going to sleep ?)

Thanks you in advance for your help.  It's truly appreciated.

  • Can you please try to toggle a pin before __WFE to make sure it is only called once every second? Or you can print some message. I am still worried about the sleep logic in your application.

    Have you tested your application without SPI? Even if the application doesn't do much, it is worth testing and comparing without the peripherals, to see if the current consumption is as expected when you don't use the peripherals. If you want to save as much power as possible, you should uninit them when you are not using them. So if you are the SPI master, you may uninitialize the SPI, and disconnect the GPIOs. Some drivers have an uninit function, but it is not always they reset the pins properly. To reset a pin you can use nrf_drv_gpiote_out_uninit(), which will put the pin in disconnected - input mode, which doesn't draw any current.

    BR,

    Edvin

  • HI Edvin,

    I went back to this power consumption problem.  

    I have disable almost everything and found out that the HFCLK used for ESB is the main culprit.

    nrf_drv_clock_hfclk_release();  // don't do anything 

    but NRF_CLOCK->TASKS_HFCLKSTOP = 1; // drop the power to few uA

    the problem now is to restart the clock.  

    Calling the init funtion dont work 

    void clocks_start( void )
    {
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_HFCLKSTART = 1;
        while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    }

    What is the proper procedure  to stop and restart the HFCLK ?

  • Edvin said:
    Can you please try to toggle a pin before __WFE to make sure it is only called once every second? Or you can print some message. I am still worried about the sleep logic in your application.

    Are you still doing this?

        else if (DMP_acq == 0)    
               {  app_timer_start(m_timer, APP_TIMER_TICKS(1000), NULL);  //  timer one shoot  - events will wake up the sensor 
              
                // Put the CPU to sleep until an interrupt is detected.   (data or timer)                    
                // Make sure any pending events are cleared
                __SEV();
                __WFE();
                // Enter System ON sleep mode
                __WFE();
                   
           
                } 

    That will not work. 

    Your main() functions while loop should look like this:

            while (true)
            {
                custom_functions(); // If you need any
                __SEV();
                __WFE();
                // Enter System ON sleep mode
                __WFE();
            }

  • I have tried multiple time using a repeated timer  and values are absolutely the same.

    This is a strip down version of the program for testing purposed, using a 1 sec repeated timer.   Power consumption goes up with the ESB clock start.

    int main(void)
    {
        int rc = 0;
        ret_code_t err_code;
        uint16_t battery_value;
        uint8_t i;
    
      
        uint8_t whoami = 0xFF;
        uint8_t reg_data;
        
        uint8_t cr;
        bool start_sensor = false;
    
         float magbias[3] = {0};
         int mgbias[3] = {0};
        // float gyrobias[3] = {0};
        //int magbias[3] = {0};
    
       
        // Initialize.
       // APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
      //  NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        clocks_start();    /// from ESB
        APP_ERROR_CHECK(esb_init());
    
    
        NRF_LOG_RAW_INFO("\n**********  ICM20948 start  **********\n\r");
    
        lfclk_init();  // for timestamp
                               // rtc_config(); // sl not used
       
        gpiote_init();   // init interrupt
    
        
        Adc12bitPolledInitialise();     ///  battery_helper.c
    
      
        
     
      err_code = nrf_pwr_mgmt_init();
      APP_ERROR_CHECK(err_code);
      timers_init();    //  ========================  init timer
     
     
    
    
      
      while(1)                 //      ****************  main loop *****************
        {   
             if  (timer_event)
              { 
                tx_payload.noack = false; 
                NRF_LOG_INFO("timer event");
                timer_event = false;
                //  battery_timer = true;
    
             //if (battery_timer)
               {  battery_value = GetBatteryVoltage();
                  sprintf(ESBstring, "Bat: %d",battery_value); 
                  NRF_LOG_DEBUG("%s ",ESBstring)
                  ESBsend();
                  battery_timer = false;
                 // next_battery_read_ms = mytimestamp + BATTERY_READ_MS;
               }
            }// if timer event
    
    
            
    
    
              
               
                 nrfx_gpiote_in_event_disable(MPU_INT_PIN); // helping  7 mv instead of 2 if disable 
                  
    
    
                 //  twi_disable(); // 1.9 mv  not helping 
                 //  nrf_esb_disable();  // 1.9 mv  not helping 
                 // NRF_ESB_SYS_TIMER->TASKS_SHUTDOWN = 1;  //  1.9 mv  not helping 
             //    NRF_CLOCK->TASKS_HFCLKSTOP = 1;
    
    
                //    nrf_drv_clock_hfclk_release();  // 78 mv  - worst
                 //  nrf_drv_clock_lfclk_release();  // 78 mv  - worst
                  
                 //nrf_saadc_disable();  // already disable   wont compile
    
    
    
               //    app_timer_start(m_timer, APP_TIMER_TICKS(1000), NULL);  //  timer one shoot  - events will wake up the sensor            
                 //  NRF_LOG_INFO("sleep start \n");    
                      
                     // Use directly __WFE and __SEV macros since the SoftDevice is not available.
    
                     // Wait for event.
                      __WFE();
    
                      // Clear Event Register.
                      __SEV();
                      __WFE();
                  
    
               //NRF_LOG_INFO("sleep stop ");        
               // NRF_LOG_FLUSH();
             
    
    
              nrfx_gpiote_in_event_enable(MPU_INT_PIN, true);
           // nrfx_gpiote_in_event_disable();
               //nrfx_gpiote_init();
              // nrf_esb_start_rx();
            
        } // while(1)
    } // main

  • SL06 said:
    Power consumption goes up with the ESB clock start.

     But you said that "NRF_CLOCK->TASKS_HFCLKSTOP = 1; // drop the power to few µA"?

    So the issue is that nrf_drv_clock_release does not do the same, right?

    I don't know if you have looked at the implementation ofnrf_drv_clock_hfclk_release(), but depending on what SDK version you are using, it should look something like this:

    void nrf_drv_clock_hfclk_release(void)
    {
        ASSERT(m_clock_cb.module_initialized);
        ASSERT(m_clock_cb.hfclk_requests > 0);
    
        CRITICAL_REGION_ENTER();
        --(m_clock_cb.hfclk_requests);
        if (m_clock_cb.hfclk_requests == 0)
        {
            hfclk_stop();
        }
        CRITICAL_REGION_EXIT();
    }

    So if you have requested the clock more times than you have released it, then it will not stop the clock. Does any other part of your project request the hfclk?

    BR,
    Edvin

Related