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

SAADC Measured sampling acquisition time is longer than expected

Hi there, I have set my SAADC to have an acquisition time of 3us, however when I toggle a pin before and after calling

nrfx_saadc_sample_convert

I measure the time of one sample to be closer to 34us. Can you tell me why this is so?

I don't require a timer like in the SAADC example, as I only need to do a bunch of measurements in rapid succession. Should I be using the oversampling/burst modes? I can't exactly figure out how they work...

My setup code:

    ret_code_t err_code;
    nrf_drv_saadc_config_t saadc_config;
    nrf_saadc_channel_config_t we_channel_config;
    nrf_saadc_channel_config_t batt_channel_config;

    //Configure SAADC
    saadc_config.low_power_mode = false;                                                  //Enable low power mode.
    saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT;                                 //Set SAADC resolution to 12-bit. This will make the SAADC output values from 0 (when input voltage is 0V) to 2^12=2048 (when input voltage is 3.6V for channel gain setting of 1/6).
    saadc_config.oversample = SAADC_OVERSAMPLE_OVERSAMPLE_Bypass;                         //Disable Oversample
    saadc_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;                           
	
    //Initialize SAADC
    err_code = nrfx_saadc_init(&saadc_config, NULL); 
    APP_ERROR_CHECK(err_code);

    /* 
        Working Electrode Channel 
    */
		
    //Configure SAADC Working Electrode Measurement Channel
    we_channel_config.reference = NRF_SAADC_REFERENCE_INTERNAL;        //Set internal reference 0.6V
    we_channel_config.gain = NRF_SAADC_GAIN1_5;                        //Set input gain to 1/5. The maximum SAADC input voltage is then (0.6)/(1/5) = 3V
    we_channel_config.acq_time = NRF_SAADC_ACQTIME_3US;                //Set acquisition time. Set low acquisition time to enable maximum sampling frequency of 200kHz. Set high acquisition time to allow maximum source resistance up to 800 kohm, see the SAADC electrical specification in the PS. 
    we_channel_config.mode = NRF_SAADC_MODE_DIFFERENTIAL;              //Set SAADC as differential, as we want to compare it to the analog reference
    we_channel_config.burst = NRF_SAADC_BURST_DISABLED;
    we_channel_config.pin_p = PS_ADC_INPUT;                            //Input is working electrode pin
    we_channel_config.pin_n = REF_ADC_INPUT;                           //Negative pin is the analog reference
    we_channel_config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;        //Disable pullup resistor on the input pin
    we_channel_config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;        //Disable pulldown resistor on the input pin
	
    //Initialize SAADC Working Electrode Measurement Channel
    err_code = nrfx_saadc_channel_init(WE_SAADC_CHANNEL, &we_channel_config);             //Initialize SAADC channel 0 with the channel configuration
    APP_ERROR_CHECK(err_code); 

My measurement code: I intend to increase the NUMBER_OF_SAMPLES

int32_t get_adc_value()
{
    ret_code_t err_code;
    int avg_adc = 0;
    nrf_saadc_value_t saadc_value;

    nrf_gpio_cfg_output(P1_PIN);
    nrf_gpio_pin_set(P1_PIN);       //TOGGLE PIN TO MEASURE TIME

    //do conversion
    for(int i = 0; i < NUMBER_OF_SAMPLES; i++){
        err_code = nrfx_saadc_sample_convert(WE_SAADC_CHANNEL, &saadc_value);
        avg_adc += saadc_value;
        // NRF_LOG_DEBUG("ADC value %d: %d", i, saadc_value);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_DEBUG("ADC error %d occured", err_code);
        }
    }
    nrf_gpio_pin_clear(P1_PIN);     //TOGGLE PIN TO MEASURE TIME
    avg_adc /= NUMBER_OF_SAMPLES;

    return avg_adc;
}

Thanks

Parents Reply Children
  • Ok I've done it your way, and still measure about 11us when the time should be <(tACQ+tCONV)×2OVERSAMPLE
    Im not using oversample, so it should be <5us


    Here's my new code:

    Event Handler:

    bool ADC_IN_PROGRESS = false;
    nrf_saadc_value_t adc_buf;
    void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
    {
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
            uint32_t err_code;
    
            adc_buf = p_event->data.done.p_buffer[0];
    
            nrf_gpio_pin_clear(P1_PIN);     //TOGGLE PIN TO MEASURE TIME
    
            //set up conversion again
            err_code = nrfx_saadc_buffer_convert(p_event->data.done.p_buffer, 1);
            if (err_code != NRF_SUCCESS){
                NRF_LOG_DEBUG("ADC error %d", err_code);
            }        
            APP_ERROR_CHECK(err_code);
    
            ADC_IN_PROGRESS = false;
        }
    }

    Take sample with nfrx_saadc_sample:

    int32_t get_adc_value()
    {
        ret_code_t err_code;
    
        nrf_gpio_cfg_output(P1_PIN);
        nrf_gpio_pin_set(P1_PIN);       //TOGGLE PIN TO MEASURE TIME
    
        //perform conversion
        ADC_IN_PROGRESS = true;
        err_code = nrfx_saadc_sample();
        if (err_code != NRF_SUCCESS){
            NRF_LOG_DEBUG("ADC error %d", err_code);
        }
        APP_ERROR_CHECK(err_code);
    
        //wait for adc to finish
        while(ADC_IN_PROGRESS);
        ADC_IN_PROGRESS = false;
    
        // return avg_adc;
        return adc_buf;
    }

  • but you're still toggling a pin via CPU with significant overhead due to the driver processing the END event.

    If you want to measure the sample time then you need to use PPI and GPIOTE to toggle the pin.

  • Ok I see, as I increase the oversampling, I get closer to what is expected

    Over 4x = 24us = 6us/sample
    Over 8x = 41us = 5.1us/sample
    Over 16x = 74us = 4.6us/sample

    Thanks for you help

Related