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

Timeslot API - low power optimization

Hello,

I'm working with timeslot API (basing on github.com/.../observer). I have an advertising and active scanning running concurrently. However, I want to completly switch off scanning functionality for some period of time. For example, I want to scan with 15000us timeslot length and 30000us timeslot distance, but just for every 5 seconds. To manage that I have a timer running and switching on/off scanning:

static void scanner_timer_timeout_handler(void * p_context)
{
	btle_status_codes_t btle_err_code;
    UNUSED_PARAMETER(p_context);
		
	scan_run ^= true;
	
	if(scan_run)
	{
		btle_err_code = btle_scan_init (SWI1_IRQn);
		scan_enable.scan_enable = BTLE_SCAN_MODE_ENABLE;
		btle_err_code = btle_scan_enable_set (scan_enable);

	} else {
		scan_enable.scan_enable = BTLE_SCAN_MODE_DISABLE;
		btle_err_code = btle_scan_enable_set (scan_enable);
	}
}

It works fine, scanning is enabled / disabled for every timer callback call. However, I noticed that after scan disable (btle_scan_enable_set(..disable param..)) there is about 950uA current consumption.

I tested it in a following way: before an endless loop in the main() I'm invoking:

// current consumption before invoking timeslot_init() is about 0.01mA
timeslot_init()
{    
  btle_err_code = btle_scan_init (SWI1_IRQn);
  btle_err_code = btle_scan_param_set (scan_param);

  // enable scanning, current consumption here is about 11mA  
  btle_err_code = btle_scan_enable_set (scan_enable);

   // wait for 2 sec    
   nrf_delay_us(2000000);
   
   // disable scanning   
   scan_enable.scan_enable = BTLE_SCAN_MODE_DISABLE;
   btle_err_code = btle_scan_enable_set (scan_enable);
  
   // ..after disable, current is about 950uA!
}
   
main()
{    
   // some initialization here..
 
    timeslot_init();

    while(1) {
       sd_app_evt_wait();

       if(sw_interrupt()){
           // handling adv and resp packets
       }
    }
}

void SWI1_IRQHandler(void)
{
   sw_interrupt = true;
}

and I'm stuck.. I'm searching in TS source code and considering what can be disabled, but can't find anything.. (I'm using PCA10004 dev board for tests).

Could you please advise me what can I do?

Thanks!

  • @adriand : Have you tried to disable the HFCLK crystal after you disable scaning ?

    It seemed that when you request the timeslot with earliest possible type, the HFCLK crystal was kept running and hadn't been turned off after you finish.

  • @hungbui thank you for your input. I didn't think about it before. However, it looks like HFCLK is always disable. I put following code into while in the main:

    while(1){ 
    	btle_err_code = sd_clock_hfclk_is_running(&hf);	
    	ASSERT (btle_err_code == NRF_SUCCESS);			
    	if(hf==0)
    		__LOG("DISABLED");
    	else
    		__LOG("ENABLED");
    
    	sd_app_evt_wait();
    
    	if(sw_interrupt()){
               		//handling adv and resp packets
         }
    }
    

    and hf is always 0. Is there any other way to check HFCLK (when SD is being used)? However, regardless of checking if HFCLK is working, I tried to invoke sd_clock_hfclk_release() after scanning disable, but it didn't change anything.

    Maybe I should mention that I changed BLE stack initialization than it is made in timeslot example. I'm using: SOFTDEVICE_HANDLER_INIT(20ppm, false); defined BLE_STACK_SUPPORT_REQD

  • @adriand: I would suggest you to use the register directly to control the HFCLK instead of using sd_* api because the application has full control of radio, HFCLK when in its timeslot. What you can do is to start the HFCLK crystal using this code:

    if (!(NRF_CLOCK->HFCLKSTAT & CLOCK_HFCLKSTAT_SRC_Msk))
    
    {
    
      NRF_CLOCK->TASKS_HFCLKSTART = 1;
    
      NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    
      while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    
    }
    

    Then stop the HFCLK after you finish scanning using :

    NRF_CLOCK->TASKS_HFCLKSTOP = 1;

    Another thing can cause high current consumption is the debug mode. You need to make sure you power off and on the device at least once after you program the chip, otherwise it will remain in debug mode.

  • Thanks. Ok, I tried your last hint, but it seems that HFCLK is enabled after scanner is enabled and disabled after scanning stops. So it's rather not HFCLK. I also checked debug (I disconnect jlink and manage power reset), uart for logging is also disabled. I tried multiactivity beacon with hrs and it seems to be ok - power consumption is about 0.01mA after scanning stops. I will try to compare source codes. The first diffrence I can see is that GPIOTE is being used (ll_scan_start()) in the observer example and there's not in multiactivity+hrs.

  • Ok, I suppose I found the problem, but I doubt if I solved it correctly. In the file ll_scan.c in function ll_scan_start() I commented out every line that has GPIOTE->CONFIG:

      /* Toggle pin when radio reaches END (RX or TX) */
      // NRF_GPIOTE->CONFIG[DBG_RADIO_END] = ..
    
      /* Toggle pin when radio reaches READY (RX or TX) */
      // NRF_GPIOTE->CONFIG[DBG_RADIO_READY]= ..
    
       /* Toggle pin when timer triggers radio START (TX) */
       // NRF_GPIOTE->CONFIG[DBG_RADIO_TIMER] = ..
    

    maybe it's strange but it works (only several minutes test): advertising works, disabling / enabling scanner works, connecting works. And current consumption is ok.

Related