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.

  • Hi Malcolm

    Please take a look at this thread, where my colleague explains how to set up sampling multiple channels in SCAN mode. Keep in mind that you can't have oversampling enabled on any channel while in scan mode, as these modes are incompatible with one another.

    Best regards,

    Simon

  • I have multiple channels working in SCAN mode, that is not my problem, rather I wanted to make a different differential measurement on each channel in the scan (see code), and this appears not to work. Instead it appears each channel works as single ended measurement and PSELN is not used in SCAN mode.

    I have workaround by using single ended for AIN2, AIN4 and sampling AIN1 and then subtracting.

  • Hi Malcolm

    Can you upload your input signals and the output you're getting, as we'd like to take a look, to see if we can spot what's actually going on in your project? As far as I know, there shouldn't be any problems with using differential measurements like this, so I'm at a loss of what this could be.

    Best regards,

    Simon

  • In my project I am trying to determine temperature by measuring resistance of an NTC. I have set up the following circuit

                /*
                                VDD
                                |
                             ---
                            |        |    RVdd
                            |        |
                             ---
                                |____Vdd (AIN4)
                                |
                             ---
                            |        | R2
                            |        |
                             ---
                                |_____Vo (AIN2)
                                |
                             ---
                            |        | R1
                            |        |
                             ---
                                |_____Vg (AIN1)
                                |
                             ---
                            |        | Rgnd
                            |        |
                             ---
                        ____|_____




                R1/R2 = (Vo - Vg) / (Vdd - Vo)

                R1 = R2 * (Vo - Vg) / (Vdd - Vo)

                We make R1 unknown and R2 known, so find R1 as Rt
                */

    This is my current code

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

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

                /* input for Vo */
                channel_config.pin_p = NRF_SAADC_INPUT_AIN1;
                err_code = nrf_drv_saadc_channel_init(2, &channel_config);
                APP_ERROR_CHECK(err_code);

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

                /* start sampling */
                nrfx_saadc_sample();
                APP_ERROR_CHECK(err_code);

            case NRF_DRV_SAADC_EVT_DONE :
                thermometer_sample(p_event->data.done.p_buffer);
                break;
        }

    In this example R1 = R2

    When I break on sample done I get

    temp_sample_buffer[0] = 3523

    temp_sample_buffer[1] =  2411

    temp_sample_buffer[2] = 1303

    I use Rgnd as the analogue ground in this chip is rather poor as is takes all the digital current.

    This approach gives me extremely good results as I average 1000 samples of each, effectively giving 20 bit accuracy (1 in 1000), and averaging reduces the noise.

    I change the code to

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

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

                /* input for Vo */
                channel_config.pin_p = NRF_SAADC_INPUT_AIN1;
                err_code = nrf_drv_saadc_channel_init(2, &channel_config);
                APP_ERROR_CHECK(err_code);

                /* initalise buffers */
                err_code = nrfx_saadc_buffer_convert(temp_sample_buffer, 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;

    I get

    temp_sample_buffer[0] = 3491

    temp_sample_buffer[1] =  2391

    temp_sample_buffer[2] = 1289

    buffer[0] should be equal to buffer[1], but isn't and voltages are similar to the first case with single ended.

    Regards

    Malcolm

  • Hi Malcolm

    It won't suffice to just set PSELN, you'll also have to change mode in the channel config. Please see this GitHub link for reference. I don't see that you do this in the snippet you've posted. Can you show us how you configure the ADC in your project?

    Best regards,

    Simon

Related