problem: not accurate measurement of battery using ADC

I'm trying to accurately measure our 3.0 volt coin battery (CR2450).

Our product consume low power (<50 uA) and we measure the battery voltage every minute.

We must have an accurate measurement in order to corectly estimate the time left for our product.

the measurements voltage changes over time in 0.01/0.02 volts:

sometimes goes down, somtimes goes up 

What I need to do in order to have an accorate measurements

I attached a typical log, circuit drawing and relevant code:

            // sample every one minute
            vdd = peripherals_read_vdd();


            vdd_float      = ((float)vdd) / 1000;
            vdd_on_no_load = vdd;

            // save measurement value in flash
            event_create_measurement(vdd_float, (float)(temperature), false);
            last_saved_measurement = xTaskGetTickCount();
            first                  = false;

            terminal_buffer_lock();
            sprintf(alert_str, "\r\nStatus: T=%dC, V=%.2fV\r\n", temperature, vdd_float);
            terminal_display_message(alert_str, 0, false);
            terminal_buffer_release();




static void init_saadc(void)
{
    nrfx_err_t err_code;

    err_code = nrfx_saadc_init(NRFX_SAADC_CONFIG_IRQ_PRIORITY);
    APP_ERROR_CHECK(err_code);

    calibrate_saadc();
    init_saadc_channels();
}

static void calibrate_saadc(void)
{
    nrfx_err_t err_code;

    err_code = nrfx_saadc_offset_calibrate(NULL);
    APP_ERROR_CHECK(err_code);
}

static void init_saadc_channels(void)
{
    nrfx_err_t err_code;

    // trying external input or internal
#if VBAT_MEASURE_EXTERNAL_PIN_EN == 1
    nrfx_saadc_channel_t channels[] = {NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN0, HAL_SAADC_VBAT_CHANNEL)};
#else
    nrfx_saadc_channel_t channels[] = {NRFX_SAADC_DEFAULT_CHANNEL_SE(HAL_ADC_VBATT, HAL_SAADC_VBAT_CHANNEL)};
#endif

    channels[0].channel_config.reference = NRF_SAADC_REFERENCE_INTERNAL;
    channels[0].channel_config.gain      = NRF_SAADC_GAIN1_6;
    // channels[0].channel_config.acq_time  = NRF_SAADC_ACQTIME_40US;
    channels[0].channel_config.acq_time  = NRF_SAADC_ACQTIME_3US;

    err_code = nrfx_saadc_channels_config(channels, sizeof(channels) / sizeof(nrfx_saadc_channel_t));
    if (NRFX_SUCCESS != err_code)
        NRFX_LOG_ERROR("%s nrfx_saadc_channels_config failed: %s", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
    APP_ERROR_CHECK(err_code);
}

inline uint16_t peripherals_read_vdd(void)
{
    uint32_t vdd_adc = hal_read_vdd_raw();

    // INFO https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/measuring-lithium-battery-voltage-with-nrf52
    vdd_adc *= 100 * 6 * 6; // Convert to mV, Gain 1/6, Ref 0.6V

#if VBAT_MEASURE_EXTERNAL_PIN_EN == 1
    // return ROUNDED_DIV(vdd_adc, 4095); // Div by 4095 (12 bits)  and X2
    return (vdd_adc >> 11);
#else

    // return ROUNDED_DIV(vdd_adc, 4095); // Div by 4095 (12 bits)
    return (vdd_adc >> 12);
#endif
}





int16_t hal_read_vdd_raw(void)
{
    nrfx_err_t        err_code;
    nrf_saadc_value_t battery_voltage[1];
    uint32_t          channels = (1 << HAL_SAADC_VBAT_CHANNEL);

    err_code = nrfx_saadc_simple_mode_set(channels, NRFX_SAADC_CONFIG_RESOLUTION, NRFX_SAADC_CONFIG_OVERSAMPLE, NULL);
    APP_ERROR_CHECK(err_code);

    err_code = nrfx_saadc_buffer_set(battery_voltage, 1);
    APP_ERROR_CHECK(err_code);

    err_code = nrfx_saadc_mode_trigger();
    APP_ERROR_CHECK(err_code);

    if (err_code != NRFX_SUCCESS) {
        NRFX_LOG_ERROR("%s %s", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
        return UINT8_MAX;
    }

    return battery_voltage[0];
}

---------------------------------------------------- - measurement log ----------------------------------------------------------------\


Status: T=0C, V=2.88V

09-01-22 12:01:39 Event Created: sector=271, id=51656, type=14

Status: T=0C, V=2.91V

09-01-22 12:02:38 Event Created: sector=271, id=51657, type=14

Status: T=0C, V=2.91V

09-01-22 12:03:36 Event Created: sector=271, id=51658, type=14

Status: T=0C, V=2.91V

09-01-22 12:04:35 Event Created: sector=271, id=51659, type=14

Status: T=0C, V=2.89V

09-01-22 12:05:33 Event Created: sector=271, id=51660, type=14

Status: T=0C, V=2.90V

09-01-22 12:06:32 Event Created: sector=271, id=51661, type=14

Status: T=0C, V=2.90V

09-01-22 12:07:31 Event Created: sector=271, id=51662, type=14

Status: T=0C, V=2.90V

09-01-22 12:08:29 Event Created: sector=271, id=51663, type=14

Status: T=0C, V=2.90V

09-01-22 12:09:28 Event Created: sector=271, id=51664, type=14

Status: T=0C, V=2.90V

09-01-22 12:10:27 Event Created: sector=271, id=51665, type=14

Status: T=0C, V=2.91V

09-01-22 12:11:25 Event Created: sector=271, id=51666, type=14

Status: T=0C, V=2.90V

09-01-22 12:12:24 Event Created: sector=271, id=51667, type=14

Status: T=0C, V=2.90V

09-01-22 12:13:22 Event Created: sector=271, id=51668, type=14

Status: T=0C, V=2.91V

09-01-22 12:14:21 Event Created: sector=271, id=51669, type=14

Status: T=0C, V=2.90V

-----------------------------------------------------------------------------------------------------------------------------------------------

our product

Related