This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

BLE battery update

HI, 

I'm developing it using NRF52832.

It is intended to update the remaining battery capacity through the battery_level_update() function by receiving the battery measurement value from saadc.

The value obtained through saadc was handed over to the battery_level_update() function, and the battery value obtained from battery_level_percent() was 100%, but remaining battery capacity was 54%. 

What's the problem? I'll attach my code.

void saadc_init(void)
{
    ret_code_t err_code;
    nrf_saadc_channel_config_t channel_config =
      //NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_DIFFERENTIAL(NRF_SAADC_INPUT_VDD, NRF_SAADC_INPUT_AIN0);
      NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);

    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);

}

static void battery_level_percent(void)
{
    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;
    }
}

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);

        /* get adc value */
        int i;
        NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);

        for (i = 0; i < SAMPLES_IN_BUFFER; i++)
        {
            NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
            adc_value= p_event->data.done.p_buffer[i];
           
            mmvolts=adc_value*(3.6)/1024;
            mvolts=mmvolts*1000;
            NRF_LOG_INFO("milivolt: %d", mvolts);
      
            battery_level_percent();
            NRF_LOG_INFO("battery_level: %d", battery_level);
        }
        m_adc_evt_counter++;

        /* update battery percent */
        battery_level_update(&battery_level);
    }
    mvolts=0;
    m_adc_evt_counter=0;
}

**@brief Function for performing a battery measurement, and update the Battery Level characteristic in the Battery Service.
 */
static void battery_level_update(uint16_t battery_level)
{
    ret_code_t err_code;

    err_code = ble_bas_battery_level_update(&m_bas, battery_level, BLE_CONN_HANDLE_ALL);
    if ((err_code != NRF_SUCCESS) &&
        (err_code != NRF_ERROR_BUSY) &&
        (err_code != NRF_ERROR_RESOURCES) &&
        (err_code != NRF_ERROR_FORBIDDEN) &&
        (err_code != NRF_ERROR_INVALID_STATE) &&
        (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
       )
    {
        APP_ERROR_HANDLER(err_code);
    }
}
int main(void)
{
    bool erase_bonds;
    log_init();

    ble_stack_init();
    scheduler_init();
    gap_params_init();
    gatt_init();
    advertising_init();
    services_init();
    sensor_simulator_init();
    conn_params_init();
    buffer_init();
    //pm_peers_delete();
    peer_manager_init();

    timers_start();
    advertising_start(erase_bonds);
    twi_init();


    /*saadc*/
    power_management_init();
    timers_init();

    uint32_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    //NRF_LOG_DEFAULT_BACKENDS_INIT();

    ret_code_t ret_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(ret_code);

    saadc_init();
    saadc_sampling_event_init();
    saadc_sampling_event_enable();
    NRF_LOG_INFO("SAADC HAL simple example started.");

  
    // Enter main loop.
    for (;;)
    { 
      /* BLE start */
      idle_state_handle();
      NRF_LOG_INFO("BLE START");
   }
}

Parents
  • Hello,

    I suspect that there is just a logical error with your formula for converting the SAADC's digital output to voltage.

    Could you show me what your log looks like when you see this behavior?
    How did you verify that the battery's remaining charge was actually 54%?
    The formula from the SAADC documentation for converting from digital output to analogue value uses millivolts - it seems your are multiplying it by 1000 an additional time, before passing it to the battery_level_percent function that seems to use millivolts as well.
    Furthermore, which battery are you using, and have you taken the battery_level_percent function from the SAADC's example (which is made specifically for CR2032 coin cell batteries), or did you create this yourself for the discharge curve of the specific battery you are using?

    Additionally, to increase stability and/or accuracy of the battery measurement you could use oversampling to reduce the impact of noise.
    You can also have the SAADC measure directly on the VDD bus by providing NRF_SAADC_INPUT_VDD to the channel configuration macro.

    Looking forward to resolving this issue together!

    Best regards,
    Karl

Reply
  • Hello,

    I suspect that there is just a logical error with your formula for converting the SAADC's digital output to voltage.

    Could you show me what your log looks like when you see this behavior?
    How did you verify that the battery's remaining charge was actually 54%?
    The formula from the SAADC documentation for converting from digital output to analogue value uses millivolts - it seems your are multiplying it by 1000 an additional time, before passing it to the battery_level_percent function that seems to use millivolts as well.
    Furthermore, which battery are you using, and have you taken the battery_level_percent function from the SAADC's example (which is made specifically for CR2032 coin cell batteries), or did you create this yourself for the discharge curve of the specific battery you are using?

    Additionally, to increase stability and/or accuracy of the battery measurement you could use oversampling to reduce the impact of noise.
    You can also have the SAADC measure directly on the VDD bus by providing NRF_SAADC_INPUT_VDD to the channel configuration macro.

    Looking forward to resolving this issue together!

    Best regards,
    Karl

Children
No Data
Related