can't send data via ble nus service at high speed and leads to disconnection

usb_cdc_ble_fordongle_use_this.zip

Hi I use nrf52840 dongle as central and nrf52840dk as peripheral

my development aim is to get a analog signal( more specific, eeg signal ) to nrf52840dk,

convert it to digital value by saadc of dk, send this data to nrf52840 dongle which act as central by ble( nus service )

then, show this adc value on teraterm by usb_cdc function.   

i scratched codes from nrfsdk 17.1.0 example and other resources on website

and i built code without error and it perform its function as i wanted.

but problem occurs when i adjust nrf_drv_timer_ms_to_ticks(&m_timer, 20) fuction's parameter 20 to less then 10

so that i can receive data value faster.

i use usb_cdc for dongle and nus service to communicate for dongle and dk.

in dk, i use saadc_callback to get adc value and   nrf_drv_timer_ms_to_ticks(&m_timer, 20)  determine the period of sending data

in  saadc_callback, i use code

bytes_to_send = sprintf(nus_string, "%.3f\r\n", adc1 );
err_code = ble_nus_data_send(&m_nus, nus_string, &bytes_to_send, m_conn_handle);

to send data to dongle

when i decrease the period less than 10ms,

dongle and dk are disconnected automatically.

period longer than 20ms is fine and send data well.

but since i need more high frequency to get data to analyse singal ( i need 2ms ) , 

i need some advice about this issue

i think it is related about ble throughput and maximum available data amount in specific time interval

since sending longer nus_string required longer  time period for sending data ( i tested it changing  nrf_drv_timer_ms_to_ticks(&m_timer, 20)'s value )

i use windows 11 and segger embedded studio 

i am a begginer in this stuff so i couldn't fully understand the ble stuff.

so my problem could seem weird and hard to understand  but any advice about this problem will be a great help for me.

i attached my project for dongle, dk  each  so it might be helpful to understand my problem.

best regards 

Parents
  • What is you connection interval, Event, length, MTU size, and LL packet size? 

    I think you're running a connection interval of 20ms, event length of 7.5ms, MTU of 27, and LL of 31, as that is the default params. 

    If that is in fact the case I suggest you increase the MTU and LL packet sizes, as well as the SAADC buffer sizes.

    Do you have any real-time latency requirements?

    I suggest you don't convert the samples from int16_t to float before transmission. A float requires at least 32bit so you need 2x the throuput to transmit the same amount of data. Also a 32bit float might loose a bit of precision, and it's best to use int16_t until you can convert to float on a larger machine. Also the float conversions will require a significant amount of power on the Cortext-M4F CPU. 

    I also suggets you enable at least 8x oversampling and increase the sample rate significantly. The SAADC will not use much more power while sampling extra samples for oversampling. 

    There's no reason why you should not be able to get up to 20kHz sample rate (including 8x oversampling) with an nRF52840 in both ends of the BLE link in an average RF environment. Though the average current consumption will increase to ~10-12mA at that sample rate and throughput. 

    See also  The ultimate guide to maximizing your BLE and Bluetooth 5 data throughput  

  • Hi haakonsh

    #define MIN_CONN_INTERVAL MSEC_TO_UNITS(30, UNIT_1_25_MS)
    #define MAX_CONN_INTERVAL MSEC_TO_UNITS(30, UNIT_1_25_MS)

    NRF_SDH_BLE_GAP_DATA_LENGTH 251

    NRF_SDH_BLE_GAP_EVENT_LENGTH 6 to 320 

    NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247

    SAADC_SAMPLES_IN_BUFFER 4 to 8

    also used

    void conn_evt_len_ext_set(void)
    {
    ret_code_t err_code;
    ble_opt_t opt;

    memset(&opt, 0x00, sizeof(opt));
    opt.common_opt.conn_evt_ext.enable = 1;

    err_code = sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt);
    APP_ERROR_CHECK(err_code);
    }

    yeah increasing NRF_SDH_BLE_GAP_EVENT_LENGTH  and SAADC_SAMPLES_IN_BUFFER

    solved above problem 

    BTW 20kHZ sample rate was able in my project.

    i was just unable to send adc value via ble more rapidly

    so the problem was about throughput am i right?

    there are so much more things i must learn about this stuff !!

    thanks for your help haakonsh

    best regards

    LeeJW

Reply
  • Hi haakonsh

    #define MIN_CONN_INTERVAL MSEC_TO_UNITS(30, UNIT_1_25_MS)
    #define MAX_CONN_INTERVAL MSEC_TO_UNITS(30, UNIT_1_25_MS)

    NRF_SDH_BLE_GAP_DATA_LENGTH 251

    NRF_SDH_BLE_GAP_EVENT_LENGTH 6 to 320 

    NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247

    SAADC_SAMPLES_IN_BUFFER 4 to 8

    also used

    void conn_evt_len_ext_set(void)
    {
    ret_code_t err_code;
    ble_opt_t opt;

    memset(&opt, 0x00, sizeof(opt));
    opt.common_opt.conn_evt_ext.enable = 1;

    err_code = sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt);
    APP_ERROR_CHECK(err_code);
    }

    yeah increasing NRF_SDH_BLE_GAP_EVENT_LENGTH  and SAADC_SAMPLES_IN_BUFFER

    solved above problem 

    BTW 20kHZ sample rate was able in my project.

    i was just unable to send adc value via ble more rapidly

    so the problem was about throughput am i right?

    there are so much more things i must learn about this stuff !!

    thanks for your help haakonsh

    best regards

    LeeJW

Children
  • LeeJW said:

    BTW 20kHZ sample rate was able in my project.

    i was just unable to send adc value via ble more rapidly

    so the problem was about throughput am i right?

    Yes, definitely. Also, if you want to use the Nordic Uart Service as a transport layer I suggest you don't encode your data into a string representational form, but leave it as int16_t and treat the received string as a binary blob with string termination. NUS is great for prototyping, but I suggest that you create a custom service instead of using NUS. That way you can have a dedicated characteristic for sending raw data, in addition to characteristics for control and meta-data (configurations, start/stop sampling, etc).

    Also, one neat feature of the TIMER peripheral is that you can capture timestamps of your ADC samples. The timestamps are useful if the datastream is interrupted/corrupted as you'll have reliable points of reference for parsing the received data. You'll be able to buffer a few seconds of data in local RAM if the link is interrupted for any reason, or if the link throughput momentarily falls below your datastream throughput requirements. 

    You can start a TIMER at the same point in time as you start a sampling session and periodically capture its value using the same signal that triggers SAADC sampling. A TIMER's CAPTURE task will record its own counter value and place it into one of its 5 CAPTURE/COMPARE registers that can be read by the CPU at a later point. You won't be able to reliably read timestamps with the CPU at 20kHz or even 500Hz, but you can capture timestamps for every 'x' number of samples. F.ex. once per block of samples that will fit inside a BLE payload.

  • thanks for your reply!

    i will try that to my project.

    have a nice day!

    best regards

    LeeJW

Related