BLE notification takes too long

Hello everyone,

I'm developing an application for an nrf52840 with the nrf connect VS Code extension.

The application runs three threads. One to acquire 40 bytes of data from a sensor at a frequency of 400Hz, another to process those data, and a third to send the result through BLE notifications.

It is important to note that I shouldn't lose the synchronization with the sensor for the processing but I can send the processed data slower. Therefore I configured the BLE like this : 

CONFIG_BT=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_PERIPHERAL=y

CONFIG_BT_USER_DATA_LEN_UPDATE=y

CONFIG_BT_ATT_PREPARE_COUNT=9
CONFIG_BT_BUF_ACL_TX_COUNT=9
CONFIG_BT_BUF_ACL_RX_SIZE=47
CONFIG_BT_CTLR_DATA_LENGTH_MAX=47
CONFIG_BT_L2CAP_TX_MTU=47
CONFIG_BT_BUF_ACL_TX_SIZE=47
CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT=7812
If my calculations are good, it should take 868µs to send a packet. But when I measure the time taken by the bt_gatt_notify it is around 20ms. 
This slows all of my processes and therefore makes the FIFOs which are in charge of passing the data from one thread to another filled very quickly.
The FIFO is filled like this : 
size_t size = sizeof(struct raw_tx_buf);
char *raw_mem_ptr = k_malloc(size);
__ASSERT_NO_MSG(raw_mem_ptr != 0);

memcpy(raw_mem_ptr, &raw_tx, size);

k_fifo_put(&raw_tx_fifo, raw_mem_ptr);
And read like this : 
struct raw_tx_buf *raw_buf = k_fifo_get(&raw_tx_fifo,K_FOREVER);

bt_gatt_notify(NULL,&mcd_svc.attrs[2],raw->raw_data,sizeof(raw->raw_data);

k_free(raw_buf);
If I can't make the notification function go faster, how can I prevent the overfilling of the FIFO which makes everything crash ?
Thanks in advance for your answer.
Parents
  • Hello,

    If my calculations are good, it should take 868µs to send a packet. But when I measure the time taken by the bt_gatt_notify it is around 20ms. 

    To easily verify the on-air time it will take to send a packet you can use the Online Power Profiler, for instance :) 
    The reason why you are seeing 20 ms here is likely that it is the Connection Interval used for the connection where the data is sent.
    The shortest possible Connection Interval for BLE communication is 7.5 ms, which would mean that you on average will send 120 bytes every connection event (7.5 ms).
    Your buffer will need to be able to store this, and potentially some additional packets of this size in case multiple packets of this size suddenly is sent in a single connection event due to a previous packet loss, for instance. 
    How large is your receiving buffer currently?
    Is this a central or peripheral device you are developing?

    Best regards,
    Karl

  • Hello, thank you for your answer.

    I thought I configured the connection interval to be 7812us (which I believe is the time to let 9 packet be exchanged on each connection event) with CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT. Is it the right way to do it ?

    My device is a peripheral and I use the Nordic connect mobile app as a central. Therefore I don't know the size of the app buffer. 

    Best regards,

    Natan 

  • Ok thank you I understand better and after reading zephyr documentation it says that the default connection interval is 30ms so that matches.

    Regarding the buffer overflow, I don't really see it because it crashes down and reboot when I try to send the data.

    I tried with a lower acquisition frequency and it goes without a problem. that's what led me to think the buffer is overflowing because it gets filled faster than the sending function can empty it.

  • Do you have logging enabled for your project?
    If so, the error code should be printed before it resets due to the returned error.
    You could then implement local specific error handling for the function that returns the error.

    I would then also recommend considering to create a ring buffer that can be used to cache the sensor data that fails to be queued, so that you do not loose it.
    This buffer should be big enough to accommodate all the data that could build up before the connection supervision timeout occurs.
    Dropped packets are also the reason why you should make sure that your connection event length is longer than what is needed to send a single sensor measurement, since you might need to re-send built-up packets from previously lost packets in addition to the new samples.
    How long is the duration of the connection supervision timeout in your application?

    Best regards,
    Karl

  • Ok i see, the connection supervision timeout is still at default value so 4s I guess.

  • Yes - you can change this to match the requirements of your application.
    But, assuming 4 s Connection Supervision Timeout means that you could potentially have 40*400*4 = 64 kB of unsent data when the connection times out.
    In the worst case scenario (with a really poor connection) you could only be getting through a packet every ~4s, which could cause your ring buffer to overflow as well, but in this case the connection is basically lost for all communication purposes.

    Does the data ever 'expire'? / does there ever come a point from which the data no longer is useable to the central?
    If so, you should change the supervision timeout to match this requirement, or have the ring buffer start to overwrite unuseful data as soon as this happens.

    Best regards,
    Karl

  • Yes, from what I understood when the FIFO is read, the data is supposed to be removed from it. And after sending the data I use k_free to free the memory of the allocated before with k_malloc.

    So after sending there shouldn't be data anymore on the peripheral.

Reply Children
No Data
Related