I'm using the nRF52382 with SDK 14.0 and softdevice s132 5.0.0, and I need to send up to hundreds or thousands of kilobytes to an Android phone over BLE. I need to optimize throughput, and I've read all the forum and blog posts I could find, and so I knew generally that I need to send data to the phone using notifications. And I knew that I need to support higher MTU and data length values. Most discussions say to look at the ble_app_att_mtu_throughput example, but that example uses an nRF52 in both roles, so it was hard to know which of that example's approaches still apply when using an Android device in the central role.
I primarily test with a Samsung Galaxy S7 running Android 7.0 and Bluetooth 4.2, so all of my throughput numbers here were recorded with that phone running nRFConnect version 4.17.0.
My baseline functionality left maximum MTU at 23 and used a connection interval of 15ms, and I typically got throughput speeds of about 20kbit/s. To optimize throughput, I've done the following:
- Increase NRF_SDH_BLE_GATT_MAX_MTU_SIZE in sdk_config.h to 247. This requires updating the linker file to allocate more RAM to the softdevice. This also results in data length extension being used, which apparently requires the NRF_SDH_BLE_GAP_EVENT_LENGTH setting in sdk_config.h to be increased from 3 (3.75ms) to 5 (6.25ms).
- Use as low a connection interval as possible. In the last few major Android releases (since Android 6.0 maybe?), this appears to be 11.25ms. But nRFConnect and some Android Bluetooth libraries appear to only allow setting connection interval as low as 15ms, so that's what I currently use.
- Increase NRF_SDH_BLE_GAP_EVENT_LENGTH. I actually don't fully understand this parameter, but trial and error showed that setting this to match my connection interval at 15ms seemed to maximize throughput.
- Disable wifi on the Android device. I believe the antenna is time-multiplexed between wifi and Bluetooth, so disabling wifi apparently allows more time for Bluetooth. Limited testing shows this might've bumped my throughput up by 50kbit/s or more.
With all these, I'm seeing data rates up to about 375kbit/s with my phone right next to my nRF52 board. (I also briefly tested my old Samsung Galaxy S5 with Android 5.1.1 and Bluetooth 4.0 and got throughput of about 100kbit/s.)
And so here are some questions:
- What exactly does the NRF_SDH_BLE_GAP_EVENT_LENGTH setting do? Why does increasing it require more RAM? Is setting it to match my connection interval the right approach? Are there any other connection interval/event length combinations that would increase throughput? I tried setting both to 30ms and 45ms, but it didn't seem to help.
- What sorts of throughput numbers can we expect with an Android device in the central role? The throughput example claims numbers about 2x as fast as I'm seeing with Bluetooth 4.2. Is this expected? What are the limitations?
- Are there any optimizations that I haven't mentioned that I may not already be using? I'm not in a position to test the 2M PHY yet. The throughput example uses the connection event extension feature with longer connection intervals, but I read somewhere that that is actually a Nordic feature rather than a Bluetooth spec feature, so my understanding is that I can't use that feature with an Android device.
- With these settings (MTU of 247, data length of 251, connection interval of 15ms, event length of 15ms), throughput is actually _very_ erratic and _heavily_ dependent on signal strength. Is it my imagination, or is it possible for throughput to actually drop below throughput of some lower performance configurations in some poor signal strength scenarios? If it's possible to sacrifice some throughput for better stability, what would be the best approach?