Reporting Battery Voltage over BLE



The Bluetooth SIG defines a battery service. The definition of this service can be found here

This article discusses how to create an application to monitor the battery voltage and report it as a percentage of full charge, as defined by the specification above.



The first step in adding support for the battery service to your application is to set up your GATT database to include the service as shown below


Once you’ve dragged the battery service as shown, click generate. For this example, only the read property is enabled, the notification property is optional and so it is disabled.

Next, it will be necessary to add the capability to measure the voltage. This can be done using the EFR32’s ADC without the need for any external GPIO. Open the hardware configurator by double-clicking the .hwconf file in your project. Check the ADC0 box as shown and save the hwconf file to generate the code


The generated code goes in InitDevice.c, its function is to enable the ADC clock so that the remainder of the initialization can take place.

In the attached project, you will find adc.c which contains all of the code necessary to set up the ADC. The initial setup is performed by InitADCforSupplyMeasurement(). This function mostly uses the defaults for the ADC with a few important adjustments. The inputs to the ADC are chosen to be AVDD and VSS. The reference voltage is chosen to be the internal 5V reference. It is also necessary to 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

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

And the attenuation for the input voltage is defined as

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 our example,

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

        =  5.0 V

And the number of volts per division, VFS/4096 = 1221 uV/division

Using this information we can determine the battery supply voltage.

In adc.c you will find a function called readSupplyVoltage() 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.


Running the Example

The attached example is built for the BGM121 but will also run on BGM111, BGM113 and EFRBG1 SoCs.

To run the example, extract the attached zip file and import it into your SimplicityStudio workspace. Build the project and download to your hardware. Open the Bluegecko app on your mobile, then open the Bluetooth Browser tab and connect to the device, the name will display as “BattMon”. Expand the Battery Service service and then expand the Battery Level characteristic to view the Battery charge level.


Additional Reading

For additional information on the ADC and other peripherals please see the EFR32 reference manual.

The emlib peripheral driver library documentation can be found here

The Bluetooth Smart API Reference Manual contains information on the Bluetooth related APIs


  • Knowledge Base Articles
  • Bluetooth Low Energy
  • Bluetooth Classic
  • Hi

    Does anybody knows if this example works with evaluation board SLWSTK6102A? Because I have implemented this and then changed the switch to BAT option but battery service gives me a zero as result.


  • I did not implement the example. But i have used adc.c program and it works for me
  • given example is not working it showing zero value.

    how can i debug it while running the board on battery?

  • Hi,

    From what I read in the reference manual and in the driver code (em_adc.c), the VREFATT setting is used only if the REF field is set to CONF in SINGLECTRL register, which makes it use the extended settings like VREFATT from SINGLECTRLx register.

    So I think the above explanation is not valid. Though the eventual VFS=5V, that is correct.

    I myself am trying to read battery voltages upto 4.2V (supply voltage = 3.3V) and want to set VINATT=6 so that ATTVIN=0.5 but it is not clear if this is applied only if REF=CONF or for any value of REF.

    Can someone help?



  • Hi,

    I ran the battery-monitor-example on BGM121 using wireless starter kit powered through USB. The expected battery level would be 100%. However, it displayed 0%. Please let me know what could possibly cause it to display 0%.

    Thank you.