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,

    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

  • Hi Xander,

    Xander To said:

    Your log here shows the negotiated Connection Event Length. nrf_ble_gatt.c has the parameter logged at L315-L322. The unit is us.

    Please try to tune the Connection Event Length to see if there are any differences. But as noted before, the Connection Event Length, Connection Interval, Data Length are all ultimately decided by the central devices. If the central device in your case are smart phones/tablets, then you should setup your device to be as flexible as possible. In your case, that would be handling NRF_ERROR_RESOURCES from sd_ble_gatts_hvx() gracefull, and deriving a fallback/failsafe mechanism in case the BLE connection cannot consume data from the sensor fast enough (discard oldest data, or newest data, and/or include a notification that data was not consumed quickly enough).

    Best regards,

    Hieu

Reply
  • Hi Xander,

    Xander To said:

    Your log here shows the negotiated Connection Event Length. nrf_ble_gatt.c has the parameter logged at L315-L322. The unit is us.

    Please try to tune the Connection Event Length to see if there are any differences. But as noted before, the Connection Event Length, Connection Interval, Data Length are all ultimately decided by the central devices. If the central device in your case are smart phones/tablets, then you should setup your device to be as flexible as possible. In your case, that would be handling NRF_ERROR_RESOURCES from sd_ble_gatts_hvx() gracefull, and deriving a fallback/failsafe mechanism in case the BLE connection cannot consume data from the sensor fast enough (discard oldest data, or newest data, and/or include a notification that data was not consumed quickly enough).

    Best regards,

    Hieu

Children
Related