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

BLE: L2CAP Fragmentation and reassembly

nRF52840, SDK v16.0.0 SD140v7.0.1

Our electrical engineers gave us a hard ATT_MTU limit of 65 bytes, so as to keep the peak current low on the battery for our ultra-low-power IoT device. We can not TX/RX more than 65-byte ATT_MTU per connection interval.

We have a scenario where the most optimal solution would be to have the BLE LL / L2CAP fragment and reassemble data for us, so that we can write ~160 bytes over N connection intervals, but not require application-level awareness of this fragmentation and reassembly. Ideally this ~160 byte payload would appear all at once to the GATT Client running on the Central device.

Is there a way to do this? We see https://devzone.nordicsemi.com/f/nordic-q-a/17860/nrf52832-sdk12-1-extended-mtu-with-and-without-dle, in which Ulrich says

"When you increase the ATT MTU size, you increase the maximum logical length of a complete PDU. If the PDU cannot fit in a single on-air packet, it will be fragmented on the link-layer level. This means that the next on-air packet will have a continuation bit set, and no L2CAP or ATT header, basically saying that what follows should be appended directly onto the PDU you are building. Since the first packet contains the length of the complete PDU, the stack knows when the reassembly is complete. Similarly, if a new packet without the continuation bit is received, all the data will be discarded. This can happen in cases where a more important PDU needs to be sent first. However, each on-air packet will have the LL header. This includes preamble, access address, CRC and MIC (if encrypted)."

This seems close? Is there a way to increase the ATT MTU size to stimulate this link-layer fragmentation while guaranteeing that L2CAP frames will be small enough to meet our power concerns? Even if we can, some Central devices we're pairing with have fixed 23-byte ATT MTU values; is there a way to do fragmentation + reassembly below the application layer in these cases?

We also see the LE Data Length Extension in 4.2, but that looks like it's about transmitting longer on-air packets, which runs against our power requirements.

  • Sorry, to be clear, by

    We have a scenario where the most optimal solution would be to have the BLE LL / L2CAP fragment and reassemble data for us, so that we can write ~160 bytes over N connection intervals, but not require application-level awareness of this fragmentation and reassembly. Ideally this ~160 byte payload would appear all at once to the GATT Client running on the Central device.

    I mean, "so that we can write ~160 bytes over N connection intervals with the ATT_MTU <= 65 bytes". If the Central only supports a 23-byte ATT_MTU, then this would take 160 / 20 = 8 connection intervals.

  • Hi Charles

    In this case it sounds like your best bet is to use LE Data Length Extension, but ensure that you don't set the data length larger than 65.

    Then you can safely set the ATT_MTU to 160 bytes or more, and the link layer will have to fragment a single 160 byte update into multiple on-air packets according to the data length. 

    You might want to set the NRF_SDH_BLE_GAP_EVENT_LENGTH to a low number also, otherwise the SoftDevice will be able to send multiple packets back to back in a single connection event, which could break your peak current constraints set by the electrical engineers.

    If you have central devices that don't support more than 23-byte ATT MTU I must assume these are quite old devices, as longer ATT MTU has been a feature in the specification for a long time?
    In this case you don't really have any choice other than to split the packet into multiple fragments manually, and send 20 bytes at a time. 

    Best regards
    Torbjørn 

  • Thanks for the thorough and fast response, Torbjørn!

    So it sounds like a good strategy is to go for as large of an ATT_MTU as we can get (250?), and then as long as the Data Length is <= 65 we'll get the fragmentation + reassembly for free and keep our EEs happy. They were very excited to learn about the NRF_SDH_BLE_GAP_EVENT_LENGTH field as well, presumably that controls the "transmit window" value?

    I wonder if I misspoke and instead of seeing 23-byte ATT_MTU we're actually seeing 23-byte data length? I'll investigate more; if was a report from a partner of ours.

    Do you know of any resources that catalogue the capabilities of modern Android + iOS handsets? We're using a third-party testing company for handset compatibility and they're doing a great job, but we've also wished for a database somewhere that describes BLE version, max ATT_MTU / Data Length / Connection Interval ranges / Slave Latency / .....

    Charles

  • Hi Charles

    The maximum ATT_MTU you can use is normally 512 bytes, while the maximum data length is 251 (leaving 244 bytes for data once you subtract the 3 byte ATT header and the 4 byte L2CAP header). 

    If your data fits logically in ~160 bytes then I would scale the MTU after this, plus 3 bytes for the ATT header. Using a larger ATT_MTU might provide slightly more efficient communication, depending on how the link layer can split the attribute into multiple 65 byte on air packets, but I don't think the difference would be very significant. 

    The NRF_SDH_BLE_GAP_EVENT_LENGTH can be quite useful, yes, but I don't think it is directly related to any parameters in the Bluetooth specification. The transmit window is related to the first packet in a BLE connection, and is not relevant for subsequent packets in a connection. 

    The number of packets you can send in one connection event is not defined by the Bluetooth specification, other than that it needs to be at least one (obviously), and that you can extend it for as long as both the master and the slave allow by setting the 'more data' bit in the packet header. 

    The NRF_SDH_BLE_GAP_EVENT_LENGTH uses a unit of 1.25ms, and the minimum value is 2, meaning the minimum time you can set is 2.5ms. 

    charles said:
    I wonder if I misspoke and instead of seeing 23-byte ATT_MTU we're actually seeing 23-byte data length? I'll investigate more; if was a report from a partner of ours.

    Typically the minimum data length should be 27 bytes, because this includes the 4 byte L2CAP header on top of the 23 byte minimum attribute MTU. 

    Did they mention which phone(s) they were talking about?

    charles said:
    Do you know of any resources that catalogue the capabilities of modern Android + iOS handsets? We're using a third-party testing company for handset compatibility and they're doing a great job, but we've also wished for a database somewhere that describes BLE version, max ATT_MTU / Data Length / Connection Interval ranges / Slave Latency / .....

    I don't know of any such tool unfortunately. 

    At various times we have thought of doing something like that ourselves, create an app that people can run on their own handsets that would report the capabilities back to the cloud. Then it wouldn't be necessary for any one company or group to acquire every single phone, but it could be a collaborative project between users of the app (assuming they have a Nordic DK available to act as the peripheral device). 
    We might do something like this in the future, but for the time being we don't have any concrete plans for it unfortunately. 

    Best regards
    Torbjørn

  • Hi Charles,

    Let me share my thoughts concerning your case. If 65-byte limitation is quite hard, I'm afraid you should take it into account at application level. As Torbjørn pointed out, miminum event length is 2.5 ms that is quite long, and you have no control over a number of packets sent during a single event, other than restrain SoftDevice's tx queue no more than 65 bytes long. Using large MTU with short data length, you'll probably see two or more fragments sent one-by-one every connection event.

Related