Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Low Throughput Issues

According to some benchmarks shown here: https://www.novelbits.io/bluetooth-5-speed-maximum-throughput/, I should be able to get a connection speed of around 120,000 bytes / second. However, in my testing, I can only get up to 20,000 bytes / second.

I have a nR52 2832 S132 chip that I connect to from an Android (galaxy s9) phone. The following settings are enabled:

-MTU: 247

-Data length extension: 251

-PHY: 2M

-TX Power: 4

-Connection interval: 7.5 min, 7.5 max

My code is available here in full: https://github.com/wdavies973/MagiCoil-microcode

Gatt init: (set mtu & data length extension)

static void gatt_init(void) {
ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
printf("GATT SUCCESS: %d\n",err_code);

conn_evt_len_ext_set();

printf("nrf_ble_mut_max: %d, mtu_default: %d\n", NRF_SDH_BLE_GATT_MAX_MTU_SIZE, BLE_GATT_ATT_MTU_DEFAULT);

err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, 247);
printf("mtu: %d\n",err_code);

err_code = nrf_ble_gatt_data_length_set(&m_gatt, BLE_CONN_HANDLE_INVALID, 251);
printf("data_length: %d\n",err_code);
}

PHY & MTU update requests:

static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
uint32_t err_code;

switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
printf("Connected");
err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
APP_ERROR_CHECK(err_code);
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
APP_ERROR_CHECK(err_code);

err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_CONN, m_conn_handle, 4);

break;

case BLE_GAP_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected");
// LED indication will be changed when advertising starts.
m_conn_handle = BLE_CONN_HANDLE_INVALID;
advertising_start(true);
break;
case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
{
ble_gap_conn_params_t params;
params.max_conn_interval = MAX_CONN_INTERVAL;
err_code = sd_ble_gap_conn_param_update(p_ble_evt->evt.gap_evt.conn_handle, &params);
} break;
case BLE_GAP_EVT_CONN_PARAM_UPDATE:
{
uint16_t max_con_int = p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.max_conn_interval;
uint16_t min_con_int = p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.min_conn_interval;

printf("conn updated\n");

//m_ble_params_info.con_interval = max_con_int;
//ble_its_ble_params_info_send(&m_its, &m_ble_params_info);
//NRF_LOG_INFO("Con params updated: CI %i, %i", (int)min_con_int, (int)max_con_int);
} break;

case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
{
printf("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);
printf("PHY update to 2MBPS: %d\n",err_code);
} break;

case BLE_GAP_EVT_PHY_UPDATE:
//m_ble_params_info.tx_phy = p_ble_evt->evt.gap_evt.params.phy_update.tx_phy;
// m_ble_params_info.rx_phy = p_ble_evt->evt.gap_evt.params.phy_update.rx_phy;
// ble_its_ble_params_info_send(&m_its, &m_ble_params_info);
printf("Phy update: %i, %i", (int)p_ble_evt->evt.gap_evt.params.phy_update.tx_phy, (int) p_ble_evt->evt.gap_evt.params.phy_update.rx_phy);
break;

case BLE_GAP_EVT_SEC_PARAMS_REQUEST:

// Pairing not supported
err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
APP_ERROR_CHECK(err_code);
break;

/*case BLE_GATTS_EVT_SYS_ATTR_MISSING:
// No system attributes have been stored.
err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
APP_ERROR_CHECK(err_code);
break;*/

case BLE_GATTC_EVT_TIMEOUT:
// Disconnect on GATT Client timeout event.
err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
break;

case BLE_GATTS_EVT_TIMEOUT:
// Disconnect on GATT Server timeout event.
err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
break;

default:
// No implementation needed.
//NRF_LOG_INFO("BLE event not handled by app: %i", p_ble_evt->header.evt_id);
break;
}
}

And finally, the send method:

void ble_cus_custom_value_update(ble_cus_t * p_cus)
{
uint8_t data[244];
uint16_t payload_len = 244;

ble_gatts_hvx_params_t hvx_param;

memset(&hvx_param, 0, sizeof(hvx_param));

hvx_param.handle = p_cus->custom_value_handles.value_handle;
hvx_param.type = BLE_GATT_HVX_NOTIFICATION;
hvx_param.p_len = &payload_len;
hvx_param.p_data = data;

uint32_t err_code = NRF_SUCCESS;

while(err_code == NRF_SUCCESS) {
(void)uint32_encode(0, data);

err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_param);

if (err_code == NRF_ERROR_RESOURCES)
{
// Wait for BLE_GATTS_EVT_HVN_TX_COMPLETE.
busy = true;
break;
}
else if (err_code != NRF_SUCCESS)
{
printf("sd_ble_gatts_hvx() failed: 0x%x", err_code);
}
}

}

Android Code:

@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {

super.onCharacteristicChanged(gatt, characteristic);

// if(status == BluetoothGatt.GATT_SUCCESS) {
// characteristic available for reading
//final byte[] data = characteristic.getValue();
// System.out.println("Receiving characteristic read"+characteristic.getValue().length);

if(receivedBytes > 10_000) {


double elapsedSeconds = (System.nanoTime() - startTime) / 1000000000.0;

double tp = 10_000.0 / elapsedSeconds;

System.out.println("TP: "+tp);
receivedBytes = 0;
startTime = System.nanoTime();
} else {

receivedBytes+=244;
}


// if (data != null && data.length > 0) {
// final StringBuilder stringBuilder = new StringBuilder(data.length);
// for(byte byteChar : data)
// stringBuilder.append(String.format("%02X ", byteChar));
// intent.putExtra(EXTRA_DATA, new String(data) + "\n" +
// stringBuilder.toString());

// }
}
Related