Hi,
I know that a lot of question exists on that subject, but I can't manage to have an accurate battery measure on [Nordic Beacon device] (battery CR1632 3V) (www.nordicsemi.com/.../nRF51822-Bluetooth-Smart-Beacon-Kit). The measure is always -100mV-300mv to low and I can't understand why.
First of all, I read the Nordic GitHub project to inpired me and then modify the configuration to fit my need, but I certainly did a mistake.
The battery measurment is done before any bluetooth stack is involved (before starting the advertisment) : in summary no advertising and device not connected.
Here is my code :
#define ADC_REF_VOLTAGE_IN_MILLIVOLTS 1200 /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
#define ADC_PRE_SCALING_COMPENSATION 3 /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
#define DIODE_FWD_VOLT_DROP_MILLIVOLTS 270 /**< Typical forward voltage drop of the diode (Part no: SD103ATW-7-F) that is connected in series with the voltage supply.
This is the voltage drop when the forward current is 1mA. Source: Data sheet of 'SURFACE MOUNT SCHOTTKY BARRIER DIODE ARRAY' available at www.diodes.com. */
#define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
((((ADC_VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLTS) / 255) * ADC_PRE_SCALING_COMPENSATION)
//ADC initialization
static void adc_init(void)
{
/* Enable interrupt on ADC sample ready event*/
NRF_ADC->INTENSET = ADC_INTENSET_END_Msk;
sd_nvic_SetPriority(ADC_IRQn, NRF_APP_PRIORITY_LOW);
sd_nvic_EnableIRQ(ADC_IRQn);
// Configure ADC
NRF_ADC->CONFIG = (ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos) | /*!< 8bit ADC resolution. */
(ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) |
(ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) | /*!< Use internal 1.2V bandgap voltage as reference for conversion. */
(ADC_CONFIG_PSEL_Disabled << ADC_CONFIG_PSEL_Pos) |
(ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos); /* Bits 17..16 : ADC external reference pin selection. */
/* Enable ADC*/
NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
}
void ADC_IRQHandler(void)
{
if (NRF_ADC->EVENTS_END != 0)
{
uint8_t adc_result;
uint16_t batt_lvl_in_milli_volts;
NRF_ADC->EVENTS_END = 0;
adc_result = NRF_ADC->RESULT;
NRF_ADC->TASKS_STOP = 1;
//Release the external crystal
sd_clock_hfclk_release();
batt_lvl_in_milli_volts = ADC_RESULT_IN_MILLI_VOLTS(adc_result);
m_bat_level = (batt_lvl_in_milli_volts / 10) - 100;
kernel_setSignal(SIGNAL_BATTERY_CHECK);
}
void kernel_battery_check(void)
{
uint32_t p_is_running = 0;
sd_clock_hfclk_request();
while(! p_is_running) { //wait for the hfclk to be available
sd_clock_hfclk_is_running((&p_is_running));
}
NRF_ADC->EVENTS_END = 0; // Stop any running conversions.
NRF_ADC->TASKS_START = 1;
}