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
  • Hi

    Due to the Easter holiday you will have to expect a delay in replies, sorry for the inconvenience!

    I see that in your previous post you have made some changes to your saadc_callback function, and that you've made further changes to that function in this case as well. It seems you have removed the SAADC_EVT_DONE event, which should be generated when the buffer is filled with samples, which is why I think you are experiencing the crash. Please make sure that this snippet is in your saadc_callback function, and see if that fixes your problem.

    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
            ret_code_t err_code;
    
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
            APP_ERROR_CHECK(err_code);
    
            int i;
            NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);
    
            for (i = 0; i < SAMPLES_IN_BUFFER; i++)
            {
                NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
            }
            m_adc_evt_counter++;
        }

    Best regards and happy Easter,

    Simon

  • Hi ,

    No it's still here but I simplify my code for an easier reading :)

    I still have the if NRF_DRV_SAADC_EVT_DONE. It's true that the issue happens always when I try to reconnect after a disconnection while the saadc_callback was fired after the disconnection.

    For example please take a look at this log, I hope it's clear and that I didn't make mistake copy/pasting :

    uint8_t u8_device_state=0;
    
    
    void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    {
       
      	NRF_LOG_INFO("u8_device_state: %d", u8_device_state);
      	NRF_LOG_INFO("NRF_DRV_SAADC_EVT_DONE: %d", NRF_DRV_SAADC_EVT_DONE);
      	NRF_LOG_INFO("p_event->type: %d", p_event->type);
      	NRF_LOG_PROCESS();
    
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE &&
            m_conn_handle == NRF_SUCCESS)
        {
     
            ret_code_t err_code;
    
            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);
              }
    
        }
        else{
          if(m_conn_handle != NRF_SUCCESS){
            NRF_LOG_INFO("m_conn_handle not ready: %d", m_conn_handle);
            NRF_LOG_PROCESS();
          }
        }
    }
    
    
    
    
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_DISCONNECTED:
                u8_device_state=DEVICE_GOtoLowpower;
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
                send_log("m_conn_handle DISCONNECTED");
                send_log("");
                send_log("");
                // LED indication will be changed when advertising starts.
                break;
    
            case BLE_GAP_EVT_CONNECTED:
               	u8_device_state=DEVICE_SET;
               	// err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
               	// APP_ERROR_CHECK(err_code);
                m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                NRF_LOG_INFO("m_conn_handle CONNECTED : %d", m_conn_handle);
                NRF_LOG_PROCESS();
                err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
                APP_ERROR_CHECK(err_code);
                // SET TX POWER AFTER CONNECTING
    	    	uint32_t err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_CONN, m_conn_handle, TX_POWER_LEVEL); 
    	    	APP_ERROR_CHECK(err_code);
                break;
    
            // Other default cases after here not copy/pasted
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    
    
    
    int main(void)
    {
        uint8_t i=0;
        uint32_t err_code;
        bool erase_bonds;
    
        // Some initialisations before that I did not included...
      
        saadc_init();
        timers_init();
        power_management_init();
    
        // Some initialisations after here that I did not included...
       
        err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, m_advertising.adv_handle, TX_POWER_LEVEL);
        APP_ERROR_CHECK(err_code);
    
        u8_device_state=DEVICE_GOtoLowpower;
    
        // Enter main loop.
        for (;;){ 
     		switch(u8_device_state)
            {
              case DEVICE_CONNECTED :
                if(TimerTwo_IRQ && m_conn_handle == NRF_SUCCESS)
                  {
                    send_log("nrf_drv_saadc_sample");
                    nrf_drv_saadc_sample();
                    TimerTwo_IRQ = 0; 
                  }
                  else{
                    if(m_conn_handle != NRF_SUCCESS){
                      NRF_LOG_INFO("m_conn_handle not ready !!! : %d", m_conn_handle);
                      NRF_LOG_PROCESS();
                    }
                  }
                idle_state_handle();
            break; 
    
            case DEVICE_DISCONNECTED : 
            	idle_state_handle();
            break; 
    
            case DEVICE_SET :
    			send_log("------------------------------------------------------");
    			saadc_init();
    			GPIO_init();
    			accel_init();
    			start_TimerTwo();
    			send_log("Device SET");
    			NRF_LOG_INFO("m_conn_handle : %d", m_conn_handle);
    			NRF_LOG_PROCESS();
    			u8_device_state=DEVICE_CONNECTED;
    			break;
    
           	case DEVICE_GOtoLowpower :
    			send_log("Start DEVICE_GOtoLowpower");
    			stop_TimerTwo();
    			send_log("Timers stopped");
    			accel_deep_sleep();
    			disable_spi();
    			send_log("before saadc_uninit");
    			saadc_uninit();
    			send_log("after saadc_uninit");
    			GPIO_lowpower();
    			u8_device_state=DEVICE_DISCONNECTED;
    			send_log("End DEVICE_GOtoLowpower");
            	break; 
    
           	default: 
           		break; 
    
            //nrf_pwr_mgmt_run();
        }
    }
    }
    
    
    

    <info> app: m_conn_handle CONNECTED : 0       <--------------------- Start connection request
    <info> app: ------------------------------------------------------
    <info> app: Device SET
    <info> app: m_conn_handle : 0       <--------------------- Connection made
    <info> app: nrf_drv_saadc_sample       <--------------------- Perform SAADC sample
    <info> app: u8_device_state: 0       <--------------------- Device connected
    <info> app: NRF_DRV_SAADC_EVT_DONE: 0       <--------------------- Just a debug for me
    <info> app: p_event->type: 0       <--------------------- NRF_DRV_SAADC_EVT_DONE
    <info> app: m_conn_handle: 0
    <info> app: err_code: 13313       <--------------------- Waiting for the connected device receive the data
    [......]
    <info> app: nrf_drv_saadc_sample
    <info> app: u8_device_state: 0
    <info> app: NRF_DRV_SAADC_EVT_DONE: 0
    <info> app: p_event->type: 0
    <info> app: m_conn_handle: 0
    <info> app: err_code: 13313
    <info> app: nrf_drv_saadc_sample
    <info> app: u8_device_state: 0
    <info> app: NRF_DRV_SAADC_EVT_DONE: 0
    <info> app: p_event->type: 0
    <info> app: m_conn_handle: 0
    <info> app: err_code: 0       <--------------------- Now the data are received in the connected device
    [......]
    <info> app: nrf_drv_saadc_sample
    <info> app: u8_device_state: 0
    <info> app: NRF_DRV_SAADC_EVT_DONE: 0
    <info> app: p_event->type: 0
    <info> app: m_conn_handle: 0
    <info> app: err_code: 0
    <info> app: nrf_drv_saadc_sample
    <info> app: m_conn_handle DISCONNECTED       <--------------------- Disconnected by the device
    <info> app:
    <info> app:
    <info> app: Start DEVICE_GOtoLowpower
    <info> app: Timers stopped
    <info> app: before saadc_uninit
    <info> app: after saadc_uninit
    <info> app: End DEVICE_GOtoLowpower
    <info> app: u8_device_state: 1       <--------------------- /!\ WARNING : I still receive data on saadc_callback, when this happen, I know next connection will fail to send data
    <info> app: NRF_DRV_SAADC_EVT_DONE: 0
    <info> app: p_event->type: 0
    <info> app: m_conn_handle not ready: 65535
    
    
    <info> app: m_conn_handle CONNECTED : 0       <--------------------- Start a new connection request
    <info> app: ------------------------------------------------------
    <info> app: Device SET
    <info> app: m_conn_handle : 0       <--------------------- Connection made
    <info> app: nrf_drv_saadc_sample       <--------------------- Perform SAADC sample but never trigger saadc_callback
    <info> app: nrf_drv_saadc_sample
    <info> app: nrf_drv_saadc_sample
    <info> app: nrf_drv_saadc_sample
    <info> app: nrf_drv_saadc_sample
    <info> app: nrf_drv_saadc_sample
    <info> app: nrf_drv_saadc_sample
    [.......]

    Thanks for your help and feedbacks !

    Stéphane

  • It is normal that the saadc never trigger again after that.  This is because you didn't read the data out when the connection handle is invalid.  The state of the saadc was not reset.  You should read the saadc date even not connected, just don't send it.

  • Hi ,

    Thanks for your feedback, so I updated my saadc_callback to send it only if m_conn_handle is equal to zero (connected). Here is the new saadc_callback.

    void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    {
       
      NRF_LOG_INFO("u8_device_state: %d", u8_device_state);
      NRF_LOG_INFO("p_event->type: %d", p_event->type);
      NRF_LOG_PROCESS();
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
     
            ret_code_t err_code;
    
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
            APP_ERROR_CHECK(err_code);
            send_log("nrf_drv_saadc_buffer_convert DONE");
          
            val = p_event->data.done.p_buffer[0];
            if(val > 65000 || val < 0) val=0;
    
            
            value_data[0]= (uint8_t) val;
            value_data[1]= (uint8_t) (val>>8);
    
            if(m_conn_handle == NRF_SUCCESS){
              NRF_LOG_INFO("Send it !");
              err_code = ble_service_on_value_change(m_conn_handle, &m_service, value_data);
              NRF_LOG_INFO("m_conn_handle: %d", m_conn_handle);
              NRF_LOG_INFO("err_code: %d", err_code);
              NRF_LOG_PROCESS();
              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
                 )
                {
                  NRF_LOG_INFO("ERROR CHECK");
                  NRF_LOG_PROCESS();
                  APP_ERROR_CHECK(err_code);
                }
            }
            else{
              send_log("Did not sent it because we are not connected anymore");
            }
    
        }
    }

    But it's not working. Here are the log :

    WORKING LOGS :
    [...]
    <info> app: Send it !
    <info> app: m_conn_handle: 0
    <info> app: err_code: 0
    <info> app: m_conn_handle DISCONNECTED
    <info> app:
    <info> app:
    <info> app: Start DEVICE_GOtoLowpower
    <info> app: enter stop_TimerOne
    <info> app: exit stop_TimerOne
    <info> app: enter stop_TimerTwo
    <info> app: exit stop_TimerTwo
    <info> app: Timers stopped
    <info> app: enter saadc_uninit
    <info> app: before nrf_drv_saadc_uninit
    <info> app: after nrf_drv_saadc_uninit
    <info> app: exit saadc_uninit
    <info> app: enter GPIO_lowpower
    <info> app: exit GPIO_lowpower
    <info> app: End DEVICE_GOtoLowpower
    <info> app: m_conn_handle CONNECTED : 0
    <info> app: ------------------------------------------------------
    <info> app: enter saadc_init
    <info> app: exit saadc_init
    <info> app: enter GPIO_init
    <info> app: exit GPIO_init
    <info> app: enter start_TimerTwo
    <info> app: exit start_TimerTwo
    <info> app: Device SET
    <info> app: m_conn_handle : 0
    <info> app: nrf_drv_saadc_sample
    <info> app: u8_device_state: 0
    <info> app: p_event->type: 0
    <info> app: nrf_drv_saadc_buffer_convert DONE
    <info> app: Send it !
    <info> app: m_conn_handle: 0
    [...]
    
    
    
    
    NOT WORKING LOGS :
    [...]
    <info> app: nrf_drv_saadc_sample
    <info> app: m_conn_handle DISCONNECTED
    <info> app:
    <info> app:
    <info> app: Start DEVICE_GOtoLowpower
    <info> app: enter stop_TimerOne
    <info> app: exit stop_TimerOne
    <info> app: enter stop_TimerTwo
    <info> app: exit stop_TimerTwo
    <info> app: Timers stopped
    <info> app: enter saadc_uninit
    <info> app: u8_device_state: 3
    <info> app: p_event->type: 0
    <info> app: nrf_drv_saadc_buffer_convert DONE
    <info> app: Did not sent it because we are not connected anymore
    <info> app: before nrf_drv_saadc_uninit
    <info> app: after nrf_drv_saadc_uninit
    <info> app: m_conn_handle CONNECTED : 0
    <info> app: ------------------------------------------------------
    <info> app: enter saadc_init
    <info> app: exit saadc_init
    <info> app: enter GPIO_init
    <info> app: exit GPIO_init
    <info> app: enter start_TimerTwo
    <info> app: exit start_TimerTwo
    <info> app: Device SET
    <info> app: m_conn_handle : 0
    <info> app: nrf_drv_saadc_sample
    <info> app: nrf_drv_saadc_sample
    <info> app: nrf_drv_saadc_sample
    [...]

Reply
  • Hi ,

    Thanks for your feedback, so I updated my saadc_callback to send it only if m_conn_handle is equal to zero (connected). Here is the new saadc_callback.

    void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    {
       
      NRF_LOG_INFO("u8_device_state: %d", u8_device_state);
      NRF_LOG_INFO("p_event->type: %d", p_event->type);
      NRF_LOG_PROCESS();
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
     
            ret_code_t err_code;
    
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
            APP_ERROR_CHECK(err_code);
            send_log("nrf_drv_saadc_buffer_convert DONE");
          
            val = p_event->data.done.p_buffer[0];
            if(val > 65000 || val < 0) val=0;
    
            
            value_data[0]= (uint8_t) val;
            value_data[1]= (uint8_t) (val>>8);
    
            if(m_conn_handle == NRF_SUCCESS){
              NRF_LOG_INFO("Send it !");
              err_code = ble_service_on_value_change(m_conn_handle, &m_service, value_data);
              NRF_LOG_INFO("m_conn_handle: %d", m_conn_handle);
              NRF_LOG_INFO("err_code: %d", err_code);
              NRF_LOG_PROCESS();
              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
                 )
                {
                  NRF_LOG_INFO("ERROR CHECK");
                  NRF_LOG_PROCESS();
                  APP_ERROR_CHECK(err_code);
                }
            }
            else{
              send_log("Did not sent it because we are not connected anymore");
            }
    
        }
    }

    But it's not working. Here are the log :

    WORKING LOGS :
    [...]
    <info> app: Send it !
    <info> app: m_conn_handle: 0
    <info> app: err_code: 0
    <info> app: m_conn_handle DISCONNECTED
    <info> app:
    <info> app:
    <info> app: Start DEVICE_GOtoLowpower
    <info> app: enter stop_TimerOne
    <info> app: exit stop_TimerOne
    <info> app: enter stop_TimerTwo
    <info> app: exit stop_TimerTwo
    <info> app: Timers stopped
    <info> app: enter saadc_uninit
    <info> app: before nrf_drv_saadc_uninit
    <info> app: after nrf_drv_saadc_uninit
    <info> app: exit saadc_uninit
    <info> app: enter GPIO_lowpower
    <info> app: exit GPIO_lowpower
    <info> app: End DEVICE_GOtoLowpower
    <info> app: m_conn_handle CONNECTED : 0
    <info> app: ------------------------------------------------------
    <info> app: enter saadc_init
    <info> app: exit saadc_init
    <info> app: enter GPIO_init
    <info> app: exit GPIO_init
    <info> app: enter start_TimerTwo
    <info> app: exit start_TimerTwo
    <info> app: Device SET
    <info> app: m_conn_handle : 0
    <info> app: nrf_drv_saadc_sample
    <info> app: u8_device_state: 0
    <info> app: p_event->type: 0
    <info> app: nrf_drv_saadc_buffer_convert DONE
    <info> app: Send it !
    <info> app: m_conn_handle: 0
    [...]
    
    
    
    
    NOT WORKING LOGS :
    [...]
    <info> app: nrf_drv_saadc_sample
    <info> app: m_conn_handle DISCONNECTED
    <info> app:
    <info> app:
    <info> app: Start DEVICE_GOtoLowpower
    <info> app: enter stop_TimerOne
    <info> app: exit stop_TimerOne
    <info> app: enter stop_TimerTwo
    <info> app: exit stop_TimerTwo
    <info> app: Timers stopped
    <info> app: enter saadc_uninit
    <info> app: u8_device_state: 3
    <info> app: p_event->type: 0
    <info> app: nrf_drv_saadc_buffer_convert DONE
    <info> app: Did not sent it because we are not connected anymore
    <info> app: before nrf_drv_saadc_uninit
    <info> app: after nrf_drv_saadc_uninit
    <info> app: m_conn_handle CONNECTED : 0
    <info> app: ------------------------------------------------------
    <info> app: enter saadc_init
    <info> app: exit saadc_init
    <info> app: enter GPIO_init
    <info> app: exit GPIO_init
    <info> app: enter start_TimerTwo
    <info> app: exit start_TimerTwo
    <info> app: Device SET
    <info> app: m_conn_handle : 0
    <info> app: nrf_drv_saadc_sample
    <info> app: nrf_drv_saadc_sample
    <info> app: nrf_drv_saadc_sample
    [...]

Children
  • I see that there was a saadc sample started then saadc uninit before getting the result then the saadc interrupt occurs in between.  Could this be the cause of the issue ?

      

  • This is exactly what I found by checking the log multiple time. It looks like every time the error occurs is when m_conn_handle DISCONNECTED is called just after a nrf_drv_saadc_sample is requested. This is why I included it in my log.

    I need to confirm.

    But if this is the case, how can we prevent it ? Because we should be able to disconnect any time.

    EDIT : I'm almost sure this is the reason, every time I am able to reproduce the error, this is what I see in the logs.

    EDIT 2 : It looks like, when I add a nrf_delay_ms(100); at the beginning of my DEVICE_GOtoLowpower case, I do not reproduce the error. Maybe this give him the time to finish the nrf_drv_saadc_sample ?! Do you see a better solution or is it OK if I keep this like that ?

  • One way is to check a flag in the uninit if it is sampling set another flag to uninit the in the saadc event handler after processing the sample.  If no sampling in progress then proceed with uninit.  

    An other way is to check in saadc event handler if connection is invalid then uninit the saadc instead of sending data.  

  • Thanks for the ideas.

    I ended up setting a flag to true every time I do a nrf_drv_saadc_sample() and I set it to false just after I've done the nrf_drv_saadc_buffer_convert()

    When I disconnect, in the DEVICE_GOtoLowpower case I check if my flag is true or false.

    If it's false then we do not have a saadc sample in progress so I can do all my uninit. If it's true, I wait 10ms.

    So far it's working great ! Hope we are done with this !

    Thanks for your help and (and your patience)

Related