How to minimize current consumption for BLE application on nRF51822
The low power modes for the nRF51 series are System On and System Off. You can read about them in the nRF51 Series Reference Manual v3.0 sections 12.1.5 and 12.1.7. Additional information are also given here.
If you are using ANT or BLE softdevice for the nRF51, look at the "Power Profiles" chapter in the Softdevice Specification document for the softdevice you are using, S110 SDS, S120 SDS, S210 SDS and S310 SDS. The power profiles show what peripherals are drawing current during a radio event. Current consumption numbers for the different peripherals can be found in the nRF51822 PS v3.1. Look at table 32 for current consumption numbers for System On (I_ON) and System Off (I_OFF). Table 36 shows current consumed by the radio peripheral for LDO mode. For example, I_TX,0dBm is the current consumption used when radio TX is enabled with 0dBm transmit power. I_RX,1M is the current consumption when radio RX is enabled for BLE or ANT. Table 37 then shows the same numbers when DCDC mode is enabled. LDO mode and DCDC modes are explained later in this post.
Look at the “Measuring current” section in the User guide for the nRF51-DK development kit (third revision nRF51), evaluation kit (second revision nRF51) or the "Current measurements" section for the development kit (second revision nRF51) to find out how to set up the kit in order to measure current. In addition to the text in the user guide, make sure you power-reset the nRF51 after flashing your firmware to it. After flashing, the nRF51 stays in debugger-mode, which consumes excessive current (~1mA). When the nRF51 is power-reset, it will enter normal-mode where actual current consumption can be measured. It is also possible to use nrfjprog.exe (part of nrf Tools) with the command "nrfjprog --pinreset" in order to enter normal mode.
To test current consumption for the nRF51 low power modes without softdevice, try out the System Off mode example and the System On mode example.. Expected current consumption for the System Off mode example example is 0.6uA with no RAM retention and 2.6uA for the System On mode example. To initially test current consumption with these examples, disconnect the all external circuits from GPIO pins as well as the debugger/programmer. To run those examples on evaluation kit (PCA10001 boards) look at these threads (1) (2)
To test current consumption for a BLE application, use the Power profiling application in the nRF51 SDK, or e.g. the heart rate application. In a BLE application, the radio is enabled periodically to transmit advertising packets or connection packets in so called BLE advertising/connection events. Between BLE advertising/connection events, the nRF51 should be in System On low power mode and should consume ~4uA. It is however hard to see the current consumption between those events on a multimeter if the advertising/connection interval (the time between advertising/connection events) is small. If you modify the application to have long advertising interval, the reading on your multimeter should stabilize between advertising events, and you should be able to read the expected ~4uA. The advertising interval can be adjusted from 20ms to 10.24s, and can be set to e.g. 4 seconds in the power profiling example by modifying the following define at the top of the main.c file:
#define APP_CFG_CONNECTION_INTERVAL 4000
To test the power profiling application, press Button 1 on the nRF51-DK (PCA10028) in order start the advertising after you upload the code to the nRF51-DK board and power-reset it. Note that when connection is established, the connection interval is determined by the central device which is normally relatively short. Since the power profiling application does not send connection parameter update request to the central, the connection interval stays short and current consumption is therefore relatively high when connected.
nRF51 consumes excessive current after entering either System On low power mode or System Off mode, the most likely reasons for that are:
As for now, we do not have an online tool to calculate current consumption for the nRF51 series. However, there are some common scenarios given in this blog post, both when advertising and when in a connection. If you need current consumption calculation for a specific profile, please send your profile to us and we can calculate expected current consumption for you. You can do that by registering a support case on www.nordicsemi.com. Go to "My Page" and select "REGISTER NEW CASE". The profile parameters that are needed are:
Accuracy of 32kHz crystal or if you are using internal 32kHz RC.
For calculating current consumption during advertising:
For calculating current consumption during connection:
For calculating current consumption from SPI, UART or TWI transmission:
Also specify use of other peripherals, if any, e.g. TIMER, GPIOTE, etc.
Please provide as much as possible of these parameters above to enable us to measure the current consumption for your profile.
Battery life can be calculated when you know the average current consumption of the device and the energy capacity of your battery. Below are some calculation examples for battery lifetime for batteries with different energy capacity:
Average current consumption of device: 20 uA
Energy capacity: 220 mAh (typical CR2032 coin cell battery)
Battery lifetime: 0,22 Ah / 0,00002 A = 11,000 hours = 458 days
Average current consumption of device: 100 uA
Energy capacity: 220 mAh (typical CR2032 coin cell battery)
Battery lifetime: 0,22 Ah / 0,0001 A = 2,200 hours = 91 days
Average current consumption of device: 100 uA
Energy capacity: 1000 mAh
Battery lifetime: 1 Ah / 0,0001 A = 10,000 hours = 417 days
Also, in your design you should consider what low frequency clock source to use. As the nRF51 reference manual states there is a choice of three low frequency clock sources, external crystal, internal RC and the synthesized clock. Using the synthesized clock is of really no use in terms of current consumption since it will require the 16 MHz clock to be constantly enabled. Using a high accuracy external crystal is clearly the best choice in terms of current consumption.
Another choice is to use the internal 32kHz RC oscillator and calibrate every 4 seconds to maintain accuracy within 250 ppm. A motivation for using the internal 32kHz RC is either to decrease BOM or to save space on PCB. Using internal low frequency 32kHz RC clock instead of 20ppm external crystal will add around 10 uA current consumption compared to 20ppm external crystal. The internal 32kHz RC needs to be calibrated every 4 seconds and obtains frequency tolerance of 250ppm.
When initialising the softdevice with ble_stack_init() function call in the main function, select the NRF_CLOCK_LFCLKSRC_RC_250_PPM_TEMP_4000MS_CALIBRATION option when using the internal RC clock. For further information on choice of 32kHz clock source with a softdevice, look at this thread.
To minimize current consumption, choose 16MHz external crystal with minimal “startup” current consumption. For this purpose you should choose a crystal with low load capacitance, i.e. around 9 pF instead of the specified maximum of 16 pF for the nRF51.
For a general guide on 16MHz clock sources for the nRF51, look at this thread.
If using BLE, use the application timers that are generally used in the BLE examples in the SDK. Those use the RTC1 in the background which is very power efficient. Look at i.e. the ble_app_hrs example which has several application timers implemented.
Most BLE examples in the SDK will include the power_manage call in the main function. This call uses the sd_app_event_wait() softdevice call (or power_manage()) which enables the System On low power mode, which keeps current consumption to a minimum.
To put a device into System Off mode when using the softdevice, call sd_power_system_off() function.
The softdevice uses RTC0 to keep track of time and to know when to wake up for the next BLE connection event. The RTC0 will eventually wake the chip up and the softdevice will carry out the action needed for the BLE connection event, which includes receiving and sending packages. When it is done, execution will continue where it left off in the application after sd_app_event_wait() command. Normally in BLE examples in the SDK, the sd_app_event_wait() command is inside the main loop, therefore code residing in the main loop will execute once and then the sd_app_event_wait() is called again and the chip will sleep again in System On low power mode until the next BLE connection event.
What sd_app_event_wait() actually does is to disable the CPU. All peripherals (e.g. SPI, UART, TIMER, ...) that are enabled before calling sd_app_event_wait() will still be enabled. The CPU will actually wake up on any interrupt, i.e. it will wake up for BLE connection/advertising events, softdevice callbacks or peripheral interrupts (e.g. SPI, UART, TIMER, ... interrupts).
Control of current consupmtion during connection is mainly a question of tuning the Bluetooth connection parameters. If your "connection interval" parameter is large, communication will be slow and your device will consume little current during connection and packet delay will be relatively large. Setting short connection interval will enable larger throughput and relatively short packet delay but your device will consume more current. "Slave latency" is another bluetooth parameter that allows the device to not respond to number of packets sent from the host. This will decrease current consumption of the device while still allowing data bursts with high thoroughput.
A typical scenario for transmitting data on a button press is to have BLE connection with relatively low connection interval but with high slave latency. Low connection interval will enable your device to send packets frequently, i.e. to have a good response on a button press. High slave latency will allow your device to not send packets on every connection event, thereby saving current.
“Slave latency” is a special BLE connection parameter. Information about the slave latency parameter is found on the Bluetooth Developer site, A quote from this site about slave latency:
Slave Latency – Slave latency allows a slave to use a reduced number of connection events. The connSlaveLatency parameter defines the number of consecutive connection events that the slave device is not required to listen for the master. As a result, slave device can skip a number of connection events if it does not have additional data resulting in power savings.
For example, for an energy sensitive application, you choose relatively long connection interval, e.g. 4 seconds, in order to save energy of the peripheral. This will make the host/master send a packet every 4 seconds, also requesting the slave/peripheral to respond with a packet transmission (to tell the master that the slave is alive, which prevents link loss) which will also contain data if the slave/peripheral has some data to send. An alternative would be to create a connection interval of 1 second and have a slave latency of 3. This would make the master send packets to the slave every second but the slave would be obligated to respond only to every fourth packet. This will therefore not create an increase in current consumption for the slave compared to the 4 second connection interval, but instead will decrease slave data delay and enable data bursts as well from the slave with higher throughput.
If you are to connect with an iPhone there are however constraints from Apple on how connection parameters can be tuned. This apple document states the following in the section about “Connection Parameters”:
The connection parameter request may be rejected if it does not comply with all of these rules:
Interval Max * (Slave Latency + 1) ≤ 2 seconds
Interval Min ≥ 20 ms
Interval Min + 20 ms ≤ Interval Max
Slave Latency ≤ 4
connSupervisionTimeout ≤ 6 seconds
Interval Max * (Slave Latency + 1) * 3 < connSupervisionTimeout
To modify the connection interval in any BLE example in the nRF51 SDK, adjust the following constants that are located at the top of the main file:
#define MIN_CONN_INTERVAL MSEC_TO_UNITS(500, UNIT_1_25_MS) /**< Minimum acceptable connection interval (0.5 seconds). */
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(1000, UNIT_1_25_MS) /**< Maximum acceptable connection interval (1 second). */
which means that the connection interval will be 0.5-1.0 seconds, but it is really up to the central device to set the connection interval. More information on the connection parameter update procedure is found on this thread. Similarly, the slave latency is adjusted by modifying this constant:
#define SLAVE_LATENCY 0 /**< Slave latency. */
Current consumption during advertising mainly depends on the advertising interval, which is adjusted by modifying the following constant:
#define APP_ADV_INTERVAL 40 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 25 ms). */
The longer the advertising interval the less current will the device consume during advertising. However, when connecting to a central device, increasing the advertising interval will normally not decrease current consumption as it will take longer for the central device to discover the peripheral device. The result is that current consumption will be lower for the peripheral during advertising, but it will normally have to advertise for a longer time, therefore, energy consumed before connecting to the central will generally be more or less the same as when short advertising interval is chosen.
For some scenarios, it is convenient to advertise periodically, and that will save current instead of having the device advertise continuously. The timeout for the advertising can be adjusted by modifying the following parameter:
#define APP_ADV_TIMEOUT_IN_SECONDS 180 /**< The advertising timeout in units of seconds. */
Another parameter that effects the current consumption during advertising is how many payload bytes are sent in each advertising packet. It is e.g. typically 20%-25% lower current consumption during advertising if 10 payload bytes are sent in each advertising packet than the maximum of 31 bytes. Therefore, it may be beneficial in terms of current consumption to only place primary advertising data in the advertising packet and place all secondary data in the scan response packet, as advertising packets are sent much more frequently than scan response packets.
The three different modes are described in the nRF51 Series Reference Manual, Power chapter. Schematics for the three different modes are shown in the nRF51822 Product Specification (PS), Reference Circuitry chapter.
The specified current consumption is 0.6uA for System Off mode and no RAM retention but if you operate it it low voltage mode it is 1.6uA, refering to note 1 in table 27 in the PS v2.0. So. If you intend to use external switching regulator you could possibly save some current in low voltage mode for the reason that it accepts supply power down to 1.75V, but then you have 1uA higher current consumption in both System On and System Off modes. Since you can run the LDO mode almost as low, or down to 1.80V, I would assume that choosing the LDO option provides lower current consumption for most applications.
The internal DCDC converter can potentially decrease power consumption of the device. For explanation how a DCDC converter potentially lowers current consumpiton, look a this thread.
The DCDC is safe to use with the third revision nRF51 hardware and softdevices S110 8.0.0, S120 2.0.0, S130 1.0.0, S210 5.0.0, S310 3.0.0 or more recent softdevices. The DCDC mode can also be used safely with third revision nRF51 for proprietary protocols. For the second revision of the nRF51 hardware, or softdevices older than mentioned above, we do not recommend customers to use the DC/DC together with the BLE or ANT softdevices, as this has been discovered to create radio disturbances. The DCDC can optionally be used with propriatery protocol after carefully considering its operation limitations described in the nRF51 Series Reference Manual version 2.1, Power chapter. Further recommendation for the DCDC mode is given on this thread
Enable compiler optimization in order for you application to be executed in as few instructions as possible. This will make the code execute faster and finish sooner and will therefore save power. To enable compiler optimization in Keil, select Options for Target -> C/C++ tab and set Optimization to “Level 3” and check “Optimize for Time”. In order for you to efficiently debug the application code in Keil, the setting should be however Optimization: “Level 0” and “Optimize for Time” should be unchecked.
According to nRF51822/nRF51422 PS v3.1 table 34, current consumption can be decreased by executing code from RAM instead of from flash. How to execute code from RAM is described here.
Since the SPI, UART and TWI more or less have the same current consumption for different transmission speeds (see nRF51822 PS, “Electrical Specifications” chapter) it is most energy efficient to choose maximum transmission speed. This will require the SPI/UART/TWI to be enabled for a minimal time, therefore saving current. Disabling a peripheral is usually done by writing a Disabled value to the peripheral's ENABLE register, and will ensure that they don't keep the clock running when it isn't actually needed. More general information for enabling/disabling peripherals is given on this thread.
Low Power UART
When you enable the UART on the nRF51822, it will consume a lot of current, ~1mA constantly. The strategy is to only enable the UART when data transmission is needed. There are primarily two methods for achieving this, one is to manually configure two GPIO's for controlling this, second method is to enable the UART in LOW_POWER mode, an UART example with low power mode is available on Nordic's Github. The LOW_POWER mode is implemented in nRF51 SDK 9.0.0 and older SDKs.
The LOW POWER example will have flow control enabled in a specific LOW POWER mode where the nRF51822 is woken up and UART is enabled when CTS goes low. nRF51822 will set RTS low when it is ready to receive data. So the peer UART device must set nRF51822 CTS low when sending data to nRF51822 and set it high again when finished transmitting data. Further information on the functionality is given in the Readme for the UART Low Power example.
To Enable the UART, both RX and TX, execute the following code:
NRF_UART0->ENABLE = 1;
NRF_UART0->TASKS_STARTTX = 1;
NRF_UART0->TASKS_STARTRX = 1;
If you only need to receive data, enable the UART and only start RX, it will consume less current than starting both TX and RX. Similarly, if you only need to transmit data, enable the UART and only start TX.
To disable the UART, execute the following code:
NRF_UART0->TASKS_STOPTX = 1;
NRF_UART0->TASKS_STOPRX = 1;
NRF_UART0->ENABLE = 0;
Low Power SPI master
Similar to the UART, the SPI is high current when enabled. To enable low current consumption, you should therefore only enable the SPI when there is data to be transmitted.
To enable the SPI peripheral 0, execute the following code:
NRF_SPI0->ENABLE = 1;
To disable the SPI peripheral 0, execute the following code:
NRF_SPI0->ENABLE = 0;
Low Power SPI slave
The SPI slave peripheral is low power by default, meaning it consumes close to no current when the CSN line is high (chip select for the nRF51 is not set by the connected SPI master device). When the CSN line is set low by the SPI master, the SPI slave is enabled and consumes ~1mA. The SPI slave goes back into low power state when the SPI master ends the SPI transaction by setting the CSN line high.
For info on current consumption of the GPIOTE peripheral and how to set it up for low current applications, take a look at this thread
My goodness -- this may as well be a bible. Fantastic post!
great post, thanks
Create an Application Note out of that...