Bluetooth Low Energy


Bluetooth Low Energy (a.k.a Bluetooth LE, BTLE, Bluetooth Smart)

Managing Power on mbed BLE

The Low Power Credentials of the Current BLE API

Here's an update on the power consumption profile of the BLE API.

Power is a topic of considerable importance for BLE, and we target the best that the radio controller has to offer. It is our goal that the power consumed by the BLE stack (together with BLE API) will be dwarfed by the overhead of driving the radio, so that it becomes a negligible concern.

Measuring Power Consumption

Measuring power can be tricky with BLE because of the large dynamic range involved; the baseline currents are 6-10uA while the BLE stack is idling, but consumption jumps to 10-15mA when the radio is used; that's a variance of three orders of magnitude. Traditional methods such as measuring the voltage drop across a sense resistor don't have enough of a dynamic range, and so don't work very well. In some cases useful measurements can be obtained as averages (some multi-meters offer reasonably accurate estimates of average currents through the use of min-max-avg modes), or through the use of auto-ranging oscilloscopes.

Some of the development boards (such as the mKIT) further complicate things by introducing the mbed interface chip into the equation; measuring power by observing what's fed into the USB input to the board gives misleading numbers due to the overheads of the supporting circuitry. In those cases, it's necessary to isolate the extraneous components through appropriate jumpers and schematic-study, and by switching from USB power to battery. Measuring from a custom board with minimal components, or through the use of something like the Nordic Smart Beacon Kit, is another successful strategy.

Power Consumption Example

Using Nordic's Smart Beacon Kit (where the interface chip is absent), the BLE_Beacon example on mbed consumes 35uA on average. Here's a power profile for that use-case:

/media/uploads/iritarkin/editedbeaconpowerdata.png

The vertical axis is the current consumption in milliamps, and the horizontal axis shows time; this picture captures nearly one second of activity. The major peak is an advertising event where a beacon is broadcast; the minor peak comes from periodic housekeeping activities by the Bluetooth stack. Outside the peaks, current consumption is around 6uA (when measured using instruments with 0.1uA precision), as can be seen from the instantaneous current value of 0.01mA.

The primary power consumer is the radio; it peaks at 12-15mA for around 2ms during every advertisement event, when the advertising payload must be sent out over the three advertising channels, and then the radio is run a little longer to look for scan-requests or connection requests. In the default beacon example, advertisements are sent out at 1Hz (once every second) and at a power level of 0dB; both of these factors are under the control of the developer. This should give you an idea of what's possible.

The average current (underlined in red on the right panel), is around 35uA, and with a coin cell battery the system may be expected to last around 7,000 hours, which is nearly a year.

Strategies for Lower Power Consumption

Here are some of the strategies we've employed with the Nordic nRF51822 to lower baseline power consumption:

  • The system now starts with the low frequency clock by default (instead of using the external 16MHz clock). The high frequency clock is still available to the SoftDevice, but now it doesn't remain active all the time. This by itself lowers the baseline consumption significantly. It also means that if an application needs the high frequency clock, for example for high-speed serial communication, it must explicitly enable it. The external clock should be managed in a power-conscious manner, which means that clocks will be turned off when not needed.
  • We make an effort to avoid using mbed's wait() API. This API is currently synchronous and wastes a lot of power.
  • We've also re-implemented the Ticker APIs to use the RTC instead of a high frequency timer. This involves a tradeoff between precision and power, and we believe power trumps precision in the context of BLE.

Connection intervals and connection latency can also be modified, and play a very important role in power consumption. Users may also experiment with reducing the transmission power of their radio; there's an API for this:

/**
* Set the radio's transmit power.
* @param[in] txPower Radio transmit power in dBm.
*/
ble_error_t setTxPower(int8_t txPower);

Please try using the following API once a connection is made in order to request the central to update the settings:

BLEDevice::updateConnectionParams(Gap::Handle_t handle, const Gap::ConnectionParams_t *params)

It is ultimately up to the central (master) to choose the connection parameters; your requested settings may not be honored.

Please remember the following comment from ble_gap.h (under nrf- sdk/s110) and pay attention to the constraint mentioned at the end:

/**@brief Update connection parameters.
 *
 * @details In the central role this will initiate a Link Layer connection parameter update procedure,
 *          otherwise in the peripheral role, this will send the corresponding L2CAP request and wait for
 *          the central to perform the procedure. In both cases, and regardless of success or failure, the application
 *          will be informed of the result with a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE event.
 *
 * @note If both a connection supervision timeout and a maximum connection interval are specified, then the following constraint
 *       applies: (conn_sup_timeout * 8) >= (max_conn_interval * (slave_latency + 1))
...

Here's one user's attempt to reduce connection intervals after a connection has been established (this is a heart-rate demo):

#define MIN_CONN_INTERVAL               MSEC_TO_UNITS(379, UNIT_1_25_MS)              /**< Minimum connection interval (379 ms) */
#define MAX_CONN_INTERVAL               MSEC_TO_UNITS(399, UNIT_1_25_MS)              /**< Maximum connection interval (399 ms). */
#define SLAVE_LATENCY                   4                                             /**< Slave latency. */
#define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(6000, UNIT_10_MS)               /**< Connection supervisory timeout (6 seconds). */

void onConnectionCallback(Gap::Handle_t handle, const Gap::ConnectionParams_t *p_conn_param)
{
    Gap::ConnectionParams_t gap_conn_params;
    gap_conn_params.minConnectionInterval = MIN_CONN_INTERVAL;
    gap_conn_params.maxConnectionInterval = MAX_CONN_INTERVAL;
    gap_conn_params.slaveLatency = SLAVE_LATENCY;
    gap_conn_params.connectionSupervisionTimeout = CONN_SUP_TIMEOUT;
    ble.updateConnectionParams(handle, &gap_conn_params);
}

...

The mbed team is also working towards asynchronous (non-blocking, interrupt-driven) APIs; automatic, smart management of clocks; and the use of DMA. Once these are in place, even non-trivial applications should be able to exhibit excellent power profiles.