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

Battery Voltage Calculation on pins Other than analog pins.

Hello

I am working on nrf52382,sdk11,softdevice 2.0.

/cfs-file/__key/support-attachments/beef5d1b77644c448dabff31668f3a47-fd3fce63fa6d4ddfa73158194e4d87c3/battery_5F00_pins.pdf

/cfs-file/__key/support-attachments/beef5d1b77644c448dabff31668f3a47-fd3fce63fa6d4ddfa73158194e4d87c3/battery_5F00_protection_5F00_circuit.pdf

/cfs-file/__key/support-attachments/beef5d1b77644c448dabff31668f3a47-fd3fce63fa6d4ddfa73158194e4d87c3/battery_5F00_pins_5F00_connection.pdf

 

Schematics for connection of battery with a protection circuit are in these links, Not allowed to share whole Schematics.

Using  SAADC I tried to get battery voltage on BAT_MON_EN pin with Single Ended, 10-bit resolution, internal reference and gain 1/6, observe that a constant value 02DB(784) which according to calculation gives 3.0 v

Calculation : batt_voltage = saadc_reading/((1023*(1/6))/0.6)

With the same configuration on analogs free pins AIN0 and AIN1, I was getting 96,95 as saadc_reading.

I changed the configuration to  Differential Taking BAT_MON_EN pin as positive and BATTERY pin as negative I got the result like 400 around.

Please look at the battery schematics and explain how can I get readings out of it.Which pins I need to consider.

My code snippet:

void saadc_callback(nrf_drv_saadc_evt_t const * p_event{

    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)

    {

        ret_code_t err_code;

        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);

        APP_ERROR_CHECK(err_code);

       // printf("ADC event number: %d\r\n",(int)m_adc_evt_counter);

        for (int i = 0; i < SAMPLES_IN_BUFFER; i++)

        {

        test_c.number = p_event->data.done.p_buffer[i];

        string_send(test_c.ch,4);

            //printf("%d\r\n", p_event->data.done.p_buffer[i]);

        }

//        m_adc_evt_counter++;

nrf_drv_saadc_uninit();

        NRF_SAADC->INTENCLR = (SAADC_INTENCLR_END_Clear << SAADC_INTENCLR_END_Pos);

        NVIC_ClearPendingIRQ(SAADC_IRQn);

    }

}

void saadc_init(void){

    ret_code_t err_code;

    nrf_saadc_channel_config_t channel_config =

     NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(TX_PIN_NUMBER);

    err_code = nrf_drv_saadc_init(NULL, saadc_callback);

    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &channel_config);

    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0],SAMPLES_IN_BUFFER);

    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1],SAMPLES_IN_BUFFER);

    APP_ERROR_CHECK(err_code);

}

Calling of these are done when ever required with 

saadc_init();

nrf_drv_saadc_sample();

Parents
  • You can only use analog pins to measure the battery voltage. 

    Note if the battery is directly connected to VDD, you can measure the battery voltage directly by using the internal reference. If the battery voltage is regulated, you have to connect it to a analog input via a voltage divider.

  • Hi Ketiljo.

    As per above answer, no pins other than analog pins can give me voltage information.

    but as per schematics, Hardware engineer attached p0.08 to the voltage divider and MOSFET.  \

    On Pin BATTERY (Which is P0.08) I am trying to get voltage information.

  • P0.08 is not a analog input, there are only 8 analog inputs, AIN0 to AIN7. See the pin assignment.

  • You can get a reasonable battery measurement without an ADC, but you'll have to do some characterisation and possibly some temperature compensation; better than nothing though. Simply enable the (complicated looking) FET switches to provide the battery voltage to the pin, which is set as an input, and the battery voltage charges any distributed capacitance on the circuit connected to the pin. Then turn off the FET switches and time how long it takes for the voltage on the pin to decay to the digital input low voltage threshold (ie, 1 -> 0). Voila, an indication of battery voltage. If the numbers are too small (tiny distributed capacitance say 5pF) simply add some more - say 100pF across R29. Better still, make R29 much bigger and add some extra capacitance. In fact you could swap R28 and R29, since you no longer require a voltage divider unless you have a very high battery voltage. The slower the discharge, the more counts for a given voltage.

    // Define the on/off and sample pin and sense mask
    #define BATT_MON_ENABLE_PIN 9
    #define BATTERY_VOLTAGE_PIN 8
    #define BATTERY_VOLTAGE_PIN_MASK  (1 << BATTERY_VOLTAGE_PIN)
    
    uint32_t SampleBatteryVoltageViaChargeDischarge(uint32_t Timeout)
    {
       uint32_t myCounter = 0;
    #if 1 // Measure mode, time how long the capacitance takes to discharge
       nrf_gpio_cfg_input(BATTERY_VOLTAGE_PIN, NRF_GPIO_PIN_NOPULL);
    #else // Test timeout mode, characterise the max count
       nrf_gpio_cfg_input(BATTERY_VOLTAGE_PIN, NRF_GPIO_PIN_PULLUP);
    #endif
       // Enable the battery voltage onto the sense pin 8
       nrf_gpio_pin_set(BATT_MON_ENABLE_PIN);
       nrf_gpio_cfg_output(BATT_MON_ENABLE_PIN);
       // Charge any capacitance on the pin - there might be enough, or add few 100 pF
       nrf_delay_us(2);
       // Remove the battery voltage from the sense pin 8
       nrf_gpio_pin_clear(BATT_MON_ENABLE_PIN);
       // Wait until discharge or timeout
       while ( ((NRF_GPIO->IN & BATTERY_VOLTAGE_PIN_MASK) == BATTERY_VOLTAGE_PIN_MASK) && (myCounter < Timeout) )
       {
          myCounter++;
       }
       return myCounter;
    }
    

    For best count resolution, you need cpu cache enabled and fast clocks running.

       // If cache not enabled enable cache and hit/miss registers
       if ((NRF_NVMC->ICACHECNF & NVMC_ICACHECNF_CACHEEN_Msk) != (NVMC_ICACHECNF_CACHEEN_Enabled << NVMC_ICACHECNF_CACHEEN_Pos)){
          // Enable instruction cache (I-Cache) and cache hit & miss profiling (the latter two if required)
          NRF_NVMC->ICACHECNF = (NVMC_ICACHECNF_CACHEEN_Enabled << NVMC_ICACHECNF_CACHEEN_Pos) | (NVMC_ICACHECNF_CACHEPROFEN_Enabled << NVMC_ICACHECNF_CACHEPROFEN_Pos);
          while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
          // Enable Read-only to allow cache to operate correctly
          NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
          while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
       }
    

  • Thanks, Hmolesworth for the brief answer.I will try to do the same and check for the output.

  • You are welcome. Also note if you do rework the board to use a SAADC input pin you will not get good results with your circuit unless you add a capacitor from the input pin to Gnd since the source impedance is 1M5 + 180K which is double the value allowed for settling even at 40uSec sample time. With a capacitor the charge is shared between it and the internal sampling capacitor and allows a much shorter sampling time to achieve full resolution measurements. The internal C is 2.5pF at max gain, so you only need (say) 100pF.

Reply
  • You are welcome. Also note if you do rework the board to use a SAADC input pin you will not get good results with your circuit unless you add a capacitor from the input pin to Gnd since the source impedance is 1M5 + 180K which is double the value allowed for settling even at 40uSec sample time. With a capacitor the charge is shared between it and the internal sampling capacitor and allows a much shorter sampling time to achieve full resolution measurements. The internal C is 2.5pF at max gain, so you only need (say) 100pF.

Children
No Data
Related