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.

Parents
  • Sorry for the title.   I have search how to edit the title and the text but did not find how...

  • Hello,

     

    SL06 said:
    Sorry for the title.   I have search how to edit the title and the text but did not find how...

     No worries. I don't think it is possible.

    Where do you set DMP_acq = 1?

    First of all, What do you use to measure the voltage over the serial resistor? If you use a multimeter that may be quite inaccurate, because the current consumption is not constant. BLE will typically cause very short current spikes that are quite tall. Multimeters hande these spikes very differently. 

    As you can see in the attached screenshot from the Power Profiler Kit, using nRF Connect for Desktop -> Power Profiler:

    You can see that the spikes are at ~10mA, but the average current consumption for the entire window is 1.073mA. 

    I suspect that you are trying to implement your own sleep logic using timers and stuff. I don't know how you did that implementation, but be aware of that both starting and stopping the app_timer will generate events shortly after this call,

    BR,

    Edvin

Reply
  • Hello,

     

    SL06 said:
    Sorry for the title.   I have search how to edit the title and the text but did not find how...

     No worries. I don't think it is possible.

    Where do you set DMP_acq = 1?

    First of all, What do you use to measure the voltage over the serial resistor? If you use a multimeter that may be quite inaccurate, because the current consumption is not constant. BLE will typically cause very short current spikes that are quite tall. Multimeters hande these spikes very differently. 

    As you can see in the attached screenshot from the Power Profiler Kit, using nRF Connect for Desktop -> Power Profiler:

    You can see that the spikes are at ~10mA, but the average current consumption for the entire window is 1.073mA. 

    I suspect that you are trying to implement your own sleep logic using timers and stuff. I don't know how you did that implementation, but be aware of that both starting and stopping the app_timer will generate events shortly after this call,

    BR,

    Edvin

Children
  • Hi Edwin,  thanks for you reply.  

    I had made the measurement with my voltmeter across the 10 ohm resistor.  As suggest, I got out my scope out of the box and got the same exact same voltage.  In standby I got approx. 50 mv. I could also see a bref peak corresponding to the ESB signal transmission each 1 second (battery voltage transmission).  When transmitting quaternion data at 50 HZ, I got a noisy signal averaging at around 120 mV - same as the voltmeter.

    "I suspect that you are trying to implement your own sleep logic using timers and stuff..."

    Yes, this is the code that I have put above.  DMP_acq is just a variable to indicate that the data_acquisition + transmission is active. If DMP_acq = 1,  I don't want to enter in sleep mode.

    If DMP_acq = 0 the acquisition is OFF and I want to send battery level each 1 sec to keep communication going between the peripheral and central and pickup new instruction trough acknowledge.  While waiting, I want to enter sleep mode and use the app_timer event to wake up.

    I have modify the code as follow to get ride of the app_timer start event, but voltage value did not change.

    else if (DMP_acq == 0)    
               {  app_timer_start(m_timer, APP_TIMER_TICKS(1000), NULL);  //  timer one shoot  - events will wake up the sensor 
                  while (timer_event == true);
                  timer_event = false;
                  //nrf_delay_ms(50);     // small voltage increase 
                  
                // 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 also test disabling ESB, but no voltage change.
    I have pick the code __SEV(); __WFE(); __WFE(); for sleep mode without softdevice in the exemples .

    Is that the proper way to do it ?
     

     

  • Sorry, I realized that there an error in the code above .  

    It should be 

    while (timer_event == false);  // ie wait for the app_timer event

    However, that did not work, I did not get the event. I had used that timer_event routine before successfully.

    I have tried to simple put a 50 ms second delay after the app_timer start codeto pass over the timer_event but I dont see any improvement.








  • This is the code I pick up from the low power esb exemple :

    while (true)
                   {
                     // Use directly __WFE and __SEV macros since the SoftDevice is not available.
    
                     // Wait for event.
                      __WFE();
    
                      // Clear Event Register.
                      __SEV();
                      __WFE();
                   }


    If implement in my program, the voltage across the 10 ohm resistor is still 50 mV (5 mA) but the app_timer event does not work anymore.

    IF I disable < while(true) >, then app_timer work, voltage is about the same.



  • 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(); }

Related