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

Race condition in starting the ADC following calibration

Race condition in starting the ADC following calibration. I am trying to start the ADC in the interrupt routine when the end calibration is reported, however I have unreliable results when converting several channels with a buffer. I see the first channel converted and then I see it is converted a second time followed by the remaining channels that are placed in the buffer and in the first location of the second buffer. On next conversion sample, two samples are placed in what is now the first buffer and the final sample is placed in the second buffer.

As a workaround I calibrate separately and sometime later start the conversion.

  • You might want to check the Errata as the 52832 has several for the SAADC.  Errata 86 may apply.

  • Thank you, this was helpful. I therefore modified my code to the following. However note that the **** line no longer works as intended as the interrupt routine now checks for a STOPPED event and set the SAADC to IDLE state and the second buffer is not passed in the following interrupt routine..

    Regards

    Malcolm

    void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    {
        ret_code_t err_code;

        switch (p_event->type) {
            case NRFX_SAADC_EVT_CALIBRATEDONE :
                /* workaround for errata 86 */
                nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
                // Wait for ADC being stopped.
                bool result;
                NRFX_WAIT_FOR(nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED), 1000, 0, result);
                NRFX_ASSERT(result);

                /* configure each of the channels to be used */
                channel_config.gain = NRF_SAADC_GAIN1_4;
                channel_config.acq_time = NRF_SAADC_ACQTIME_3US;

                /* differential input for Vdd */
                channel_config.pin_p = NRF_SAADC_INPUT_AIN4;
                channel_config.pin_n = NRF_SAADC_INPUT_AIN2;
                err_code = nrf_drv_saadc_channel_init(0, &channel_config);
                APP_ERROR_CHECK(err_code);
                
                /* differential input for Vo */
                channel_config.pin_p = NRF_SAADC_INPUT_AIN2;
                channel_config.pin_n = NRF_SAADC_INPUT_AIN1;
                err_code = nrf_drv_saadc_channel_init(1, &channel_config);
                APP_ERROR_CHECK(err_code);

                /* initalise buffers */
                err_code = nrfx_saadc_buffer_convert(temp_sample_buffer1, BUFFER_SAMPLES);
                APP_ERROR_CHECK(err_code);

    ****            err_code = nrfx_saadc_buffer_convert(temp_sample_buffer2, BUFFER_SAMPLES);
                APP_ERROR_CHECK(err_code);

                /* start sampling */
                nrfx_saadc_sample();
                APP_ERROR_CHECK(err_code);
                break;
            case NRFX_SAADC_EVT_LIMIT :
            /* this is not used */
                break;
            case NRF_DRV_SAADC_EVT_DONE :
                thermometer_sample(p_event->data.done.p_buffer);
                break;
        }
    }

  • Further on this topic. It is not explicit in the documentation if SCAN mode also changes PSELN when the channel is changed. It appears not.

    Malcolm

  • Hi Malcolm

    Is this issue related to your other ticket at all? Do you still need support in this thread or are you happy with the results from that thread? 

    Please note that PSELN should be used when you want to measure negative values or you use differential measurements.

    Best regards,

    Simon

  • I need further help. I am using SCAN mode to sample 3 separate channels. I tried to sample each of these in differential mode and so set PSELP and PSELN (see code) but when looking at the data, it appears to be single ended, and SCAN mode does not change the PSELN pin.

Related