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

Measuring the battery voltage with nRF52832

Hi!

To measure the voltage level of a coin cell CR2450 can be done in different ways. You can use the comparator, the low power comparator or the ADC. I wonder which one is the most adequate to use and affects least the current consumption? The CR2450 is the only power supplay in the system and the voltage is 3,0V when it has full capacity and 2,0V when it's discharged.

BR, Nixon

Parents
  • Hi Nixon

    All options can be low current, also the SAADC when used for battery measuring. I suspect the LPCOMP/COMP and Power Failure warnings generate more of low battery warning events, while the SAADC provides actual battery monitoring. If you use the SAADC to sample once a second or less, I suspect it will add less than 1uA to the current consumption. This is not given though, you have to set the SAADC up correctly in order to achieve low current. The default saadc example in the nRF5 SDK 11.0.0 conumes around 2mA. I attach a low power SAADC example for you to explore, which uses RTC to trigger sampling. I have tested it with SDK 11.0.0 and nRF52832 revision 1. The SAADC is only enabled before sampling and disabled when sampling completes to avoid high current consumption of the EasyDMA.

    saadc_low_power_with_rtc.zip

    This example is sampling on an intput pin. To sample the battery voltage which the nRF52832 IC is powered with, configure the SAADC channel you use to be single ended, the input on PSELP as VDD and gain as 1/6, which will measure the battery voltage directly and give the SAADC range from 0V to 3.6V.

    Let me know if my message is unclear or if there are any questions

Reply
  • Hi Nixon

    All options can be low current, also the SAADC when used for battery measuring. I suspect the LPCOMP/COMP and Power Failure warnings generate more of low battery warning events, while the SAADC provides actual battery monitoring. If you use the SAADC to sample once a second or less, I suspect it will add less than 1uA to the current consumption. This is not given though, you have to set the SAADC up correctly in order to achieve low current. The default saadc example in the nRF5 SDK 11.0.0 conumes around 2mA. I attach a low power SAADC example for you to explore, which uses RTC to trigger sampling. I have tested it with SDK 11.0.0 and nRF52832 revision 1. The SAADC is only enabled before sampling and disabled when sampling completes to avoid high current consumption of the EasyDMA.

    saadc_low_power_with_rtc.zip

    This example is sampling on an intput pin. To sample the battery voltage which the nRF52832 IC is powered with, configure the SAADC channel you use to be single ended, the input on PSELP as VDD and gain as 1/6, which will measure the battery voltage directly and give the SAADC range from 0V to 3.6V.

    Let me know if my message is unclear or if there are any questions

Children
  • Hi,

    Found Intresting, Still i have one quick query, What are the setting available in Resistor ladder? As we will require to do so. we are measuring 3V(CR2032) battery with ADC internal ref=0.6V.

  • Hi Stefan, I didn't understood the configuration to read battery voltage .Also the links you given in explanation are blank. How can i measure the battery voltage using your example?

  • I am trying to resolve the same problem. Anyone can to resolved this question?

  • Try this; I wrote it for polled mode for occasional low-power monitoring of CR2032 coin cells with no external components; that assumes of course no regulator or LDO or series schottky diode between coin cell and nRF52832:

    // Input range of internal Vdd measurement = (0.6 V)/(1/6) = 3.6 V
    // 3.0 volts -> 14486 ADC counts with 14-bit sampling: 4828.8 counts per volt
    #define ADC12_COUNTS_PER_VOLT 4551
    
    /**
     * @brief Function for 14-bit adc init in polled mode
     */
    void Adc12bitPolledInitialise(void)
    {
        uint32_t timeout = 10;
        nrf_saadc_channel_config_t myConfig =
        {
            .resistor_p = NRF_SAADC_RESISTOR_DISABLED,
            .resistor_n = NRF_SAADC_RESISTOR_DISABLED,
            .gain       = NRF_SAADC_GAIN1_6,
            .reference  = NRF_SAADC_REFERENCE_INTERNAL,
            .acq_time   = NRF_SAADC_ACQTIME_40US,
            .mode       = NRF_SAADC_MODE_SINGLE_ENDED,
            .burst      = NRF_SAADC_BURST_ENABLED,
            .pin_p      = NRF_SAADC_INPUT_VDD,
            .pin_n      = NRF_SAADC_INPUT_DISABLED
        };
    
        nrf_saadc_resolution_set((nrf_saadc_resolution_t) 3);   // 3 is 14-bit
        nrf_saadc_oversample_set((nrf_saadc_oversample_t) 2);   // 2 is 4x, about 150uSecs total
        nrf_saadc_int_disable(NRF_SAADC_INT_ALL);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
        nrf_saadc_enable();
    
        NRF_SAADC->CH[1].CONFIG =
                  ((myConfig.resistor_p << SAADC_CH_CONFIG_RESP_Pos)   & SAADC_CH_CONFIG_RESP_Msk)
                | ((myConfig.resistor_n << SAADC_CH_CONFIG_RESN_Pos)   & SAADC_CH_CONFIG_RESN_Msk)
                | ((myConfig.gain       << SAADC_CH_CONFIG_GAIN_Pos)   & SAADC_CH_CONFIG_GAIN_Msk)
                | ((myConfig.reference  << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
                | ((myConfig.acq_time   << SAADC_CH_CONFIG_TACQ_Pos)   & SAADC_CH_CONFIG_TACQ_Msk)
                | ((myConfig.mode       << SAADC_CH_CONFIG_MODE_Pos)   & SAADC_CH_CONFIG_MODE_Msk)
                | ((myConfig.burst      << SAADC_CH_CONFIG_BURST_Pos)  & SAADC_CH_CONFIG_BURST_Msk);
    
        NRF_SAADC->CH[1].PSELN = myConfig.pin_n;
        NRF_SAADC->CH[1].PSELP = myConfig.pin_p;
    }
    
    /**
     * @brief Function for 14-bit adc battery voltage by direct blocking reading
     */
    uint16_t GetBatteryVoltage1(void)
    {
        uint16_t result = 9999;         // Some recognisable dummy value
        uint32_t timeout = 10000;       // Trial and error
        volatile int16_t buffer[8];
        // Enable command
        nrf_saadc_enable();
        NRF_SAADC->RESULT.PTR = (uint32_t)buffer;
        NRF_SAADC->RESULT.MAXCNT = 1;
        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
        nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);
    
        while (0 == nrf_saadc_event_check(NRF_SAADC_EVENT_END) && timeout > 0)
        {
            timeout--;
        }
        nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        // Disable command to reduce power consumption
        nrf_saadc_disable();
        if (timeout != 0)
        {
            result = ((buffer[0] * 1000L)+(ADC12_COUNTS_PER_VOLT/2)) / ADC12_COUNTS_PER_VOLT;
        }
        return result;
    }
    
    

Related