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.

Parents
  • 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

Reply
  • 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

Children
No Data
Related