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

How to manage SAADC and BLE run in parallel

 I'm trying to send ADC data through BLE using nRF52840.

 According to the example codes named ble_peripheral/ble_app_uart, peripheral/saadc, I wrote a code and it is able to transmit the data.

 But the problem is that the throughput is about 850 kbps, which is much lower than I expected. When I ran the throughput demo, it was able to get 1M(conn_interval =7.5ms)~1.3M(conn_interval=400ms) bps.

 So I wonder whether one of the ADC sampling or BLE task becomes a bottleneck as I aligned them in a serial way like the below code.

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    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);
        //SEGGER_RTT_WriteString(0, "saadc_callback function\n");

        saadc2ble_convert();   
        uint16_t length = (uint16_t)(SAMPLES_IN_BUFFER * 2);            
        //SEGGER_RTT_WriteString(0, "Trying to send data.\n");  
        
        notification_err_code = ble_nus_data_send(&m_nus, adc_output, &length, m_conn_handle);   
        //sprintf(error_string, "Error number: %#x\n", notification_err_code);
        //SEGGER_RTT_WriteString(0, error_string);  
        if ((notification_err_code != NRF_ERROR_INVALID_STATE) &&
                    (notification_err_code != NRF_ERROR_RESOURCES) &&
                    (notification_err_code != NRF_ERROR_NOT_FOUND))
        {
            APP_ERROR_CHECK(notification_err_code);                    
        }
    }
}

 For now, ble_nus_data_send() is called every time when the SAADC buffer is full.

 Will there be some advances if I save the ADC samples in a kind of buffer and call ble_nus_data_send() several times when the data are collected?

Parents
  • Hi 

    What is your SAMPLES_IN_BUFFER parameter set to?

    In order to achieve the maximum possible throughput it is necessary to adjust the packet length depending on the data length that is exchanged during the connection establishment. 

    Do you know what connection parameters, data length and ATT MTU settings you are using for the connection?

    Best regards
    Torbjørn

  • I've set SAMPLES_IN_BUFFER to 240. And I set MTU = 247 and turned on the data length extension option. Also, I checked 240 bytes of data are received in a client device.

  • Maybe my question was not good...

    So, I want to be sure that if I call ble_nus_data_send() functions too fast, then are the data stored in some buffer and transmitted consecutively?

    Or, the device or SoftDevice or somewhat waits until the transmission is possible and send data and then go back to ADC work?

    Or, lastly, there is no buffer in default so if I can not send data via BLE, then the data just disappear and the next ADC data are sent?

  • Hi

    DL_November said:
    So, I want to be sure that if I call ble_nus_data_send() functions too fast, then are the data stored in some buffer and transmitted consecutively?

    As long as NRF_SUCCESS is returned from the nus_data_send() function the data will be buffered in the SoftDevice, and all the packets buffered in the SoftDevice will be transmitted in sequence as soon as the next connection event occurs. 

    In case you have packet loss over the air the SoftDevice might have to retransmit a packet several times before it is received on the other side, so you can't know exactly how much time it will take to send each packet, but a packet stored in the SoftDevice buffer will never be dropped unless a disconnect occurs. 

    If NRF_ERROR_RESOURCES is returned then no data is sent to the SoftDevice buffer, and it is the responsibility of the application to upload the data again later (or allow it to be dropped).  

    In order to be more robust to data transmission delays over the BLE link I would recommend that you use a ring buffer in the application to receive ADC data, and use this as an intermediary buffer between the ADC and the BLE connection. Then you will have some additional buffer for ADC data in case of Bluetooth delays, and once the Bluetooth stack is able to send more data again it can be quickly fed by the buffer. 

    With such a system you can fill the ringbuffer in the saadc callback, and empty it from the main loop, which allows the ADC to run more seamlessly in the background even when the SoftDevice is delayed by packet loss. 

    A side effect of this is that the average latency could increase, but it should lead to more stable transmission.

    Best regards
    Torbjørn

  • As long as NRF_SUCCESS is returned from the nus_data_send() function the data will be buffered in the SoftDevice, and all the packets buffered in the SoftDevice will be transmitted in sequence as soon as the next connection event occurs. 

    Sorry for the late reply.

    Then, how much data can be buffered in the SoftDevice? Does it have additional memory than 1 MB flash of nRF52840?

  • Hi 

    The buffer size is based on the NRF_SDH_BLE_GAP_EVENT_LENGTH parameter in sdk_config.h. 

    The larger this parameter the more buffer size will be allocated in the SoftDevice, but the drawback is that you need to allocate more RAM to the SoftDevice as well. 

    All the SoftDevice buffers are placed in RAM, not in flash, so you are limited by the amount of RAM available in the nRF device. 

    Best regards
    Torbjørn

  • The buffer size is based on the NRF_SDH_BLE_GAP_EVENT_LENGTH parameter in sdk_config.h. 

    I changed the NRF_SDH_BLE_GAP_EVENT_LENGTH from 400 to 800. However, when I checked memory usage in SES debugging mode, only 32.5 KB of 256 KB are used no matter of the NRF_SDH_BLE_GAP_EVENT_LENGTH.

    Is there something I have to change more than sdk_config.h?

Reply Children
Related