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

ADC fastest channel sampling rate

I need to sample ADC channel at the fastest deterministic rate.

If i use burst mode with 3us acquisition time, do i get a sample exactly every 5us? 

does t(conv) is always 2us or does it vary?

should i use a timer instead of burst mode to get the rate predicted?

If yes - can i use timer that clocks every 5us when using t(acq)=3us? or can i go lower?

  • My concern is that when END event is received and i get an interrupt, by the time i trigger the START task i may miss real samples (assuming i am interrupted by the SD priority 0 interrupt that may delay my interrupt processing by up to 250us when i am connected via BLE). I am sampling every 5us.

    I understand from the "buffer-swap issue" link above, that the solution is to do this: "Use PPI to trigger START task on an END event. This will avoid the delayed triggering og the START task due to a queued interrupt generated by the END event, but in the case of high sample frequency and long delays, it can cause your buffer to be overwritten before you are able to process the buffer. In case of using this solution, it is necessary to use double buffering and large enough buffers to avoid data loss."

  • Yes, this is a possibility. If you require every sample to be triggered at a specific interval you will have to modify the driver or write your application in a way that use the double-buffer feature in a better way (e.g. setting the new buffer immediately when STARTED event is received). By doing this and using large enough buffers, you should not see any missed samples if you short END event with START event as described in the post.

  • Thanks i will do that.

    Last question that i have is to try and understand why do i see actually a sampling rate faster than 5us in the following code (as if the timer has no effect):

    nrf_drv_saadc_config_t saadc_config =
    {
    .resolution = NRF_SAADC_RESOLUTION_12BIT,
    .oversample = NRF_SAADC_OVERSAMPLE_DISABLED,
    .interrupt_priority = SAADC_CONFIG_IRQ_PRIORITY,
    .low_power_mode = SAADC_CONFIG_LP_MODE
    };
    err_code = nrf_drv_saadc_init(&saadc_config, train_adc_callback);
    APP_ERROR_CHECK(err_code);

    nrf_saadc_channel_config_t channel_config =
    {
    .resistor_p = NRF_SAADC_RESISTOR_DISABLED,
    .resistor_n = NRF_SAADC_RESISTOR_DISABLED,
    .gain = NRF_SAADC_GAIN1_4,
    .reference = NRF_SAADC_REFERENCE_VDD4,
    .acq_time = NRF_SAADC_ACQTIME_3US,
    .mode = NRF_SAADC_MODE_SINGLE_ENDED,
    .burst = NRF_SAADC_BURST_DISABLED,
    .pin_p = NRF_SAADC_INPUT_AIN1,
    .pin_n = NRF_SAADC_INPUT_DISABLED
    };

    // pin 1
    channel_config.pin_p = NRF_SAADC_INPUT_AIN1;
    channel_config.gain = NRF_SAADC_GAIN1_4,
    err_code = nrf_drv_saadc_channel_init(0, &channel_config);
    APP_ERROR_CHECK(err_code);

    // pin 2
    channel_config.pin_p = NRF_SAADC_INPUT_AIN2;
    channel_config.gain = NRF_SAADC_GAIN1, // 250-3350
    err_code = nrf_drv_saadc_channel_init(1, &channel_config);
    APP_ERROR_CHECK(err_code);

    // pin 3
    channel_config.pin_p = NRF_SAADC_INPUT_AIN3;
    channel_config.gain = NRF_SAADC_GAIN1_2, // 200-2700
    err_code = nrf_drv_saadc_channel_init(2, &channel_config);
    APP_ERROR_CHECK(err_code);

    // buffer 1
    err_code = nrf_drv_saadc_buffer_convert(adc_buffer[0], 669);
    APP_ERROR_CHECK(err_code);

    // buffer 2
    err_code = nrf_drv_saadc_buffer_convert(adc_buffer[1], 669);
    APP_ERROR_CHECK(err_code);

    // NRF_TIMER1 is a timer used to clock adc sampling of the 3 sensors we have
    NRF_TIMER1->MODE = (TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos);
    NRF_TIMER1->PRESCALER = 4; // 1mhz --> 1us
    NRF_TIMER1->CC[0] = 5 - 1; // 5us
    NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk;

    // ppi #6: connect adc timer to adc sampling
    NRF_PPI->CH[5].EEP = (uint32_t) &NRF_TIMER1->EVENTS_COMPARE[0];
    NRF_PPI->CH[5].TEP = (uint32_t) &NRF_SAADC->TASKS_SAMPLE;

    // Enable all ppi channels
    NRF_PPI->CHENSET = (PPI_CHENSET_CH5_Enabled << PPI_CHENSET_CH5_Pos);
    NRF_TIMER1->TASKS_START = 1; // start adc timer

  • This most likely happens because you have 3 channels enabled. Whenever your timer triggers the SAMPLE task, the SAADC will sample every enabled channel consecutively (see scan mode).

Related