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

BLE UART - ble_nus_string_send() connection interval & data transfer

Hey guys,

From what I understand, the minimum connection interval on say, an iPhone, is 20ms. Also, you can send up to 6 packets of 20 bytes within a connection interval. So that's 120 bytes every 20ms.

I've been playing around with the UART peripheral example in SDK 14. I notice that the function ble_nus_string_send() sends a max length of 20 bytes.

What I want to know is how exactly are the data packets and connection interval handled? For example, if I call ble_nus_string_send() once with 20 bytes, will it just go ahead and send the 20 bytes and take up the entire 20ms connection interval?

Consequently, if I call ble_nus_string_send() 6 times with 20 bytes, will all that data transfer within the one connection interval?

Just trying to wrap my head around how this all works. I'll search for some explanations on the SDK and tutorials, but thought it might be more time effective to ask on here.

Thanks!

Parents
  • This calls for wider discussion about "how BLE stack looks and work" but in short:

    • Connection interval is controlled by Master (on Link Layer) aka Central (on GAP layer).
    • Slave (aka Peripheral) can try to negotiate different parameters but it's always Master which decides.
    • As far as I know iOS devices default to 30ms connection interval, only HID applications can get lower.
    • Now because BLE stack is fairly recent and modern so the upper layers (on which you operate = you speak about 20B per packet which corresponds to APP layer bandwidth on top of GATT when (G)ATT uses default MTU length of 23B) act independently on Link Layer. Nordic BLE stack is following this design so you cannot be sure when exactly your GATT packets departure (not only because of LL timing but also because of packet losses and re-transmission) but you simply stack as many of them as possible (= if you have data ready and if your stack support it) and you just get notifications when packets are acknowledged by LL as received by the opposite side.
    • Now the rest is optimization game which you can play if you control at least one part of the link (in this case nRF5x side):
    • If you need maximized throughput then you should use PDU length extension (on Link Layer) and MTU extension (on (G)ATT layer) and you should fine-tune these parameters to the connection interval (surprisingly having long interval with large PDUs might give you better effective throughput then super-short intervals, read some blog posts by Nordic on throughput topic).
    • Finally if you use NUS from Nordic nRF5 SDK then simply make sure that you use the largest (G)ATT MTU size available o the link at given moment and that you push all data you have ready to the SoftDevice (stack) until you get "no TX buffers" error response. Then simply wait for "TX complete" event and continue.

    The biggest problem is that there is no magic set of parameters unless you perfectly control both sides of the link. If you target single mobile device (like iOS devices of certain version) then still you can come up with optimal sequence of steps (like connection parameters change, PDU and MTU extension) but once you want to support more (typically all mobile devices which have BLE capabilities) then you typically need to default to certain "average" configuration (like let the mobile keep its connection interval - 30ms for iOS and 48.75 for Android, try to extend MTU and PDU and just push packets of (MTU-3) size over GATT layer of SoftDevice API (Notifications or Write commands depending on Server/Client role).

    Finally back to Nordi BLE UART Service (NUS) example code in SDK: as you can see from its implementation in \components\ble\ble_services\ble_nus\components\ble\ble_services\ble_nus\ble_nus.c it simply calls sd_ble_gatts_hvx function and returns error/result code from the stack so it's up to you to manage all fragmentation and queuing in your application FW.

Reply
  • This calls for wider discussion about "how BLE stack looks and work" but in short:

    • Connection interval is controlled by Master (on Link Layer) aka Central (on GAP layer).
    • Slave (aka Peripheral) can try to negotiate different parameters but it's always Master which decides.
    • As far as I know iOS devices default to 30ms connection interval, only HID applications can get lower.
    • Now because BLE stack is fairly recent and modern so the upper layers (on which you operate = you speak about 20B per packet which corresponds to APP layer bandwidth on top of GATT when (G)ATT uses default MTU length of 23B) act independently on Link Layer. Nordic BLE stack is following this design so you cannot be sure when exactly your GATT packets departure (not only because of LL timing but also because of packet losses and re-transmission) but you simply stack as many of them as possible (= if you have data ready and if your stack support it) and you just get notifications when packets are acknowledged by LL as received by the opposite side.
    • Now the rest is optimization game which you can play if you control at least one part of the link (in this case nRF5x side):
    • If you need maximized throughput then you should use PDU length extension (on Link Layer) and MTU extension (on (G)ATT layer) and you should fine-tune these parameters to the connection interval (surprisingly having long interval with large PDUs might give you better effective throughput then super-short intervals, read some blog posts by Nordic on throughput topic).
    • Finally if you use NUS from Nordic nRF5 SDK then simply make sure that you use the largest (G)ATT MTU size available o the link at given moment and that you push all data you have ready to the SoftDevice (stack) until you get "no TX buffers" error response. Then simply wait for "TX complete" event and continue.

    The biggest problem is that there is no magic set of parameters unless you perfectly control both sides of the link. If you target single mobile device (like iOS devices of certain version) then still you can come up with optimal sequence of steps (like connection parameters change, PDU and MTU extension) but once you want to support more (typically all mobile devices which have BLE capabilities) then you typically need to default to certain "average" configuration (like let the mobile keep its connection interval - 30ms for iOS and 48.75 for Android, try to extend MTU and PDU and just push packets of (MTU-3) size over GATT layer of SoftDevice API (Notifications or Write commands depending on Server/Client role).

    Finally back to Nordi BLE UART Service (NUS) example code in SDK: as you can see from its implementation in \components\ble\ble_services\ble_nus\components\ble\ble_services\ble_nus\ble_nus.c it simply calls sd_ble_gatts_hvx function and returns error/result code from the stack so it's up to you to manage all fragmentation and queuing in your application FW.

Children
No Data
Related