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.

  • I think part of the solution is in this quote from an other ticket:

    "

    Also remember to disable TWI peripheral before sleep. And mind the PAN89: "TWI: Static 400 µA current while using GPIOTE"

    "

    I am using twi communication with the ICM-20948.

    I have play with the ESB _low power exemple and fine that to get low power consumption in the sleep mode, I had to disable gpio.

    Note that my external board does not have any LED.

    I will work on that tomorrow.

  • OK , I have done more testing.

    I have strip done my program o the minimum until I get low power value and add back some component.

    First of all, ==>   I could not get low power  with  the JLinkRTTviewer connected.   

    This is the minimize code used for testing, I have not put the void routine but they are quite standard.

    int main(void)
    {
       
        ret_code_t err_code;
        uint16_t battery_value;
        
        // Initialize.
       APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
       NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        
        APP_ERROR_CHECK(esb_init());
        clocks_start();    /// for ESB
    
    
       NRF_LOG_RAW_INFO("\n**********  ICM20948 start  **********\n\r");
    
        lfclk_init();  //for timestamp + app_timer
    
       //  rtc_config(); // sl   ---- problem
       // gpiote_init();   // init interrupt  // problem
    
        timers_init();    //  app_timer  problem
    
      
      
       Adc12bitPolledInitialise();
       twi_init();
       
    
      
      while(1)
        {   // main loop to fill later
             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;
               }
    
    
    
    
               app_timer_start(m_timer, APP_TIMER_TICKS(1000), NULL);  //  timer one shoot  - events will wake up the sensor 
              // nrf_delay_ms(10);
    
           //    while (true)
            {
              //  if (NRF_LOG_PROCESS() == false)
                {// 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();
            
                 }  }
        
    
            
        } // while(1)
    } // main
    

    With the code above, I measure about 2.1 mV across the 10 ohm resistor, so about 210  µA.  Value was the same without twi_init.  Unfortunately, this include the current going to the ICM-20948.  I will have to separate both the circuit alimentation for individual measurement.

    RTC_config (tick routine generation) and gpiote interfere with sleep mode.  I will have to disable those before entering sleep.

    Now I have this question:

    The routine below for fine  as part of the main loop but  if I enable the line < while (true) > like in SDK16  exemple then the timer _event  won't wakeup  the board.  I don't understand why.

     

        app_timer_start(m_timer, APP_TIMER_TICKS(1000), NULL);  //  timer one shoot  - events will wake up the sensor 
    // while (true)
    {// 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(); }

  • I don't understand your main() function. You have two nested while loops? And you realize that you will start the m_timer app_timer many (!) times? You have other events that will wake you up, other than the timeout itself. Perhaps you can try to set the timer to a repeated timer, and start it once, instead of what it looks like you are trying to do here.

    I think what you imagine will happen here is:

    start timer -> go to sleep -> timer times out -> do something -> start timer again.

    what will actually happen: 

    start timer -> go to sleep -> start timer event fires (not timeout) -> start timer again -> go to sleep -> start timer event fires -> start timer again.

    So if you think you are sleeping for 1 second here, that is not the case.

    Try this:

    Start repeated timer-> sleep. Then use timer events to set flags that you can handle in main, like it looks like you are doing, but the timeout event is not the only thing that will wake up the CPU.

  • Thnaks Edwin,

    I will work on that.

    What I am trying to do is

    main loop:

    while (1):

    do something,

    if no data acquisition  - >  start one shot 1sec timer -> wait for timer start event -> go to sleep   -> timer times out -> go back to do something 

    while(true)

    if (timer_event ) {send_battery_level}

    if (DMP_acq >= 0)

       {  .....           }

    else if (DMP_acq == 0)
    { app_timer_start(m_timer, APP_TIMER_TICKS(1000), NULL); // timer one shoot - events will wake up the sensor

    (wait to timer start event :)


    // 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();


    }

    }

    I have tried to catch the timer start_event before going to sleep but 

       while (timer_event == false); // did not work  , it keep looping

       tried  nrf_delay_ms(X); // was not needed

    Finally, sleep mode was working for 1 sec without any of those line.  I can see a very small burst, maybe 1 ms burst of power (not measured) when the processor wake up to send battery level, and then it goes back to sleep.

     

    Thanks for your help.  I am almost there.  I will work on disabling RTC and GPIOTE before sleep ans see if it work.

    I will report later.

  • Done more testing today :

    basically this is the section of code that I use inside the main section to goto sleep :

    if (DMP_acq == 0)    
               {  
                   nrfx_gpiote_in_event_disable(MPU_INT_PIN);
                 //  twi_disable();
                   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();
             }

    No event was observed after app_timer_start. Sleep mode was engage for 1 sec.


    With that code, gpiote off, Got 2.0 mV across the 10 ohm resistor => so 200 µA. If I disable twi be calling nrfx_twi_disable(&m_twi_instance);
    I don't gain anything more.

    I remove reference to RTC since it was not needed.

    The ICM-20946 board have not separate alimentation, so the curent measuremen for the nrf52 only. It use 7.5 mA when sampling data at 40 Hz.

    200 µA is acceptable and much better than before but can I got further ?

    Anything else I can try?


Related