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
VFS = 2 × VREF × ATTVREF / ATTVIN
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.
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.
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