This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Unaccurate battery level measurment on Beacon device

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;
}
Parents
  • Hi Sebastien

    I am unhappy about that I did not see your message before. Sorry for the late response.

    What is actually the current consumption of your beacon device by the time you are sampling. If it is high, the measured voltage is lower than the battery voltage that you measure with your voltage meter. This is because of the internal resistance of the battery, which will create a lower battery output voltage on high current drain. The internal resistance of the battery greatly varies between battery manufacturers and battery types.

    To check if the high current consumption is creating that much difference in the battery reading, try to not request the high frequency clock. Enabling the high frequency clock will create most of the current consumption for the ADC sampling, so by not enabling the high frequency clock, the current consumption should be much lower and you should see some difference in your ADC readings.

    However, measuring the battery voltage when the device consumes the most current is perhaps the preferred method for battery level measuring.

Reply
  • Hi Sebastien

    I am unhappy about that I did not see your message before. Sorry for the late response.

    What is actually the current consumption of your beacon device by the time you are sampling. If it is high, the measured voltage is lower than the battery voltage that you measure with your voltage meter. This is because of the internal resistance of the battery, which will create a lower battery output voltage on high current drain. The internal resistance of the battery greatly varies between battery manufacturers and battery types.

    To check if the high current consumption is creating that much difference in the battery reading, try to not request the high frequency clock. Enabling the high frequency clock will create most of the current consumption for the ADC sampling, so by not enabling the high frequency clock, the current consumption should be much lower and you should see some difference in your ADC readings.

    However, measuring the battery voltage when the device consumes the most current is perhaps the preferred method for battery level measuring.

Children
  • Hi Stefan, Thank you for your support. I agree with the fact that enable 16MHz for the battery measurement is nonsense in my case, but I would my code be closest to the Nordic reference code found in the GitHub repository before asking for help. At this time, I removed the 16MHz enabling code for the battery measurement. I can ensure you that my code is really minimal and nothing is enabling before the end of the battery check. I was doing the battery measurement in debug mode (with the segger connected to the computer) which is bad. The value is close to the reality now: -60mV But, all the battery measurements done with the development kit are really accurate. Can you confirm that a difference of -60mV is acceptable for ADC measurements using a button battery CR1632? Best regards

  • I apologize again for a very late response. I was on vacation.

    Do you have an answer to your question yet? 60mV measurement error is very high. For 10 bit measurement it is around 17 bit error.

    My question is: when are you measuring the battery voltage? If you measure it during a radio event, you will measure lower voltage then when measuring when the chip is idle and not consuming a lot of current. How much voltage drop is during the radio event (or whenever the chip consumes the most current) really depends on the internal resistance of your battery, which is very different for different battery manufacturers. Ideally you should measure the battery voltage at the moment the chip is consuming the most current.

Related