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

How do I measure battery level on an Nrf51422 without external components?

I have a custom PCB with an nrf51422 powered by a coin cell battery. The EE who designed the board assured me that the battery voltage could be measured internally through the ADC. That EE is now tied up and cannot help.

What is the proper method for measuring this voltage? It is a standard feature in nearly all devices, yet the inclusion of a resistor set will leak current. Any direction would be appreciated. Thanks.

Edit: I am able to find examples of battery service updates, but these updates are based on a simulated battery as per the code below. I have not yet found an example of configuring of the ADC to VCC.

static void battery_level_update(void)
{
    uint32_t err_code;
    uint8_t  battery_level;

    battery_level = (uint8_t)sensorsim_measure(&m_battery_sim_state, &m_battery_sim_cfg);

    err_code = ble_bas_battery_level_update(&m_bas, battery_level);
    if ((err_code != NRF_SUCCESS) &&
        (err_code != NRF_ERROR_INVALID_STATE) &&
        (err_code != BLE_ERROR_NO_TX_BUFFERS) &&
        (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
        )
    {
        APP_ERROR_HANDLER(err_code);
    }
}
Parents
  • #define VBAT_MAX_IN_MV                  3000
    
    uint8_t battery_level_get(void)
    {
    // Configure ADC
    NRF_ADC->CONFIG     = (ADC_CONFIG_RES_8bit                        << ADC_CONFIG_RES_Pos)     |
                          (ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos)  |
                          (ADC_CONFIG_REFSEL_VBG                      << ADC_CONFIG_REFSEL_Pos)  |
                          (ADC_CONFIG_PSEL_Disabled                   << ADC_CONFIG_PSEL_Pos)    |
                          (ADC_CONFIG_EXTREFSEL_None                  << ADC_CONFIG_EXTREFSEL_Pos);
    NRF_ADC->EVENTS_END = 0;
    NRF_ADC->ENABLE     = ADC_ENABLE_ENABLE_Enabled;
    
    NRF_ADC->EVENTS_END  = 0;    // Stop any running conversions.
    NRF_ADC->TASKS_START = 1;
    
    while (!NRF_ADC->EVENTS_END)
    {
    }
    
    uint16_t vbg_in_mv = 1200;
    uint8_t adc_max = 255;
    uint16_t vbat_current_in_mv = (NRF_ADC->RESULT * 3 * vbg_in_mv) / adc_max;
    
    NRF_ADC->EVENTS_END     = 0;
    NRF_ADC->TASKS_STOP     = 1;
    
    return (uint8_t) ((vbat_current_in_mv * 100) / VBAT_MAX_IN_MV);
           }
    

    the only thing you will change is VBAT_MAX_IN_MV as it depends on the battery max voltage level, it uses the bandgap voltage as it will be a constant ref whatever the value of vcc & scale vcc down to be withen 0 to bandgap voltage then it measure the battery level & refer it as percentage of the maximum voltage

    try it, I tried it & it works fine with me

Reply
  • #define VBAT_MAX_IN_MV                  3000
    
    uint8_t battery_level_get(void)
    {
    // Configure ADC
    NRF_ADC->CONFIG     = (ADC_CONFIG_RES_8bit                        << ADC_CONFIG_RES_Pos)     |
                          (ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos)  |
                          (ADC_CONFIG_REFSEL_VBG                      << ADC_CONFIG_REFSEL_Pos)  |
                          (ADC_CONFIG_PSEL_Disabled                   << ADC_CONFIG_PSEL_Pos)    |
                          (ADC_CONFIG_EXTREFSEL_None                  << ADC_CONFIG_EXTREFSEL_Pos);
    NRF_ADC->EVENTS_END = 0;
    NRF_ADC->ENABLE     = ADC_ENABLE_ENABLE_Enabled;
    
    NRF_ADC->EVENTS_END  = 0;    // Stop any running conversions.
    NRF_ADC->TASKS_START = 1;
    
    while (!NRF_ADC->EVENTS_END)
    {
    }
    
    uint16_t vbg_in_mv = 1200;
    uint8_t adc_max = 255;
    uint16_t vbat_current_in_mv = (NRF_ADC->RESULT * 3 * vbg_in_mv) / adc_max;
    
    NRF_ADC->EVENTS_END     = 0;
    NRF_ADC->TASKS_STOP     = 1;
    
    return (uint8_t) ((vbat_current_in_mv * 100) / VBAT_MAX_IN_MV);
           }
    

    the only thing you will change is VBAT_MAX_IN_MV as it depends on the battery max voltage level, it uses the bandgap voltage as it will be a constant ref whatever the value of vcc & scale vcc down to be withen 0 to bandgap voltage then it measure the battery level & refer it as percentage of the maximum voltage

    try it, I tried it & it works fine with me

Children
Related