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

Maximizing UART over BLE throughput

Hi,

I have a question regarding our approach to achieving high throughput UART transmission over BLE.

The protoboards we are currently testing have BL654 modules from Laird which use the nRF52840 SoC with the following setup:
 - nRF5SDK v16.0.0
 - Soft Device s140 v7.0.1
 - Segger embedded studio IDE
 - MSP432 communicating with BL654 via UART <-> BL654 communicating with gateway SBC

We have tested "ble_app_att_mtu_throughput" and have been able to achieve ~340Kbps between two nrf52840 DK boards with the default configuration as listed here. This is a reasonable speed using 2Mbps PHY. Of course we were hoping to achieve maximum throughput (~1Mbps) line-of-sight using UART profile as was done in the nRF52 image transfer demo.

The sample code we have modified to transfer high-density sensor data (~100kB) from a wireless sensor to a gateway were based on: 
 - ble_app_uart_c (gateway)
 - ble_app_uart (sensor)

The host microcontroller is sending ~100kB of binary data via UART to the BLE module at max 460800 baud 8N1, which is still taking ~40 seconds to send. Repeating the test using two DK's and sending a binary file via realterm takes approximately the same time. Obviously this is a bit longer than the expected 3 seconds (800K bits / 340Kbps = 2.5 seconds). However, this may due to the fact that the only code modification we have made thus far is to set the PHY from auto to 2Mbps which has not yielded any different throughput results.

            NRF_LOG_DEBUG("PHY update request.");
            ble_gap_phys_t const phys =
            {
                .rx_phys = BLE_GAP_PHY_2MBPS, /* was BLE_GAP_PHY_AUTO - 4-22-20 */
                .tx_phys = BLE_GAP_PHY_2MBPS, /* was BLE_GAP_PHY_AUTO - 4-22-20 */
            };
            err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
            APP_ERROR_CHECK(err_code);

Not being a BLE expert myself, I would likely proceed by diff'ing the projects, (ble_app_att_mtu) and (ble_app_uart), and modifying ble_app_uart configuration to achieve a higher throughput. Is this a good approach? Assuming the setup which was described above, what do you suspect is the highest possible throughput using the Nordic UART profile? 

We have not yet implemented flow control (RTS/CTS) but are in process of doing so due to dropped packets we are seeing and, if ultimately necessary, we could transmit data from our sensor's host processor to BL654 via SPI for increased speed. Any additional advice or examples would be much appreciated.

Thank you for your assistance.

Regards,

Rob

Parents
  • We have tested "ble_app_att_mtu_throughput" and have been able to achieve ~340Kbps between two nrf52840 DK boards with the default configuration as listed here. This is a reasonable speed using 2Mbps PHY. Of course we were hoping to achieve maximum throughput (~1Mbps) line-of-sight using UART profile as was done in the nRF52 image transfer demo.

     The default GAP data length in the Throughput example is 27, so oncreasing the GAP data length should result in a higher throughput.

    Not being a BLE expert myself, I would likely proceed by diff'ing the projects, (ble_app_att_mtu) and (ble_app_uart), and modifying ble_app_uart configuration to achieve a higher throughput. Is this a good approach? Assuming the setup which was described above, what do you suspect is the highest possible throughput using the Nordic UART profile? 

    Yes, comparing the two projects and using the same settings as the Throughput example in the ble_app_uart example is a good approach.  

    The ble_app_uart example uses notifications to send the data from the peripheral to the central. Looking at the Bluetooth Low Energy data throughput in the S140 SoftDevice Specification, the highest achievable throughput with a single connection,  ATT MTU = 247, GAP data length = 251 and a connection interval of 50ms is 1327kbps with the 2M Phy and 702,8kbps with the 1M Phy

    Best regards

    Bjørn

Reply
  • We have tested "ble_app_att_mtu_throughput" and have been able to achieve ~340Kbps between two nrf52840 DK boards with the default configuration as listed here. This is a reasonable speed using 2Mbps PHY. Of course we were hoping to achieve maximum throughput (~1Mbps) line-of-sight using UART profile as was done in the nRF52 image transfer demo.

     The default GAP data length in the Throughput example is 27, so oncreasing the GAP data length should result in a higher throughput.

    Not being a BLE expert myself, I would likely proceed by diff'ing the projects, (ble_app_att_mtu) and (ble_app_uart), and modifying ble_app_uart configuration to achieve a higher throughput. Is this a good approach? Assuming the setup which was described above, what do you suspect is the highest possible throughput using the Nordic UART profile? 

    Yes, comparing the two projects and using the same settings as the Throughput example in the ble_app_uart example is a good approach.  

    The ble_app_uart example uses notifications to send the data from the peripheral to the central. Looking at the Bluetooth Low Energy data throughput in the S140 SoftDevice Specification, the highest achievable throughput with a single connection,  ATT MTU = 247, GAP data length = 251 and a connection interval of 50ms is 1327kbps with the 2M Phy and 702,8kbps with the 1M Phy

    Best regards

    Bjørn

Children
  • Hi,

    I have tested the ble_app_att_mtu code and achieved 1327 kbps as referenced in the link sent.

    However, I am having difficulty achieving increased throughput using the ble_app_uart project. I diff'd the projects and reviewed the code extensively.

    Here are the few modifications I have made for ble_app_uart:

    BLE_APP_UART
    --------------------------------------------------------
    # sdk_config.h
    --------------------------------------------------------
    // <i> Requested BLE GAP data length to be negotiated.
    #ifndef NRF_SDH_BLE_GAP_DATA_LENGTH
    #define NRF_SDH_BLE_GAP_DATA_LENGTH 251
    #endif
    --------------------------------------------------------
    // <o> NRF_SDH_BLE_GATT_MAX_MTU_SIZE - Static maximum MTU size. 
    #ifndef NRF_SDH_BLE_GATT_MAX_MTU_SIZE
    #define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247
    #endif
    
    --------------------------------------------------------
    # main.c
    --------------------------------------------------------
    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(50, UNIT_1_25_MS)             /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(50, UNIT_1_25_MS)             /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
    --------------------------------------------------------
    static uint16_t   m_ble_nus_max_data_len = NRF_SDH_BLE_GATT_MAX_MTU_SIZE - 3;       /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
    --------------------------------------------------------
        case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
        {
            NRF_LOG_DEBUG("PHY update request.");
            ble_gap_phys_t const phys =
            {
                .rx_phys = BLE_GAP_PHY_2MBPS,
                .tx_phys = BLE_GAP_PHY_2MBPS,
            };
            err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
            APP_ERROR_CHECK(err_code);
        } break;
    
    
    
    
    
    
    

    And here are the few modifications I have made for ble_app_uart_c

    BLE_APP_UART_C
    --------------------------------------------------------
    # sdk_config.h
    --------------------------------------------------------
    // <i> Requested BLE GAP data length to be negotiated.
    #ifndef NRF_SDH_BLE_GAP_DATA_LENGTH
    #define NRF_SDH_BLE_GAP_DATA_LENGTH 251
    #endif
    --------------------------------------------------------
    // <o> NRF_SDH_BLE_GATT_MAX_MTU_SIZE - Static maximum MTU size. 
    #ifndef NRF_SDH_BLE_GATT_MAX_MTU_SIZE
    #define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247
    #endif
    
    --------------------------------------------------------
    # main.c
    --------------------------------------------------------
    static uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
    --------------------------------------------------------
    
    
    

     

    The peripheral device should now be configured for ATT MTU = 247, GAP data length = 251 and a connection interval of 50ms with the 2M Phy. Since the peripheral device is sending the big payload, I assume that I do not have modify ble_app_uart_c as extensively since the peripheral sets these parameters. I believe this is why I could not find where the connection interval or PHY was set in the central firmware.

    However, when I test this and use RealTerm to send a 87kB binary file over UART at 230400 baud from the peripheral device, it takes ~38 seconds to send (18kbps). Much too slow.

    It should actually take about 5 seconds since:

    UART over BLE transmit time = 87kB of data sent at 230400 baud = 3.77 seconds + UART overhead = 4-5 seconds

    I am assuming that BLE transmission speed (1327 kbps) >> UART transmission (230.4 kbps) therefore we should not get any buffers overflowing on BLE modules during transmission.

    Your help is much appreciated.

    Thanks,

    Robert

  • Hello Robert,

    It is true that this could give a BLE speed of about 1.3MBPS under the same conditions, such as distance and environment, as your ble_att_mtu_throughput test. However, you should also set the connection interval to what you used in that test. I don't know what it is, but please check that it is set to be equal both on the peripheral and the central. Depending on what SDK version you use, this is done in either main.c or sdk_config.h on the central, and the main.c file on the peripheral. Let me know what SDK version you use if you can't find it.

    The key to a high throughput in BLE is to use the entire MTU when you send packets. I don't know how you do that now, but shorter packets will mean higher overhead/payload ratio, and hence a lower throughput.

    Please check out the attached throughput demo over NUS. I don't remember exactly, but you need to push button 3 or 4 on one of the devices to start the transmission of data. Monitor the RTT log on both devices to check the throughput. You should be able to tell from the source code what the different buttons do.

    Unzip in SDK16, so they have the similar paths as the examples in the SDK.

    nus_throughput.zip

    BR,

    Edvin

Related