BLE data packet drop during transmission

.Hi Nordic Support team,

I'm using NRF52832, SoftDevice S132, SDK version is nRF5_SDK_17.1.0_ddde560.

I want to transmit 9 bytes of data collected from an I2C sensor every 2.5ms via BLE. The sensor has an internal buffer so I can queue up to 288 bytes (80ms from empty to full sensor buffer). However, I2C can only receive 255 bytes per queue, so I only collect data from the sensor every 60ms, because for 60ms, the sensor produces 216 bytes of data and it is within 1 MTU packet ( configure it to be 247 bytes per MTU). That means I will send 1 MTU every 60ms. That means I only need a connection interval of 60ms. Am I correct?

In my BLE structure, I also have another different characteristic that reports the device temperature (takes only 2 bytes) every 10 seconds (yes, second not milliseconds). However, from my experiment, 60ms cannot keep up with this data rate from both characteristics. Do I misunderstand anything? Should I use the connection event extension length? 

Here are my BLE parameters: NRF_SDH_BLE_GAP_EVENT_LENGTH is 6. TX queue length is 1. Min connection interval = Max connection interval = 60ms. Save lantecy is 4.

I also have tried to increase the TX queue length to 18. Set Min connection interval = 30ms, Max connection interval = 120ms, enable Connection Event Length Extension by the following code right after ble_advertising_init. However, I still occasionally get NRF_ERROR_RESOURCES from sd_ble_gatts_value_set(p_cus->conn_handle, p_cus->data_char_handles.value_handle, &gatts_value);

What I am trying to do is optimize power consumption while also ensuring absolutely NO data loss via BLE transfer.

// Connection Event Length Extension
ble_opt_t  opt;

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

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

Please let me know if I do anything wrong. 

Best regards,

Xander

Parents
  • Hi Xander,

    I want to transmit 9 bytes of data collected from an I2C sensor every 2.5ms via BLE. The sensor has an internal buffer so I can queue up to 288 bytes (80ms from empty to full sensor buffer). However, I2C can only receive 255 bytes per queue, so I only collect data from the sensor every 60ms, because for 60ms, the sensor produces 216 bytes of data and it is within 1 MTU packet ( configure it to be 247 bytes per MTU). That means I will send 1 MTU every 60ms. That means I only need a connection interval of 60ms. Am I correct?

    It is weird that the sensor can queue 288 bytes, but only allow 255 bytes read at a time.

    Otherwise, this seems correct. 

    In my BLE structure, I also have another different characteristic that reports the device temperature (takes only 2 bytes) every 10 seconds (yes, second not milliseconds). However, from my experiment, 60ms cannot keep up with this data rate from both characteristics. Do I misunderstand anything? Should I use the connection event extension length? 

    You don't have to worry about connection event length, but you should use Data Length Extension (DLE), because the amount of overhead at that data size is too much.

    However, 60ms should be more than enough to transmit 216 bytes, with or without DLE. So, something is not right here.

    To change GAP Data Length, you can change NRF_SDH_BLE_GAP_DATA_LENGTH in sdk_config.h.

    Here are my BLE parameters: NRF_SDH_BLE_GAP_EVENT_LENGTH is 6. TX queue length is 1. Min connection interval = Max connection interval = 60ms. Save lantecy is 4.

    I also have tried to increase the TX queue length to 18. Set Min connection interval = 30ms, Max connection interval = 120ms

    For this, I would like to reuse my answer in another case:

    Furthermore, please know that this is just what the peripheral "proposes" to the central device. It is still the central device that decides the actual connection interval. To debug what the actual connection interval is, please check the GAP events.

    At the beginning of a connection, BLE_GAP_EVT_CONNECTED is received, and the connection parameters can be found in ble_evt_t.ble_gap_evt_t.connected.

    After that, the connection parameters may be updated, BLE_GAP_EVT_CONN_PARAM_UPDATE is received, and the connection parameters can be found in ble_evt_t.ble_gap_evt_t.conn_param_update.

    Furthermore, in BLE, packets cannot be dropped. If a packet is drop, the connection itself is also dropped, so if you don't see a disconnection, but data is lost, then it might indicate a problem with preprocessing the data to be sent, or postprocessing the data received. 

    Hieu

  • Hi Hieu,

    It is weird that the sensor can queue 288 bytes, but only allow 255 bytes read at a time.

    I mean the NRF52832 has the I2C queue limits to 255 bytes. The sensor has no such limitation.

    However, 60ms should be more than enough to transmit 216 bytes, with or without DLE. So, something is not right here.

    I just simplified the real scenario. In my app, I poll the sensor every 60ms, returning 216 bytes. However, I hold them in a buffer and wait until the buffer size exceeds 243 bytes since this is the nearest multiple of 9 smaller than MTU size 247 bytes (I verified this number from the connection event). Therefore, the first time the 60ms timer is timeout, there won't be any MTU packet being sent (216 bytes < 243 bytes). But the second time timer timeout, 243 bytes of data from the buffer will be sent (with some remaining data left which will be sent from the third time timer timeout,... ). However, I don't think this won't be an issue as there cannot be any timeout 2 MTU packets will be sent.

    You don't have to worry about connection event length, but you should use Data Length Extension (DLE), because the amount of overhead at that data size is too much.

    Where can I find an example of how to use DLE?

    To debug what the actual connection interval is, please check the GAP events.

    GAP events look fine to me. By the way, 1 interesting I found on this screenshot is on the line "Peer on connection 0x0 requested an ATT MTU of 527 bytes.". Does this mean the other device (my PC) have requested 523 bytes? I believe NRF52832 won't support this high MTU size so both ends agree at 247 bytes MTU size? 

    Connection intervals look correct to me as well from debug message as well.

    Furthermore, in BLE, packets cannot be dropped. If a packet is drop, the connection itself is also dropped, so if you don't see a disconnection, but data is lost, then it might indicate a problem with preprocessing the data to be sent, or postprocessing the data received. 

    We currently don't do APP_ERROR_CHECK() for any data written to the BLE queue buffer because we believe this data rate must be able to handle these BLE parameters. I think data loss will happen because we ignore the NRF_ERROR_RESOURCES, which indicates data cannot be queued in the BLE TX queue.

    By the way, it's nice to meet a Viet guy on this forum Handshake

  • Hi Xander,

    What function is returning NRF_ERROR_RESOURCES? I know in your opening post, you said sd_ble_gatts_value_set(), but according to documentation, that function doesn't return NRF_ERROR_RESOURCES.

    Best regards,

    Hieu

  • Hi Hieu,

    Sorry for my mistake. It should be the function sd_ble_gatts_hvx, which means I cannot queue more in TX queue right?

    Best regards,

    Xander

  • Hi Xander,

    Yes, sd_ble_gatts_hvx() returning NRF_ERROR_RESOURCES means that the queue is full.

    The documentation of the function contains some note on this exact error. It might give more insight it to check the relevant Message Sequence Charts as well.

    With such information in mind, please try to analyze the code and run some testing to see if there are anything unexpected.

    Our colleague Hung discussed a little about handling the notification queue in this DevZone case as well:  sd_ble_gatts_hvx returns NRF ERROR RESOURCES while transferring bytes .

    Best regards,

    Hieu

  • Hi Hieu,

    I have checked Hung's suggestion. However, it still doesn't explain why I have a queue-being-full issue.

    TX queue size is 18, which still causes this error, meaning the BLE cannot keep up with the data rate I require. So I think it's something in BLE parameters I need to reconfigure, instead of keep tracking the remaining slots in the queue. So I want to understand the mismatch between my calculation and the actual behaviour of BLE. Because I thought NRF_SDH_BLE_GAP_EVENT_LENGTH is 6, MTU size = 247 bytes, min connection interval = max connection interval = 60ms and slave latency is 4 should be adequate for 216 bytes every 60ms + 2 bytes every 10 seconds.

    Best regards,

    Xander

  • Maybe try testing in a clean BLE- WiFi- etc- free environment and see if the problem goes away; Radio congestion leads to multiple attempts to send BLE packets until they succeed, which means some transmission effective rates are much slower than expected (in periodic intervals) and hence NRF_ERROR_RESOURCES error follows. Typically fix by using much larger intermediate buffers for packets than expected.

    NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC event and retry.

Reply
  • Maybe try testing in a clean BLE- WiFi- etc- free environment and see if the problem goes away; Radio congestion leads to multiple attempts to send BLE packets until they succeed, which means some transmission effective rates are much slower than expected (in periodic intervals) and hence NRF_ERROR_RESOURCES error follows. Typically fix by using much larger intermediate buffers for packets than expected.

    NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC event and retry.

Children
  • Hi Hmolesworth,

    Should I increase NRF_SDH_BLE_GAP_EVENT_LENGTH  first or should I lower the connection interval first? Which one is better for low-power consumption applications?

    Best regards,

    Xander

  • Hi Xander,

    NRF_SDH_BLE_GAP_EVENT_LENGTH is better for power concern.

    Lowering the connection interval usually increases power consumption.

    However, are you sure NRF_SDH_BLE_GAP_EVENT_LENGTH is 6? From your log, GAP Data Length was successfully updated to 251.

    Best regards,

    Hieu

  • Hi Hieu,

    I'm a bit confused here. I thought the NRF_SDH_BLE_GAP_EVENT_LENGTH  is a parameter of NRF that won't need to be negotiated between NRF and other peers. So if I set 6, it means 6 will be applied no matter what. But you said:

    From your log, GAP Data Length was successfully updated to 251.

    I though 251 is like MTU packet size and has nothing to do with GAP event length. Can you please explain this to me?

    I'm also confused with "Connection Event Length Extension". Does it extend the connection interval when there is less data to transmit to save power, or does it spend more time sending data per connection interval?

    Best regards,

    Xander

  • Hi Xander,

    Xander To said:

    I'm a bit confused here. I thought the NRF_SDH_BLE_GAP_EVENT_LENGTH  is a parameter of NRF that won't need to be negotiated between NRF and other peers. So if I set 6, it means 6 will be applied no matter what. But you said:

    From your log, GAP Data Length was successfully updated to 251.

    I though 251 is like MTU packet size and has nothing to do with GAP event length. Can you please explain this to me?

    My apology. I read NRF_SDH_BLE_GAP_EVENT_LENGTH but in my head I perceived NRF_SDH_BLE_GAP_DATA_LENGTH for some reasons.

    Update: The following crossed out information about Connection Event (Length) is incorrect. See my next reply for the correct information.

    But Event Length is also a part of the connection parameter negotiation, and the value you give is not the value that will be applied no matter what.

    In most common cases, the negotiated value will be the lower one between the two peers, and modern smart phones usually are capable of higher length, thus make the Event Length effectively the value you set with NRF_SDH_BLE_GAP_EVENT_LENGTH.

    Xander To said:
    I'm also confused with "Connection Event Length Extension". Does it extend the connection interval when there is less data to transmit to save power, or does it spend more time sending data per connection interval?

    With "Connection Event Length Extension," the Connection Interval is not extended. The Connection Event within the Interval is extended. It's technically "spending more time sending data per connection interval."

    For more information, see Connection timing with Connection Event Length Extension.

    Best regards,

    Hieu

  • Hi Hieu,

    Is there any way to verify the negotiated NRF_SDH_BLE_GAP_EVENT_LENGTH value? 

    Best regards,

    Xander

Related