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

Update timer speed once connected

I have a custom Characteristic in my GATT that is sending data in Notify mode every 30ms.

In my firmware I use timer to do this with something like this :


#define RTC1_TICK_DURATION		31
	
#define TIMER_ONE_DURATION   		33 // 30ms																/**<(deflt:1000)[ms] sending/measurement cycle duration for 1s cycled characteristics*/
#define TIMER_ONE_TICKS_NB 		(TIMER_ONE_DURATION * 1000 / RTC1_TICK_DURATION)


err_code = app_timer_start(m_TimerOne_id, (uint32_t)TIMER_ONE_TICKS_NB, NULL);


Everything is working great but sometimes, randomly, my app using BLE or my laptop using Web BLE (so two different device with two different source code with the same behavior) are unable to retrieve value for this Characteristic. They are able to connect to my device but no Characteristic value is send.

I tried to change the interval from 30ms to 90ms and so far I am not able to reproduce this issue so it lead me to think that the speed can be the source of the issue.

How would you deal with that ? Is it possible to notify at a low pace, then one second after a connection is made, increase the speed ? Or better, when someone subscribe to the Notifying Characteristic increase speed, when it disconnect decrease speed ?

Thanks !

Parents Reply Children
  • Hi 

    My product is now assembled so I cannot have access to the board, I can only update the firmware so it's not super easy to put debug.

    Here is the basic process of my code, where do you want to debug ?

    #define TIMER_TWO_DURATION   		25
    #define TIMER_TWO_TICKS_NB 			(TIMER_TWO_DURATION * 1000 / 31)
    
    APP_TIMER_DEF(m_TimerTwo_id); 
    uint16_t TimerTwo_IRQ;
    
    uint8_t  value_data[2];
    
    
    void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    {
    	err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);
    
        val = p_event->data.done.p_buffer[0];
    
        value_data[0]= (uint8_t) val;
        value_data[1]= (uint8_t) (val>>8);
    
    	err_code = ble_service_on_value_change(m_conn_handle, &m_service, value_data);
            if (err_code != NRF_SUCCESS &&
                err_code != BLE_ERROR_INVALID_CONN_HANDLE &&
                err_code != NRF_ERROR_INVALID_STATE &&
                err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING &&
                err_code != NRF_ERROR_RESOURCES
               )
              {
                APP_ERROR_CHECK(err_code);
              }
    }
    
    
    uint32_t ble_service_on_value_change(uint16_t conn_handle, ble_service_t * p_service, uint8_t value_data[2])
    {
        ret_code_t retval;
        ble_gatts_hvx_params_t params;
        uint16_t len = 2;
    
        memset(&params, 0, sizeof(params));
        params.type   = BLE_GATT_HVX_NOTIFICATION;
        params.handle = p_service->value_char_handles.value_handle;
        params.p_data = value_data;
        params.p_len  = &len;
    
        return sd_ble_gatts_hvx(conn_handle, &params);
    }
    
    
    
    void TimerTwo_timeout_handler(void * p_context)
    {
      UNUSED_PARAMETER(p_context);
      
      TimerTwo_IRQ = 1;
    }
    
    
    
    static void timers_init(void)
    {
        // Initialize timer module.
        uint32_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
        // Initialize timer2 module.
        err_code = app_timer_create(&m_TimerTwo_id, APP_TIMER_MODE_REPEATED, TimerTwo_timeout_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    
    void start_TimerTwo(void)
    {
    	uint32_t err_code;
    	
    	err_code = app_timer_start(m_TimerTwo_id, (uint32_t)TIMER_TWO_TICKS_NB, NULL);
    	APP_ERROR_CHECK(err_code);
    }
    
    
    
    void stop_TimerTwo(void)
    {
    	uint32_t err_code;
    	
    	err_code = app_timer_stop(m_TimerTwo_id); /* stops the fifo timer */
    	APP_ERROR_CHECK(err_code);
    }
    
    
    
    int main(void)
    {
        // All initialisation here
        
        timers_init();
        u8_device_state=DEVICE_GOtoLowpower;
    
        // Enter main loop.
        for (;;)
        { 
     		switch(u8_device_state)
            {
    	        case DEVICE_CONNECTED :
    	            if(TimerTwo_IRQ)
    	              {
    	                nrf_drv_saadc_sample();
    	                TimerTwo_IRQ = 0;       
    	              }
    	            idle_state_handle();
    	        	break; 
    
    	        case DEVICE_DISCONNECTED : 
    	        	idle_state_handle();
    	        	break; 
    
    	        case DEVICE_SET :
    				saadc_init();
    				start_TimerTwo();
    				u8_device_state=DEVICE_CONNECTED;
    				break; 
    
    	       case DEVICE_GOtoLowpower :
    				stop_TimerTwo();
    				u8_device_state=DEVICE_DISCONNECTED;
    				break; 
    
    	        default : 
    	       		break;
    	    }
    	}
    }

    What do you think about the race condition for the timer ? It doesn't looks like it ?

    Thanks for your support !

Related