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

saadc oversampling

HI, 

I'm developing it using NRF52832.

I'm updating the remaining battery capacity using saadc. However, the battery value is not stable because the value obtained from saadc is not constant. 

Can I stabilize the saadc value using oversampling?

Is there anything I missed when setting up the code for oversampling?

I'll attach the code.

<nrfx_saadc.h>

#define NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(PIN_P) \
{                                                   \
    .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_10US,           \
    .mode       = NRF_SAADC_MODE_SINGLE_ENDED,      \
    .burst      = NRF_SAADC_BURST_ENABLED,         \
    .pin_p      = NRF_SAADC_INPUT_AIN0,             \
    .pin_n      = NRF_SAADC_INPUT_DISABLED          \
}

<sdk_config.h>

// <o> NRFX_SAADC_CONFIG_OVERSAMPLE  - Sample period
 
// <0=> Disabled 
// <1=> 2x 
// <2=> 4x 
// <3=> 8x 
// <4=> 16x 
// <5=> 32x 
// <6=> 64x 
// <7=> 128x 
// <8=> 256x 

#ifndef NRFX_SAADC_CONFIG_OVERSAMPLE
#define NRFX_SAADC_CONFIG_OVERSAMPLE 8
#endif

<main.c>

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

}

void saadc_sampling_event_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
    APP_ERROR_CHECK(err_code);

    /* setup m_timer for compare event every 400ms */
    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 500);
    nrf_drv_timer_extended_compare(&m_timer,
                                   NRF_TIMER_CC_CHANNEL0,
                                   ticks,
                                   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                   false);
    nrf_drv_timer_enable(&m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
                                                                                NRF_TIMER_CC_CHANNEL0);
    uint32_t saadc_sample_task_addr   = nrf_drv_saadc_sample_task_get();

    /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                          timer_compare_event_addr,
                                          saadc_sample_task_addr);
    APP_ERROR_CHECK(err_code);
}


void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

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

        
        int i;
        NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);
        avg_mvolts=0;

        for (i = 0; i < SAMPLES_IN_BUFFER; i++)
        {
            /* get adc value */
            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;
            m_adc_evt_counter++;
        }
        avg_mvolts+=mvolts;
               
         /* Update the battery every minute. */
        if (m_adc_evt_counter>240)
        {
          battery_level=avg_mvolts/m_adc_evt_counter;

          /* battery level in percent to coin cell */
          battery_level_percent();
          NRF_LOG_INFO("battery_level: %d", battery_level);

          /* update battery percent */
         battery_level_update();
         m_adc_evt_counter=0;
        }
     
    m_adc_evt_counter++;
        
    /*Initialize variables.*/
    mvolts=0;
    avg_mvolts=0;
  }
}

Parents Reply
  • Values fluctuate within a single digit range.BUT There are times when the value fluctuates significantly.

    I also tried to derive the remaining battery capacity through the average value by setting the buffer to 1.However, the remaining battery capacity is not constant due to the large splashing values.

    Should we process additional signals?

Children
  • sabsari said:
    Values fluctuate within a single digit range

    measured in mV this is a good result. 


    sabsari said:
    BUT There are times when the value fluctuates significantly.

    how much is significantly ? 


    If the value fluctuation that is significant occurs as the same time that the CPU, Radio or some peripheral is doing something then there will be peaks and valleys on the VDD. So you will have to figure out if something else is going on during those significant fluctuations periods. 


    In addition you will also have to use the discharge curve of the battery that you are using. We only have it for CR2032.

    You can also average with oversampling, by having buffer size 1 and oversampling 16, then only one value will be written to the buffer anyways. 

    Regards,
    Jonathan

Related