Note: This KBA has been marked as deprecated. A more updated KBA can be found here: Reporting Battery Voltage over BLE
The Bluetooth SIG defines a battery service. The definition can be found in Bluetooth SIG GATT Service List. 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.
Start by creating an SoC - Empty sample app for your chosen hardware.
Next, add support for the battery service to your application by setting up your GATT database to include the service as shown below
Once you’ve dragged the battery service as shown, change the type of the ‘battery level’ characteristic to ‘user’. Now select the ‘Device Name’ characteristic and change the value to ‘BattMon’ then click Save and then 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.
In the attached app.c file, you will find functions which contain all of the 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 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 μV/division
Using this information we can determine the battery supply voltage.
In app.c you will find 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.
To run the example, build the project and flash it 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 and then expand the Battery Level characteristic to view the Battery charge level.
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.
given example is not working it showing zero value.
how can i debug it while running the board on battery?
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?
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%.
The article and sample code have been updated now.
I just checked and the app.h is accessible. Please try again. If you're still having trouble I can send you the files some other way, like through a support ticket.