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

SAADC Burst oversampling

Hi. 

I have issue measure ADC value from battery.

setup is NRF52832, SDK 15.3.0, S332, using ANT+, BLE, GPIOTE, PPI, RTC, APPTIMER, LOW_PWM

my goal is measure periodically voltage using saadc.

process is timer interrupt --- ppi --- saadc.

I got value just one sampling. it was normal.

what I want is values of several times measured is averaged.

So I use burst and oversampling.

1. I saw document and if set oversampling is 8x means that sampled as fast as 2^8 and averaged the values? is it right?

2. 8x oversampling value  is average of 256 sampled value?

3.

under below is code about saadc.

void battery_init()
{
  ret_code_t err_code; 

  voltage = 0; 
  count = 0;  
  battery_cutoff_state = false;
  
  err_code = nrf_drv_saadc_init(&saadc_config, user_battery_saadc_handler);
  APP_ERROR_CHECK(err_code);
 
  if(!calibration_onoff_state)
  {
    calibration_onoff_state = true;
    Calibration_init();  // excute before channal init
  }  

  err_code = nrf_drv_saadc_channel_init(BATTERY_SAADC_CHANNEL, &channel_config);
  APP_ERROR_CHECK(err_code);

  err_code = nrf_drv_saadc_buffer_convert(battery_adc_buffer[0], BATTERY_ADC_BUFFER_SIZE);
  APP_ERROR_CHECK(err_code);

  err_code = nrf_drv_saadc_buffer_convert(battery_adc_buffer[1], BATTERY_ADC_BUFFER_SIZE);
  APP_ERROR_CHECK(err_code);   

  battery_sample_event_init();
  
}

static void battery_sample_event_init()
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);


    uint32_t timer_compare_event_addr = rtc_get_battery_event_addr();
    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);

    err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

    APP_ERROR_CHECK(err_code);

    NRF_LOG_INFO("SAADC PPI Init Done\n");
}

static void user_battery_saadc_handler(nrf_drv_saadc_evt_t const * p_event)
{
   nrf_saadc_value_t *value =  p_event->data.done.p_buffer; // nrf_saadc_value_t = uint16_t
   ret_code_t err_code;
   switch(p_event->type)
   {    
     case NRF_DRV_SAADC_EVT_CALIBRATEDONE : 
       NRF_LOG_INFO("SAADC Calibration Done");
       CaliState = false;
       break;
     case NRF_DRV_SAADC_EVT_DONE : 
      rtc_battery_timer_stop();

      err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, BATTERY_ADC_BUFFER_SIZE);
      APP_ERROR_CHECK(err_code);
       
      NRF_LOG_INFO("*****ADC VALUE");
      NRF_LOG_INFO("------ %d -----",p_event->data.done.p_buffer[0]);
      NRF_LOG_INFO("*****");      
     
       break;     
     default:
       break;
   }
}

void battery_config_value_init()
{
  memset(&saadc_config, 0 , sizeof(saadc_config));
  saadc_config.resolution         = (nrf_saadc_resolution_t)NRFX_SAADC_CONFIG_RESOLUTION;
  saadc_config.oversample         = (nrf_saadc_oversample_t)NRFX_SAADC_CONFIG_OVERSAMPLE;
  saadc_config.interrupt_priority = NRFX_SAADC_CONFIG_IRQ_PRIORITY;
  saadc_config.low_power_mode     = NRFX_SAADC_CONFIG_LP_MODE;

  memset(&channel_config, 0 , sizeof(channel_config));
  channel_config.resistor_p   = NRF_SAADC_RESISTOR_DISABLED;
  channel_config.resistor_n   = NRF_SAADC_RESISTOR_DISABLED;
  channel_config.gain         = NRF_SAADC_GAIN1_6;
  channel_config.reference    = NRF_SAADC_REFERENCE_INTERNAL;
  channel_config.acq_time     = NRF_SAADC_ACQTIME_10US;
  channel_config.mode         = NRF_SAADC_MODE_SINGLE_ENDED;
  channel_config.burst        = NRF_SAADC_BURST_ENABLED;
  channel_config.pin_p        = (nrf_saadc_input_t)(NRF_SAADC_INPUT_AIN0);
  channel_config.pin_n        = NRF_SAADC_INPUT_DISABLED;

  cal_value_set();
}

setting value is

resolution is 10bit

oversample is 8x

low power mode

burst enable

acqtime is 10us

input gpio is AIN0

buffer size 1

timer is 5s. 

after first nrf_drv_saadc_sample_task_get() , NRF_DRV_SAADC_EVT_DONE is not triggerd.

after second nrf_drv_saadc_sample_task_get(),  NRF_DRV_SAADC_EVT_DONE is triggered but value is strange. always minus value. number is random.

third times. the value is normal. it is what i want.

My opinion, it is related to double buffer? and  not enough fulfilled?

if I add  nrf_drv_saadc_sample func after saadc_buffer_convert in battery_init, it start second. 

please give me advice

Thank you.

Parents
  • Hi,

    1. I saw document and if set oversampling is 8x means that sampled as fast as 2^8 and averaged the values? is it right?

    Yes. Oversampling 8x means 2^8=256. And since you also use burst you just need to trigger the SAMPLE task once for each oversampled sample, instead of once for every raw sample.

    2. 8x oversampling value  is average of 256 sampled value?

    Yes.

    after first nrf_drv_saadc_sample_task_get() , NRF_DRV_SAADC_EVT_DONE is not triggerd.

    after second nrf_drv_saadc_sample_task_get(),  NRF_DRV_SAADC_EVT_DONE is triggered but value is strange. always minus value. number is random.

    I do not immediately spot a problem. But I also dont understand the comment. Calling nrf_drv_saadc_sample_task_get() multiple times should not be relevant. Do you mean nrf_drv_saadc_buffer_convert()?

    In any case, you should just need to trigger the SAMPLE task once, this is the basic difference between using burst mode and not. (if using burst mode, trigger SAMPLE task once, and oversampling happens automatically. If not, trigger SAMPLE every time for as many times as you have configured oversampling.

  • yes right.

    but in my code, first trigger and second trigger sample task is not result normally.

    I found the cause.

    If I remove calibration func, my issue is not happened.

    I executed calibration before trigger sample.

    1. If calibration is not excute, How much adc value is error depend on temperature? max and min 

    2. if after calibration, saadc uninit and re saadc init, the calibration offset value is still remain?

    after calibration, I try saadc uninit and one more init saadc, the issue is disppear.

    3. if select 256x, is it right 2^256???.  it too huge number. It take so long time.

    thanks you,

  • Hi,

    I see. Then this may be related to erratum 86. You can employ the workaround or simply ignore the first sample after calibration. Note that there is no need to calibrate frequently. The SAADC has a temperature-dependent offset, but the temperature does not change significantly you can ignore this. Alternatively, you can calibrate only if the temperature has changed significantly, or by other methods.

    1. We do not have official numbers on that. Essentially you should always calibrate at least once.

    2. Yes, the calibration value is still valid, since this does not reset the peripheral itself. 

    3. I was not clear. Setting the value to 8 gives you 256 (2^8), but if you are referring to the numbers used in the define names in nrfx, then 8x is mapped to 3, which is 8 (2^3=8). Similarly, 256x is mapped to 8, which is 2^8=256. This is the highest possible value.

Reply Children
No Data
Related