Cordio BLE not supporting max/min connection event length

i tried to make some experiments with my artemis thing board plus boards from sparkfun for measuring the maximum troughput from a central and a peripheral device implemented using cordio stack with WDXC_ENABLED/WDXS_ENABLED, and i found that the min/max connection event lenght parameters specified in the connection specification type struct (corresponding to minCELen/maxCELen in hciConnSpec_t, respectively) are not taking into consideration neither in the connection creation nor the connection parameters update, so only one packet is sent per connection event, and as a consequence, the maximum througput is very poor. Is that corrrect?. Does Cordio support the specification of min/max ce lenght?. I would really appreciate any help or any comment related to other experiments regarding this issue.

Hi @ftobajas, the minimum/maximum connection length events are informative according to the specification. Support will depend on the controller hardware and software.

Hi @vcoubard ! … thanks a lot for your answer … so for the particular case of cordio stack, does it support the definition of minimum/maximum connection length parameters? … in case it doesn’t, the max achievable throughput using this BLE stack is limited to hundred kbps! … at least according to the experimental results i obtained from my experiments using cordio stack with WDXC_ENABLED/WDXS_ENABLED.

@ftobajas The Cordio stack in Mbed is an host stack, it is communicates with a controller which handles minimum and maximum connection length event. Performances will depends on the controller used.

On NRF52 platforms, the controller stack is also provided by Cordio. I can check how connection length is handled but ultimately, throughput will depends on many factors including capabilities at the receiving end, the connection interval, or the transport being used (1Mbps or 2Mbps). One of the major issue with BLE API is the non exposition of data length extension.

I remember I was able to send 8 packets in a single connection event on NRF52840 to another NRF52840.

Could you provide more details about your use case ?

Hi @vcoubard … i really apporeciate your support. In my particular case, i am using 2 sparkfun artemis_thing_plus boards, which integrate the Artemis module from Sparkfun. The core of this module is the Apollo3 Blue microprocessor from Ambiq. I’ve programmed one of the artemis_thing_plus boards to act as a central device, and the other one to act as a peripheral device by using AmbiqSuiteSDK, whis is based on cordio stack (see /thirdparty/exactle subdirectory). My aim is to measure the max achivable BLE throughput between these boards with WDXC_ENABLED/WDXS_ENABLED (Wireless Data Exchange Profile).

For this purpose, i defined in the central device a 4s (DATC_WDXS_DATA_RATE_TIMEOUT) timer, and the following function is called once it expires:

 *  \brief  Calculate the data rate.
 *  \param  connId    Connection identifier.
 *  \return None.
static void datcWdxcProcessDataRateTimeout(dmConnId_t connId)
  uint32_t bps;
  uint32_t packets;

          APP_TRACE_INFO0("*** datcWdxcProcessDataRateTimeout.");

  /* Suppress warning when APP_TRACE disabled */
  (void) bps;

  /* Calculate data rate */
  bps = (datcCb.rxCount[connId-1] - datcCb.lastCount[connId-1]) * 8 / DATC_WDXS_DATA_RATE_TIMEOUT;
  datcCb.lastCount[connId-1] = datcCb.rxCount[connId-1];

  datcCb.streamSeconds[connId-1] += DATC_WDXS_DATA_RATE_TIMEOUT;
  datcCb.streamRate[connId-1] = datcCb.rxCount[connId-1] * 8 / datcCb.streamSeconds[connId-1];

  APP_TRACE_INFO2("Streaming data rate %d bps, overall %d bps", bps, datcCb.streamRate[connId-1]);
  am_menu_printf(" -- Streaming packets = %d, data rate %d bps, overall %d bps\r\n", packets, bps, datcCb.streamRate[connId-1]);

  /* Restart the timer */
  datcCb.dataRateTimer[connId-1].msg.event = DATC_WDXS_DATA_RATE_TIMER_IND;
  datcCb.dataRateTimer[connId-1].msg.param = connId;
  datcCb.dataRateTimer[connId-1].handlerId = datcCb.handlerId;

  WsfTimerStartSec(&datcCb.dataRateTimer[connId-1], DATC_WDXS_DATA_RATE_TIMEOUT);

with datcCb.rxCount[connId-1] being updated each time a wdx packet is received from the peripheral device:

 *  \brief  WDXC File Transfer Data Callback.
 *  \param  connId    Connection ID.
 *  \param  fileHdl   Handle of the file.
 *  \param  len       length of pData in bytes.
 *  \param  pData     File data.
 *  \return None.
static void datcWdxcFtdCallback(dmConnId_t connId, uint16_t fileHdl, uint16_t len, uint8_t *pData)
  datcCb.rxCount[connId-1] += len;

However, the experimental results i have obtained by now, show a data rate which apparently is limited by the reception of 1 MTU packet per connection interval, i.e. with a connection interval of 100 (125ms) and MTU=241bytes, i obtain a data rate around 15232 bps, which represents 32x241bytes for a 4s time interval, and apparently implies the reception of 241 bytes per connection interval.

But today i used an sniffer in order to capture the packets transferred between the central and the peripheral device in this use case, and from the wireshark image below, up to 10 packets are transferred per connection interval, but they are L2CAP Fragment packets with a maximun size of 52 bytes … does it make sense?


Hi @vcoubard … any suggestion with this issue? … i checked from hci_core.c code, that the packets are not fragmented, so were could be the problem? … any help will be appreciated. thanks.

I have read your posts also on Sparkfun forums so i know you are trying several BLE stacks…
I am a complete rookie in regards of programming Bluetooth and i am currently still quite confused with the Cordio stack…
As Mbed dropped BLE support for the MAX32630FTHR boards since OS V6.0 i had to look for some other stack and i found this stack. Took me 2 days to figure out how to run the examples on the MAX32630 but i get around 230KB/s constant payload between 2 boards. Actually with Bluetooth classic as this stack also supports dual-mode chips!

More important for you is that this stack comes with a port for the apollo2 chip, but that chip has the very same em9304 BLE chip as the Apollo3 has…so maybe this stack would work also on our Artemis Thing Plus boards. Even the payload throughput might be higher than with the Cordio stack…though i did not try it myself.

Digging deeper i found AmbiqSuite\third_party\cordio\ble-host\sources\hci\ambiq\apollo3\hci_drv_apollo3.h which has this in the 5th line: //! @brief Support functions for the Nationz BTLE radio in Apollo3

So the Bluetooth chip in Apollo3 is not an EM9304 and the stack i proposed does not work with Apollo3.

@ftobajas The packets are fragmented by the controller. The GATT MTU size is not always equal to the L2CAP PDU size. To increase the L2CAP PDU, the data length extension must be used. It is not accessible in Mbed API today but it can be accessed in the Cordio API.

Can you share your wireshark trace ?

These blog posts are interresting to understand the impact on changing the GATT MTU and data length extension.