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

Questions regarding BLE throughput

Hi. I've seen many questions here regarding BLE throughput, I've been trying to get something better than the 200 B/s I'm getting.

I am using a nrf52832 as a GATT server.

So, I now that if I have write commands instead of write requests, it should improve it a lot. So one of my questions is:

* Does write commands translate to BLE_GATTS_EVT_WRITE events and write requests to BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event with type BLE_GATTS_AUTHORIZE_TYPE_WRITE? It's not really clear.

I have observed that inse the write request struct there is an OPCODE, could an event be triggered with opcode == BLE_GATTS_OP_WRITE_CMD? If so, wouldn't I still need to send a reply?

Another way to improve the data rate is through a higher MTU, I have managed to send commands from the client side and set it to a higher value (243 ATT MTU size), so that leaves 240 bytes of application data right? But I still can't send more than 52 application data bytes per packet, otherwise the MCU gets stuck somewhere before reaching the evt handler. So, my other question is:

* How do I make use of the higher MTU data size I managed to set? Do I need to enable DLE, is that what makes it possible to use more than the 23 byte default size?

Also, regarding long write and reliable write:

* Is long write the same thing as reliable write? If not, what is the difference between each one?

I need to transfer rather large packets to the GATT server, but I have been only able to do so by breaking it apart in chunks of 52 usable bytes per characteristic write (on Android). I have checked the nRF-Toolbox code for sending long writes if the characteristic supports it, I have been able to make my characteristic with the same conditions that lead to the conclusion that we can send a long write, I tried simply sending a long packet from Android, but the MCU crashes at receiving it. I had a MEM_REQUEST evt being handled, but I didn't know what to do beyond replying it.

I needed at least 5kB/s,

Thanks.

  • Hi,

     

    alasknnj said:
    Does write commands translate to BLE_GATTS_EVT_WRITE events and write requests to BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event with type BLE_GATTS_AUTHORIZE_TYPE_WRITE? It's not really clear.

    I recommend taking a look at the different Message Sequence Charts for write commands and write requests.

    For write commands you will get an event BLE_GATTS_EVT_WRITE with opcode BLE_GATTS_OP_WRITE_CMD.

    For write requests the type of event you get will depend on if authorization is used or not. For Write Request with Authorization, you will get BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST with type BLE_GATTS_AUTHORIZE_TYPE_WRITE.

    For Write Request without Authorization, you will get BLE_GATTS_EVT_WRITE with opcode BLE_GATTS_OP_WRITE_REQ

     

    alasknnj said:
    I have observed that inse the write request struct there is an OPCODE, could an event be triggered with opcode == BLE_GATTS_OP_WRITE_CMD? If so, wouldn't I still need to send a reply?

    If you get a BLE_GATTS_EVT_WRITE with opcode BLE_GATTS_OP_WRITE_CMD, then this is a write command. You don’t need to send a response.

    alasknnj said:
    Another way to improve the data rate is through a higher MTU, I have managed to send commands from the client side and set it to a higher value (243 ATT MTU size), so that leaves 240 bytes of application data right? But I still can't send more than 52 application data bytes per packet, otherwise the MCU gets stuck somewhere before reaching the evt handler. So, my other question is:

    * How do I make use of the higher MTU data size I managed to set? Do I need to enable DLE, is that what makes it possible to use more than the 23 byte default size?

    For maximum throughput, you can set the ATT MTU to 247, removing the 3 byte header, you have 244 byte payload per ATT MTU. Make sure that you increase the maximum attribute value length for your characteristic. You should also debug to find the reason why the code gets stuck.See this post.

     

    Snippet:

    ble_gatts_attr_t attr_char_value;
    memset(&attr_char_value, 0, sizeof(attr_char_value));
    
    attr_char_value.max_len = MY_MAX_VALUE; //(244) E.g. NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH

    With DLE you can set the on-air packet size up to 255 bytes, removing the L2CAP and LL header, we are left with 247 bytes. If DLE is not used, the ATT packet will be fragmented into several on-air packets. So for maximum throughput you should also enable DLE.

     

    alasknnj said:
    Is long write the same thing as reliable write?

    They are very similar, but with one additional check when using reliable write. With reliable write each value that is prepared, the “Prepare Write Response” is compared with the request to ensure that the handle and the value in the response is the same as in the request.

    Note that long/reliable write is often very slow, because the client need to wait for the “Prepare Write Response” packet from the server before sending the next “Prepare Write Request”. Write commands and notifications are much faster, and don’t require a response.

     

    alasknnj said:
    I need to transfer rather large packets to the GATT server, but I have been only able to do so by breaking it apart in chunks of 52 usable bytes per characteristic write (on Android).
    • What phone are you using ? What happens if you increase it to more than 52?
    • What SDK and SoftDevice version are you using?
  • How do I enable DLE? I haven't found how to do that yet.

    I am using an Android 7.0 phone. If I change the size to something bigger than 52 bytes, the application crashes (nrf52832) whereas the Android seems to be OK.

    I am using SDK 14.2 and softdevice S132 v5. I am aware there is a newer SDK and softdevice, but I haven't tried them yet.

  • The gatt module in the SDK handles the ATT MTU and DLE request and updates for you.

    Make sure that you have gatt_init(); in your main() function. gatt_init() should call the function nrf_ble_gatt_init(). Make sure that you set NRF_SDH_BLE_GATT_MAX_MTU_SIZE to 247 in sdk_config.h, the DLE will be adjust automatically by the gatt module based on the value of NRF_SDH_BLE_GATT_MAX_MTU_SIZE.

    For maximum throughput you should also make sure that NRF_SDH_BLE_GAP_EVENT_LENGTH in sdk_config.h is set high enough (try to set it to 320).

  • I'm not able to test it now, but I am quite sure I already had those parameters. What is the difference between ble_cfg_t.conn_cfg.params.gap_conn_cfg.event_length and the define NRF_SDH_BLE_GAP_EVENT_LENGTH. I had the config param set to 320, but the define at 20, so I should set the define to 320 also?

    I am calling sd_ble_gap_data_length_update when I receive a BLE_GAP_EVT_CONNECTED, is that appropriate?

    As soon as I am able to test, I will confirm if I had those parameters. I will try to find some more useful things to help.

  • What is the difference between ble_cfg_t.conn_cfg.params.gap_conn_cfg.event_length and the define NRF_SDH_BLE_GAP_EVENT_LENGTH. I had the config param set to 320, but the define at 20, so I should set the define to 320 also

    The define(NRF_SDH_BLE_GAP_EVENT_LENGTH) is just generally what ble_cfg_t.conn_cfg.params.gap_conn_cfg.event_length is set to in nrf_sdh_ble_default_cfg_set().

    ble_cfg.conn_cfg.params.gap_conn_cfg.event_length = NRF_SDH_BLE_GAP_EVENT_LENGTH;



    I am calling sd_ble_gap_data_length_update when I receive a BLE_GAP_EVT_CONNECTED, is that appropriate?

    This is something the GATT module will do for you. On BLE_GAP_EVT_CONNECTED, the gatt module will start ATT MTU exchange and data length update request if necessary(based on the NRF_SDH_BLE_GATT_MAX_MTU_SIZE value)

Related