Reporting Battery Voltage over BLE


This example shows how to create an application to monitor the battery voltage and report it as a percentage of full charge. The Bluetooth SIG defines a battery service exactly for this purpose. The definition can be found in Bluetooth SIG GATT Service List. The example will use this adopted service to report battery level.

The battery level is measured using the EFR32’s ADC without the need for any external GPIO. In the attached app.c file, you will find functions which contain all code necessary to set up the ADC. The initial setup is performed by init_adc_for_supply_measurement(). This function mostly uses the defaults for the ADC with a few important adjustments. The inputs to the ADC are AVDD and VSS. The reference voltage is the internal 5 V reference. Users must choose the attenuation factors for the input voltage and the reference voltage. The following formulas are taken from the ADC section of the EFR32 reference manual. The attenuation factor for the reference voltage is defined as follows:

ATTVREF = (VREFATT + 6) / 24 for VREFATT < 13, and (VREFATT - 3) / 12 for VREFATT ≥ 13

The attenuation for the input voltage is defined as follows:

ATTVIN = VINATT / 12 for VINATT ≥ 3 (settings 0, 1, and 2 are not allowable values for VINATT)

The ADC is set up for 12 bit conversions, which results in a total of 4096 steps per conversion. The attenuation factor for the input voltage is chosen to 1 and the attenuation factor for the reference voltage is set to be 0.5. The full scale voltage for conversions is determined as follows:


In the example,

VFS = 2×(5.0)×(0.5)/(1) = 5.0 V

The number of volts per division, VFS/4096 = 1221 μV/division

Using this information, you can determine the battery supply voltage.

app.c file contains a function called read_supply_voltage(), which can be used to read the ADC converted value and return it as the battery voltage in mV.

The boot handler for the application starts a soft_timer to schedule an ADC conversion once per second. The handler for the timer starts a conversion and then reads the converted value. The specification for the service requires the value to be reported as a percentage so the measured voltage is converted to a percentage of 3300 mV. This value is then used in the read request handler.

Setting up

  1. Create an SoC - Empty sample app for your chosen hardware.

  2. Replace the existing app.c with the app.c attached to this article.

  3. Copy em_adc.c and em_adc.h from the SDK (e.g., C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\v2.6\platform\emlib) to the project folder (if they aren't already in the platform>emlib>inc/src folders).

  4. Import the attached gatt.xml file in the GATT Configurator sidebar (open .isc file, "Import GATT from .bgproj file"), or alternatively add the Battery service manually:

    a) Open the GATT Configurator

    b) On the left side, find the Battery service within the Services tab

    c) Drag and drop the Battery service into your GATT database

    d) Click on the Battery Level characteristic and make sure that the Read property is set to true, and the ID is set to battery_level

    e) Change the type of the Battery Level characteristic to ‘user’.

    f) Select the ‘Device Name’ characteristic and change the value to ‘BattMon’

  5. Press Save and then Generate in the GATT Configurator.

  6. Build and flash the project to two devices.

GATT Configurator


To run the example, build the project and flash it to your hardware. Open the BlueGecko app on your mobile, open the Bluetooth Browser tab, and connect to the device. The name will display as “BattMon”. Expand the Battery Service and then expand the Battery Level characteristic to view the Battery charge level.