This is part 3 of the series Building a Bluetooth application on nRF Connect SDK
You can find other parts here:
Part 1 - Peripheral Role.
Part 2 - Central Role.
In Part 1 we covered the generic architecture, the peripheral role and GATT Server. In Part 2 we discussed the Central Role and the GATT client.
Part 3 will analyze the options to optimize the connection for latency, power consumption, and throughput. We provided an NUS throughput demo that you can use as a reference design.
We start with a short description of the connection parameters:
Interval: defines the interval of the connection. How frequently the master/central will send a connection event packet to slave. The unit of connection interval is 1.25ms.
Latency: Slave latency. The slave/peripheral can skip waking up and respond to the connection event from master to slave. The latency is the number of connect event the slave can skip. This is to save power on the slave side. When it has no data it can skip some connection events. But the sleeping period should not be too long so that the connection will timeout.
Timeout: How long would the master keeps sending connection event without a response from the slave before the connection is terminated.

In a Zephyr Bluetooth LE central application, if you don't set the connection parameter when initializing scanning, the default connection parameter will be used:
Connection Interval: min30-max50 ms Latency: 0 Timeout: 4 s. (BT_LE_CONN_PARAM_DEFAULT)
This values are good for many applications; it's a good balance between shorter latency and not too power-hungry. But if you need to change that, you can either set your own connection parameter as an input to the bt_scan_init() or modify the definition of BT_LE_CONN_PARAM_DEFAULT in conn.h.
An example of setting your own connection parameters with low latency (you can use this in bt_scan_init() and bt_conn_le_create() ):
//minimum connection interval = maximum connection interval = 6*1.25 = 7.5ms //slave latency = 15 //Connection timeout = 30 * 10 = 300ms #define BT_LE_MY_CONN_PARAM BT_LE_CONN_PARAM(6, 6, 15, 30)
On the peripheral side, if you leave CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=y, the connection parameters request will be sent automatically 5 seconds after the connection is established. The reason it's sent 5 seconds after is to leave enough time for the connection running at lower latency (30-50ms for example) to complete service discovery quickly. If you immediately set the connection interval to says 1000ms, it will take pretty long to finish service discovery. The default connection parameters are similar to the ones on central with the exception of the connection timeout is set at 420ms. You can redefine this value in your project config/KConfig:
CONFIG_BT_PERIPHERAL_PREF_MIN_INT CONFIG_BT_PERIPHERAL_PREF_MAX_INT CONFIG_BT_PERIPHERAL_PREF_LATENCY CONFIG_BT_PERIPHERAL_PREF_TIMEOUT
static struct bt_le_conn_param *conn_param = BT_LE_CONN_PARAM(INTERVAL_MIN, INTERVAL_MAX, 0, 400);
static int update_connection_parameters(void)
{
int err;
err = bt_conn_le_param_update(current_conn, conn_param);
if (err) {
LOG_ERR("Cannot update conneciton parameter (err: %d)", err);
return err;
}
LOG_INF("Connection parameters update requested");
return 0;
}
//callback
static void conn_params_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout)
{
LOG_INF("Conn params updated: interval %d unit, latency %d, timeout: %d0 ms",interval, latency, timeout);
}static void request_mtu_exchange(void)
{ int err;
static struct bt_gatt_exchange_params exchange_params;
exchange_params.func = MTU_exchange_cb;
err = bt_gatt_exchange_mtu(current_conn, &exchange_params);
if (err) {
LOG_WRN("MTU exchange failed (err %d)", err);
} else {
LOG_INF("MTU exchange pending");
}
}
static void request_data_len_update(void)
{
int err;
err = bt_conn_le_data_len_update(current_conn, BT_LE_DATA_LEN_PARAM_MAX);
if (err) {
LOG_ERR("LE data length update request failed: %d", err);
}
}
static void request_phy_update(void)
{
int err;
err = bt_conn_le_phy_update(current_conn, BT_CONN_LE_PHY_PARAM_2M);
if (err) {
LOG_ERR("Phy update request failed: %d", err);
}
}#GATT_CLIENT needed for requesting ATT_MTU update CONFIG_BT_GATT_CLIENT=y #PHY update needed for updating PHY request CONFIG_BT_USER_PHY_UPDATE=y #For data length update CONFIG_BT_USER_DATA_LEN_UPDATE=y #This is the maximum data length with Nordic Softdevice controller CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 #These buffers are needed for the data length max. CONFIG_BT_BUF_ACL_TX_SIZE=251 CONFIG_BT_BUF_ACL_RX_SIZE=251 #This is the maximum MTU size with Nordic Softdevice controller CONFIG_BT_L2CAP_TX_MTU=247





(TBD)
We will provide the current measurements on common use cases with different connection parameters configurations. Basically to achieve low power consumption, what you should do is to keep the connection interval at the beginning short to finish service discovery as quick as possible. After that you can switch to a longer interval. If you need to transmit a large amount of data you can switch to shorter connection interval and switch back to longer connection interval after that.
1. Accessory Design Guidelines for Apple Devices. At chapter 40 you can find the recommended connection parameters that work best with Apple device.