The output voltage value does not change even if I keep using power

Hello, I'm from the United States.
I am currently working on a development project using nrf52840. In this project, I am implementing a battery voltage monitoring function, but the value of the output voltage hardly changes even if I keep using power. Specifically, we are implementing three functions related to saadc as shown in the following program: the first function uploads the voltage value as a percentage when an event occurs, the second function completes the initialization, and the third function is implemented in the main function as The second function completes the initialization, and the third function outputs the voltage value by looping through the while statement in the main function.
Since I am a beginner in developing with the nrf52840, I may not have enough prior knowledge in some areas. Thank you very much for your help. Thank you in advance.

static void saadc_event_handler(nrf_drv_saadc_evt_t const * p_evt)
{
    ret_code_t err_code;
    if (p_evt->type == NRF_DRV_SAADC_EVT_DONE)
    {
        nrf_saadc_value_t adc_result;

        adc_result = p_evt->data.done.p_buffer[0];

        m_batt_lvl_in_milli_volts =
            ADC_RESULT_IN_MILLI_VOLTS(adc_result) + DIODE_FWD_VOLT_DROP_MILLIVOLTS;
        
        percentage_batt_lvl=battery_level_in_percent(m_batt_lvl_in_milli_volts);

        NRF_LOG_INFO("Battery in %03d%%",percentage_batt_lvl);

        err_code=ble_bas_battery_level_update(&m_bas,percentage_batt_lvl,BLE_CONN_HANDLE_ALL);
        if((err_code !=NRF_SUCCESS)&&
           (err_code !=NRF_ERROR_INVALID_STATE)&&
           (err_code !=NRF_ERROR_RESOURCES)&&
           (err_code !=NRF_ERROR_BUSY)&&
           (err_code !=BLE_ERROR_GATTS_SYS_ATTR_MISSING)
          )
          {
             APP_ERROR_HANDLER(err_code);
          }

          nrf_drv_saadc_uninit();
        
        
    }
}


void es_battery_voltage_init(void)
{
    ret_code_t err_code = nrf_drv_saadc_init(NULL, saadc_event_handler);

    APP_ERROR_CHECK(err_code);

    nrf_saadc_channel_config_t config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);
    err_code = nrf_drv_saadc_channel_init(0, &config);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_sample();
    APP_ERROR_CHECK(err_code);
}


void es_battery_voltage_get(uint16_t * p_vbatt)
{
    VERIFY_PARAM_NOT_NULL_VOID(p_vbatt);

    *p_vbatt = m_batt_lvl_in_milli_volts;
    if (!nrf_drv_saadc_is_busy())
    {
        ret_code_t err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
        APP_ERROR_CHECK(err_code);

        err_code = nrf_drv_saadc_sample();
        APP_ERROR_CHECK(err_code);
    }
}
int main(void)

{
    initialize();
    start();

    nrf_gpio_pin_clear(POWER);
    nrf_gpio_pin_clear(ONOFF_SERVER_R_LED);
    nrf_gpio_pin_clear(ONOFF_SERVER_G_LED);
    nrf_gpio_pin_clear(ONOFF_SERVER_B_LED);

    nrf_gpio_cfg_input(DIPSW_0,NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_input(DIPSW_1,NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_input(DIPSW_2,NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_input(DIPSW_3,NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_output(BUZZER);

    int sw_1  = (nrf_gpio_pin_read(DIPSW_0) == 0)*1;
    int sw_2  = (nrf_gpio_pin_read(DIPSW_1) == 0)*2;
    int node_number = 1 + sw_1 + sw_2;

    es_battery_voltage_init();
    uint16_t vbatt;
    uint16_t battVolt;
    uint16_t battVolt_1;
    int battVolts[5];
    int battVolts_new[3];
    int i=0;
    int tmp;

    while (true)
    {
        //counter=0;
        (void)sd_app_evt_wait();

        es_battery_voltage_get(&vbatt);
        battVolt=(uint16_t)vbatt;
        battVolt_1=battVolt;
        battVolts[i]=battVolt_1;

        //__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "battery_voltage=%d",battVolt_1);

        if(i<3)
        {
            i++;
            nrf_delay_ms(1);     
        }
        else
        {
            i=0;
            for (int k=0; k<5; ++k) 
            {
                for (int j=k+1; j<5; ++j) 
                {
                    if (battVolts[k] > battVolts[j]) 
                    {
                        tmp =  battVolts[k];
                        battVolts[k] = battVolts[j];
                        battVolts[j] = tmp;
                    }
                }
            }
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "battery_voltage=,%d\n",(battVolts[1]+battVolts[2]+battVolts[3])/3);
            
            if((battVolts[1]+battVolts[2]+battVolts[3])/3<3300)
            {
                //indicate_battery_voltage();
            }

            //nrf_delay_ms(5000);

        }
       
       
    }
}

Parents
  • Hello,

    I am implementing a battery voltage monitoring function, but the value of the output voltage hardly changes even if I keep using power.

    Which battery are you using, and how have you verified that the voltage measured by the SAADC is incorrect?
    The mapping of the battery discharge curve in battery_level_in_percent is not a linear and smooth function, which might produce the same percentage of estimated battery power left with varying measured voltages.

    Could you elaborate more on the intentions behind your functions? To me it seems that you may never use es_battery_voltage_get because the init function both initializes the SAADC and takes a sample, which will trigger the DONE event (if the buffer is size 1) which ultimately uninit's the SAADC again. The intention and flow of the program is not quite clear to me. Do you wish to have a single function you can call every once in a while to get a battery measurement reading, or is there anything more you are looking to do in addition to this?

    Did you see my comment on your previous post in reference to the DIODE_FWD_VOLT_DROP_MILLIVOLTS you are using, by the way?

    Best regards,
    Karl

  • Mr. Carl.

    Thank you very much for your help. Thank you very much for your answer to my question.
    As for the first question, I am using three AA NiMH batteries, and the reason why I felt that the voltage of the second point was not correct was because the voltage value did not change at all, even though the LED light output by the microcontroller was not glowing. The second reason why I felt the voltage was incorrect was because the voltage value did not change at all even though the LED light output by the microcontroller was no longer glowing.
    First of all, "es_battery_voltage_init()" is a function to initialize the module for battery voltage.
    Next, "es_battery_voltage_get()" is literally a function to read out the battery voltage, and the details are described in https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.meshsdk.v4.2.0%2Fmd_doc_getting_started_mesh_quick_start.html.
    I need a single function to call from time to time to get the battery readings.
    I have checked your answer regarding "DIODE_FWD_VOLT_DROP_MILLIVOLTS". Thank you very much.
    Thank you very much for your time, and I look forward to working with you. Thank you very much in advance.

    LemonCake

Reply
  • Mr. Carl.

    Thank you very much for your help. Thank you very much for your answer to my question.
    As for the first question, I am using three AA NiMH batteries, and the reason why I felt that the voltage of the second point was not correct was because the voltage value did not change at all, even though the LED light output by the microcontroller was not glowing. The second reason why I felt the voltage was incorrect was because the voltage value did not change at all even though the LED light output by the microcontroller was no longer glowing.
    First of all, "es_battery_voltage_init()" is a function to initialize the module for battery voltage.
    Next, "es_battery_voltage_get()" is literally a function to read out the battery voltage, and the details are described in https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.meshsdk.v4.2.0%2Fmd_doc_getting_started_mesh_quick_start.html.
    I need a single function to call from time to time to get the battery readings.
    I have checked your answer regarding "DIODE_FWD_VOLT_DROP_MILLIVOLTS". Thank you very much.
    Thank you very much for your time, and I look forward to working with you. Thank you very much in advance.

    LemonCake

Children
  • Hello LemonCake,

    LemonCake said:
    Thank you very much for your help. Thank you very much for your answer to my question.

    No problem at all, I am happy to help!

    LemonCake said:
    As for the first question, I am using three AA NiMH batteries, and the reason why I felt that the voltage of the second point was not correct was because the voltage value did not change at all, even though the LED light output by the microcontroller was not glowing. The second reason why I felt the voltage was incorrect was because the voltage value did not change at all even though the LED light output by the microcontroller was no longer glowing.

    Thank you for clarifying. It is hard to debug this based on your assumption that the SAADC is measuring incorrectly, since we will have nothing to test the different debugging steps against.
    When you suspect that a measurement is not correct you should verify the actual value with an external tool that you know is correct, so that you can compare their results and start to debug why and how they are diverging.
    In this case, it would be very helpful if you could verify the voltage of the three AA batteries by another source, such as a multimeter or oscilloscope.

    Even so, there are a few other things we may look into based on your suspicion. Have you implemented the battery_level_in_percent function yourself, and if so, how have you done so?
    If I recall correctly the battery_level_in_percent function from the example is specifically made for a coincell battery, so its discharge curve will not match that of 3 AA batteries.

    LemonCake said:
    I need a single function to call from time to time to get the battery readings.

    Will it be called periodically (on a timer), or asynchronously(every now and then)?
    Either way I think the example you have looked at right now is not the best to achieve this.
    In case of the former, please have a look at this example instead - it demonstrates a low power periodic sampling on a timer. If the time between each sampling is very long it may save you some power to uninit the SAADC between each sampling.
    In case of the latter, I would recommend that you use the nrfx SAADC driver directly by init'ing the SAADC, and then calling nrfx_saadc_sample_convert to retrieve a single sample from the specified channel.

    Best regards,
    Karl

Related