Arduino BLE - Getting the most out of BLE 5.0 on Artemis

Hi, I’m working on a project that needs to send back-to-back characteristic writes to send a large payload of data (over 1MB) over BTLE. I’m using the Artemis chip, which supports BLE 5.0, including an MTU length up to 512 and an iOS device on the other side that also supports 512 length MTUs.

Along the way I’ve run in to a few troubles.

  1. I can use wireshark to sniff the BLE traffic to see what the MTU length was, but there was no way to see what it was from the code, and if I wrote beyond the length of the negotiated MTU then the left-overs were truncated… See here in wireshark:

image

What I thought would happen is the underlying BLE stack would use multiple packets to send my entire value… but unfortunately it just truncates and gives no error or warning and on the receiving end I get 242 bytes of my transmission only. Is there a solution to this anyone knows of?

I implemented my own that works well in BLEDevice.cpp by making these two additions:

//in BLEDevice.cpp
int BLEDevice::getMtuLength() const
{
	return ATT.mtu(ATT.connectionHandle(_addressType, _address));
}

//in BLEDevice.h
int getMtuLength() const;
  1. Why does ArduinoBLE let you create a characteristic of 512 length if there’s no way to ever use that much length (if it is going to be truncated)? And I’ve tried changing all of the MTU lengths in att.c to 512 and no matter what the negotiated size will be 242 (even when the central size which is running on iOS offers 517 as can be seen in the screenshot above):
//512 is the max you can set this to and I don't know what the difference is between the last two params (valueLength and valueSize)...
BLECharacteristic bigDataChar("f5b64b90-14ed-11ec-82a1-0242ac130000", BLENotify, 512, 512);

Does anyone know what the best way would be to send back-to-back writes to this char and get maximum throughput with ArduinoBLE library?

Here’s what I’ve tried… When the characteristic is subscribed to the event handler for that does this:

void bigDataCharSubscribed(BLEDevice central, BLECharacteristic characteristic) {
  int mtuLength = central.getMtuLength();//My new function I wrote above...

  SerialPrint(F("bigDataCharSubscribed event, subscribed and MTU is: "));
  Serial.println(mtuLength);

  for(int i=0;i<100;i++){
    char tempData[mtuLength];
    char buf[8];
    memset( tempData, 'a', sizeof(char)*mtuLength );
    *(tempData + mtuLength - 8) = '\0';
    itoa(i, buf, 10);
    strcat(tempData,buf);
    Serial.println(i);
    characteristic.writeValue(tempData, strlen(tempData), true);
  }
}

Any other tips for getting the most throughput out of Arduino BLE running on the Artemis?

I can’t see the WireShark picture you tried to include, but some feedback.

First of all, ArduinoBLE is not perfect, but is getting better with every release I have seen.

The ArduinoBLE implementation, to be more correct in ATT INDICATION or NOTIFY, it will copy up to the agreed MTU size - overhead between the central and peripheral. By default, the MTU is 32 bytes, but after the connection has been made it can be negotiated up to 256 bytes. Even though IOS is able to do up to 512, the Bluetooth on the Artemis will only allow up to 256 (HCI_DRV_MAX_TX_PACKET ) From these 256 bytes you need to extract overhead bytes. That is why you end up with a maximum of 242 user bytes.

The upper layers need to break down the larger data packages into skunks and glue them together again on the receiving side. Last winter I had spend good time understanding ArduinoBLE and I am planning to spend more time again this coming winter. I have not posted most off the code yet, but for now, have a look at some of the first code : example10 on https://github.com/paulvha/apollo3/tree … Peripheral. I will show in SendReplyCentral() routine how to breakdown the data if it gets above the default size.

@ricozinn, @paulvha

Me personally i am rather using Mbed and with Arduino i just scratched the surface until now. However using Mbed’s BLE APIs i am disappointed. By that i mean i have a hard time streaming 8-bit values at 512Hz into my Android phone (that is only about 4 kbit/s and even 0.27 Mbit/should be feasable with basic MTU size) and also about 50% of time my phone does not connect to my artemis board.

All these made me courious if ArduinoBLE would be a better solution for BLE centric application?

Do you have any benchmarks about BLE data throughput between 2 Artemis boards that are connected and programmed with ArduinoBLE?

Thanks in advance!

Mbed has embedded the Cordio-BLEstack. When you program BLE with the AMBIQ - SDK (NOT the Sparkfun V2.x library) you use the Cordio BLE. Cordio is very comprehensive as it has been developed over many years (it used to be called Exactle before it was acquired by ARM). It is running on-top-off the BLE driver build by Sparkfun. That said… it is complex and you have to do a lot of initialisation and BLE coding yourself before. Actually when I build an application I spend more time on getting BLE to work than the user application.

When you program BLE with the Sparkfun V2.x library, you use ArduinoBLE and part of the BLE driver from Sparkfun. ArduinoBLE is less complex and less complete than Cordio, it is still relative new. It has issues and bugs (as you can see on their Github page) BUT is easy to use and thus saves a lot (a TON!!) of time on BLE programming. As such you can concentrate mostly on the user program and use BLE as communication channel, instead of becoming the expert on BLE. For most solutions that work with sensors or are less time critical, ArduinoBLE is a great fit.

I have not done performance testing, looks like a good project for the bad weather days. I have already determined that MBED it self (not Cordio) brings a lot of overhead on a solution by comparing it running Sparkfun V1 to Sparkfun V2. Maybe that is already a reason for delays in communication speed.

Thank you both for replies on the topic. I need to figure out how to get alerts when something is posted…

So far I agree that ArduinoBLE is very simple and I can focus more on the application rather than BLE specifically, but this is having its drawbacks.

So have either of you specifically learned how to determine the negotiated MTU length? For my application, I need to be able to determine what length was negotiated so that I can optimize filling each MTU to the right size since as I mentioned previously, anything beyond the negotiated MTU length gets lost, and different devices we test with get different MTU lengths.