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

(nRF52832 / SDK 14.0 / s132 5.0.0) Optimizing BLE throughput between nRF52 (peripheral) and Android device (central)

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:

  1. 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.
  2. 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?
  3. 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.
  4. 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?
Parents
  • Hi Sydney!

    I also would like to measure throughput between my phone and an nrf board.

    Could you please describe me how you did this test?

    Which android app did you use, which nordic example did you use, what modification did in the example if needed, and please describe the process of the throughput test.

    Thank You,

    Kalman

  • Hi Kalman,

    Unfortunately my code is pretty far removed from the examples at this point so I'm not sure I can help you set up any of the nRF52 examples to transfer data to an Android phone. All of the testing I described in my original post was based on my custom firmware. And unfortunately I didn't write the early stages of the data transfer code so I'm not sure which example(s) the code was originally based on. But it essentially just queues and sends notifications as quickly as possible, with each notification containing some number of bytes as determined by the negotiated MTU size.

    That said, I measure throughput between an nRF52 running our firmware and an Android phone in two ways. The simplest way is to put a known amount of data on my nRF52 device, transfer that known amount of data to my Android phone, and time the transfer with a stopwatch or something similar. So if I have 512 kilobytes of data to transfer and I time the transfer at 16 seconds, that's 32 kilobytes per second or 256 kilobits per second.

    I also track time and bytes transferred in my nRF52 firmware, so I calculate and log throughput in real time during transfers. This is probably the most accurate way I measure, but I can only access the logging output if I can physically access the debug connector on the board, which isn't always the case. (Similarly, I'd think if you're writing your own Android application, it should be pretty easy to calculate throughput on the Android side.)

    We do most of our testing with our own internally developed Android application, but I also test with the Android version of nRF Connect pretty extensively.

    To test with nRF Connect, most of the process is going to be specific to firmware's custom data transfer implementation, unfortunately. Essentially you'd need to connect to your nRF52 with nRF Connect, subscribe to notifications (in nRF Connect) on whichever characteristic(s) will be sending your data, and then do whichever action you've designed your device to initiate the data transfer. This could be a button press, Android writing a specific sequence of characteristics to your device, a timer, etc. After connecting but before initiating the transfer, you'll probably want to request a higher connection priority in nRF Connect. This will lower the connection interval, allowing notifications to be sent more often, speeding up your throughput.

Reply
  • Hi Kalman,

    Unfortunately my code is pretty far removed from the examples at this point so I'm not sure I can help you set up any of the nRF52 examples to transfer data to an Android phone. All of the testing I described in my original post was based on my custom firmware. And unfortunately I didn't write the early stages of the data transfer code so I'm not sure which example(s) the code was originally based on. But it essentially just queues and sends notifications as quickly as possible, with each notification containing some number of bytes as determined by the negotiated MTU size.

    That said, I measure throughput between an nRF52 running our firmware and an Android phone in two ways. The simplest way is to put a known amount of data on my nRF52 device, transfer that known amount of data to my Android phone, and time the transfer with a stopwatch or something similar. So if I have 512 kilobytes of data to transfer and I time the transfer at 16 seconds, that's 32 kilobytes per second or 256 kilobits per second.

    I also track time and bytes transferred in my nRF52 firmware, so I calculate and log throughput in real time during transfers. This is probably the most accurate way I measure, but I can only access the logging output if I can physically access the debug connector on the board, which isn't always the case. (Similarly, I'd think if you're writing your own Android application, it should be pretty easy to calculate throughput on the Android side.)

    We do most of our testing with our own internally developed Android application, but I also test with the Android version of nRF Connect pretty extensively.

    To test with nRF Connect, most of the process is going to be specific to firmware's custom data transfer implementation, unfortunately. Essentially you'd need to connect to your nRF52 with nRF Connect, subscribe to notifications (in nRF Connect) on whichever characteristic(s) will be sending your data, and then do whichever action you've designed your device to initiate the data transfer. This could be a button press, Android writing a specific sequence of characteristics to your device, a timer, etc. After connecting but before initiating the transfer, you'll probably want to request a higher connection priority in nRF Connect. This will lower the connection interval, allowing notifications to be sent more often, speeding up your throughput.

Children
No Data
Related