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

Inconsistent battery measurement

Hi!

I'm having issues with inconsistent battery readout results. I'll elaborate more below, but in general, I have multiple devices which 'sleep' most of the time, and when they wake up they measure the battery voltage using the SAADC, translate it to battery %, and report it via BAS. My problem is that within a few hours, with nothing major changing, I can get an enormous variance in the battery % values reported. The voltage is read before any peripherals draw current, before advertising starts, the batteries are placed in a control environment so the temperature is constant, the code they run is constant, and there is nothing else I can think of which can affect them.

My devices use: nRF52840, CR2032 batteries (~3V). No relevant peripherals draw current until after the SAADC read is completed.

To get the battery %, I use the SAADC with pre-scaling 1/6, 10 bit resolution, reference voltage 0.6A, I use the linearization formula suggested here for the CR2032 curve. While I understand the curve may be inaccurate in terms of it matching reality for my specific battery, I should still expect it to give me consistent readouts- i.e, that the battery % values given should be ballpark accurate, should not increase sporadically, with minor fluctuations etc.

When I try to read the ADC multiple consecutive times with 1 ms sleep time in between them, I get a small variance between the results, lets say up to 5%. its only between different reads in different wake ups, where I see this large gap between measurements.


I'm not sure what could be causing such a large variance in the measurements, and would love it if someone could point me in any possible direction.
Here is an example of the values I'm logging:

Day0 08:36 - ADC value 849, Bat 90%

Day1 14:55 - ADC value 827, Bat 48%.

Day1 14:56 - ADC value 839, Bat 73%

Day1 14:57 - ADC value 844, Bat 83%

Day1 15:26 - ADC value 802, Bat 30%

Day1 21:27 - ADC value 785, Bat 21%

Thanks!

  • I've observed the same behavior in other devices. They may take longer, or rise by a different amount, but a steady increase in battery over the span of a few hours, maybe days does occur in a few of my devices.

    Have I accidentally created a Perpetuum mobile device Slight smile?

  • Hello again,

    A.P said:
    Have I accidentally created a Perpetuum mobile device

    Now that would have been quite the marvel!
    Sadly, I fear that this is related to the SAADC configuration and usage, more so than a sure-fire Nobel physics prize. 
    While the output may not be Nobel-grade, it is still some interesting percentages you are seeing, with a particular device seemingly increasing in power.

    A.P said:
    The only thing I can think of is that during the night the air conditioner is turned off, so some change in temperature is to be expected. However, I don't expect the temperature to change by much. Lets say about 10 degrees C.

    Temperature is the biggest cause of offset error, but you say you calibrate it before every measurement, so that should be fine.
    Could you share with me the exact implementation of your battery discharge curve model?
    Perhaps could you also provide the raw SAADC readouts, so that I may see that fluctuation in the measurements directly.

    With your configuration I would expect some LSB fluctuation in your SAADC output - and if your linearized discharge curve is incorrect, it might be the source of these wild measurements ( i.e it is just coincidental that the measurements seems to be increasing ).

    Looking forward to getting to the bottom of this!

    Best regards,
    Karl

  • Hi Karl!

    Here is the linearization scheme as it is in our code, as well as the discharge curve for the batteries we use. I've yet to capture an increasing battery % while recording the SAADC readout, so I'll try and get that to you as soon as I catch it.

    Here is something to get things rolling

    Sener CR2032.pdf

    Linearization scheme:

    static __INLINE uint8_t battery_level_in_percent(const uint16_t mvolts)
    {
        uint8_t battery_level;
    
        if (mvolts >= 3000)
        {
            battery_level = 100;
        }
        else if (mvolts > 2900)
        {
            battery_level = 100 - ((3000 - mvolts) * 58) / 100;
        }
        else if (mvolts > 2740)
        {
            battery_level = 42 - ((2900 - mvolts) * 24) / 160;
        }
        else if (mvolts > 2440)
        {
            battery_level = 18 - ((2740 - mvolts) * 12) / 300;
        }
        else if (mvolts > 2100)
        {
            battery_level = 6 - ((2440 - mvolts) * 6) / 340;
        }
        else
        {
            battery_level = 0;
        }
    
        return battery_level;
    }

  • Hi,

    A.P said:
    Here is the linearization scheme as it is in our code, as well as the discharge curve for the batteries we use.

    Thank you for providing it. This linearization is the exact one we use in our cr2032 dependent battery service examples.
    To my knowledge there has never been an issue before in which the readings have increased so steadily.
    With your configuration I would expect ~8 ENOB, with the remaining being noise.
    Could you perhaps increase the resolution to 12 bit, and see if you are seeing the same fluctuations?

    Could you also share with me the saadc setup / configuration and usage code?
    So I may see how the aquired samples are processed.

    A.P said:
    I've yet to capture an increasing battery % while recording the SAADC readout, so I'll try and get that to you as soon as I catch it.

    Great, I look forward to seeing the results, thanks!

    Best regards,
    Karl

  • Hi again!

    I've been unsuccessful in trying to capture the ADC readings on RTT viewer with a board displaying this increase in power. While I keep trying to catch one red handed, I can pass the attached table onto you and hope it helps.

    What this table shows is as follows:

    1. Wake up, initiate the SAADC, calibrate it and take 5 measurements with 1ms sleep in between them.

    2. On the first measurement, save the ADC read value.

    3. Average the 5 measurements and report them as the battery %.

    4. Do the rest of the relevant logic (advertise, connect report measurements, other stuff and go to sleep for 10 minutes).

    repeat these steps.

    So, you might notice slight inconsistencies between the ADC value in the table and its matching battery %- that is because the SAADC value is the first read, which the battery% is the average of 5 readings.

    Battery increase measurements example.xlsx

    The saadc setup / configuration is as follows:


    #define ADC_REF_VOLTAGE_IN_MILLIVOLTS 600 //
    #define DIODE_FWD_VOLT_DROP_MILLIVOLTS   270 //
    #define ADC_RES_10BIT 1023 //
    //#define ADC_RES_12BIT 4095 //
    #define ADC_PRE_SCALING_COMPENSATION 6 //
    #define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE) ((((ADC_VALUE)*ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_PRE_SCALING_COMPENSATION)

    The SAADC init function is this:

    nrfx_saadc_config_t saadc_config = NRFX_SAADC_DEFAULT_CONFIG;
    
        nrf_saadc_channel_config_t channel_config;
    
        err_code = nrfx_saadc_init(&saadc_config, saadc_event_handler);
        APP_ERROR_CHECK(err_code);
        channel_config           = (nrf_saadc_channel_config_t)NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);
        channel_config.reference = NRF_SAADC_REFERENCE_INTERNAL;
        channel_config.gain      = NRF_SAADC_GAIN1_6;
        channel_config.acq_time  = NRF_SAADC_ACQTIME_40US;
    
        err_code = nrfx_saadc_channel_init(HAL_SAADC_VBAT_CHANNEL, &channel_config);

    If you need anything else, I'd rather we switch the ticket to private before sharing more specific code.

    Thanks!

Related