This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

sd_ble_gap_scan_stop hangs the program - not hard fault or error

Hi,

I'm trying to build my own "auto sleep" mechanism based on timers.

This is my code:

const nrf_drv_timer_t SLEEP_TIMER = NRF_DRV_TIMER_INSTANCE(2);
int sleep_timer_ms = 10000;

void nrf_timer_init(void) // called from main
{
	uint32_t err_code;

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
		timer_cfg.frequency = NRF_TIMER_FREQ_31250Hz;
		timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
		timer_cfg.mode = NRF_TIMER_MODE_TIMER;
	
	err_code = nrf_drv_timer_init(&SLEEP_TIMER, &timer_cfg, SLEEP_TIMER_event_handler);
    APP_ERROR_CHECK(err_code);
}

void sleep_timer_reset(void) // varoius user activities trigger this function
{
		nrf_drv_timer_clear(&SLEEP_TIMER);
}
void sleep_timer_init(void) // called from main (after nrf_timer_init)
{
		int sleep_timer_ticks;
		nrf_drv_timer_clear(&SLEEP_TIMER);
			
		// initiate timer
		sleep_timer_ticks = nrf_drv_timer_ms_to_ticks(&SLEEP_TIMER, sleep_timer_ms);
		nrf_drv_timer_extended_compare(&SLEEP_TIMER, NRF_TIMER_CC_CHANNEL2, sleep_timer_ticks, NRF_TIMER_SHORT_COMPARE2_STOP_MASK, true);
		nrf_drv_timer_enable(&SLEEP_TIMER);
}
void SLEEP_TIMER_event_handler(nrf_timer_event_t event_type, void* p_context)
{
		soft_sleep();
}
void soft_sleep(void)
{
        // ...
        
        // don't check for errors here. We can get INVALID_STATE - that's ok
        err_code = sd_ble_gap_scan_stop();		// <-- program freezes here
		NRF_LOG_DEBUG("sd_ble_gap_scan_stop returned %i", err_code);
		
		// ...
}

The timer works as expected, but when the soft_sleep function is reached, the program freezes on the line where I want to stop the scanning:

err_code = sd_ble_gap_scan_stop();

The same code works properly when I iinitiate the soft_sleep function from a button press. It only fails from the timer handler. How Can i fix it? Thanks.

PS: the timer is enabled anc configured is sdk_config.h

// <e> TIMER_ENABLED - nrf_drv_timer - TIMER periperal driver - legacy layer
//==========================================================
#ifndef TIMER_ENABLED
#define TIMER_ENABLED 1
#endif
// <o> TIMER_DEFAULT_CONFIG_FREQUENCY  - Timer frequency if in Timer mode
 
// <0=> 16 MHz 
// <1=> 8 MHz 
// <2=> 4 MHz 
// <3=> 2 MHz 
// <4=> 1 MHz 
// <5=> 500 kHz 
// <6=> 250 kHz 
// <7=> 125 kHz 
// <8=> 62.5 kHz 
// <9=> 31.25 kHz 

#ifndef TIMER_DEFAULT_CONFIG_FREQUENCY
#define TIMER_DEFAULT_CONFIG_FREQUENCY 0
#endif

// <o> TIMER_DEFAULT_CONFIG_MODE  - Timer mode or operation
 
// <0=> Timer 
// <1=> Counter 

#ifndef TIMER_DEFAULT_CONFIG_MODE
#define TIMER_DEFAULT_CONFIG_MODE 0
#endif

// <o> TIMER_DEFAULT_CONFIG_BIT_WIDTH  - Timer counter bit width
 
// <0=> 16 bit 
// <1=> 8 bit 
// <2=> 24 bit 
// <3=> 32 bit 

#ifndef TIMER_DEFAULT_CONFIG_BIT_WIDTH
#define TIMER_DEFAULT_CONFIG_BIT_WIDTH 3
#endif

// <o> TIMER_DEFAULT_CONFIG_IRQ_PRIORITY  - Interrupt priority
 

// <i> Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
// <0=> 0 (highest) 
// <1=> 1 
// <2=> 2 
// <3=> 3 
// <4=> 4 
// <5=> 5 
// <6=> 6 
// <7=> 7 

#ifndef TIMER_DEFAULT_CONFIG_IRQ_PRIORITY
#define TIMER_DEFAULT_CONFIG_IRQ_PRIORITY 2
#endif

// <q> TIMER0_ENABLED  - Enable TIMER0 instance
 

#ifndef TIMER0_ENABLED
#define TIMER0_ENABLED 0
#endif

// <q> TIMER1_ENABLED  - Enable TIMER1 instance
 

#ifndef TIMER1_ENABLED
#define TIMER1_ENABLED 1
#endif

// <q> TIMER2_ENABLED  - Enable TIMER2 instance
 

#ifndef TIMER2_ENABLED
#define TIMER2_ENABLED 1
#endif

// <q> TIMER3_ENABLED  - Enable TIMER3 instance
 

#ifndef TIMER3_ENABLED
#define TIMER3_ENABLED 1
#endif

// <q> TIMER4_ENABLED  - Enable TIMER4 instance
 

#ifndef TIMER4_ENABLED
#define TIMER4_ENABLED 0
#endif

 I'm guessing it's the priorities problem (when I change the priority to 7 it works), however I need the timer priority as high as possible, because I use timers 0 and 1 for other, critical things in my app.

  • Hello,

    Usually when I see things hanging like this, I suspect some interrupt priority issues.

    It looks like this is also the case here. If you take a look at the softdevice interrupt priority section in the softdevice documentation.

    I see that you set your timer interrupt priority to 2 in sdk_config.h. When you call sd_ble_gap_scan_stop(), you are in this interrupt priority (2), and you try to call a softdevice call that (probably) uses a lower interrupt priority. Without knowing the details, I guess the softdevice is waiting for some event (probably another timer timeout) to trigger, but it doesn't get access to the CPU, because you are waiting in priority 2. 

     I'm guessing it's the priorities problem (when I change the priority to 7 it works), however I need the timer priority as high as possible, because I use timers 0 and 1 for other, critical things in my app.

    So I was going to suggest that you set TIMER_DEFAULT_CONFIG_IRQ_PRIORITY back to 6. Are the timers really triggering a lot at the same time? Stopping scanning doesn't sound like a time critical operation, but I don't know what your application is doing.

    You say that you are using TIMER0 and 1 for critical things. Are you sure you are using TIMER0? Because that is reserved for the softdevice, if you have enabled it.

    Another workaround is to handle this outside your timer interrupt by setting some volatile variable and check for it in your main loop:

    // Near the top of main.c:
    volatile stop_scanning = false;
    
    void SLEEP_TIMER_event_handler(nrf_timer_event_t event_type, void* p_context)
    {
    		//soft_sleep();
            stop_scanning = true;
    }
    void soft_sleep(void)
    {
            // ...
            
            // don't check for errors here. We can get INVALID_STATE - that's ok
            err_code = sd_ble_gap_scan_stop();		// <-- program freezes here
    		NRF_LOG_DEBUG("sd_ble_gap_scan_stop returned %i", err_code);
    		
    		// ...
    }
    
    int main(void)
    {
        ...
        
        for (;;)
        {
            if (stop_scanning == true)
            {
                soft_sleep();
            }
            ...
        }
    }

    Best regards,

    Edvin

Related