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

nrf52840 saadc calibration error

After starting the program, I do the first calibration and read the data 30 times.
The standard deviation is between 2.0 and 2.3.

Perform 30 "Calibration -> Read Data" each time
The standard deviation is 3.8 to 4.7 degrees.

The offset varies with each calibration.
How can I minimize this?

I use the internal reference(0.6V) and 1/6 gain

  • Hi, because of Christmas holidays we will have to come back to you in the first week of January. Sorry for the inconvenience.

  • Hi 

    I will help Stian out with this case. 

    Can you let me know how you calibrate the ADC and trigger the sample? 

    Are you able to share a code sample, or a reference to the code used?

    Best regards
    Torbjørn

  • void saadc_calibration(void){
        uint8_t busy_count = 0;

        nrfx_saadc_abort();
        (void)nrfx_saadc_calibrate_offset();

        while (nrfx_saadc_is_busy() && busy_count++ < 100U) {
            nrf_delay_us(1U);
        }

        if (busy_count < 100U) {
            s_saadc_cal_state = (uint8_t)SAADC_CAL_DONE;
            NRF_LOG_INFO("SAADC calibration complete, busy_count %d", busy_count );
        }
        else {
            s_saadc_cal_state = (uint8_t)SAADC_CAL_RETRY;
            NRF_LOG_INFO("SAADC calibration fail");
        }
    }

    #define ADC_VOLTS(ADC_VALUE) \
        (int16_t)(((((double)ADC_VALUE * ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * \
        ADC_PRE_SCALING_COMPENSATION) + 0.5)
    #define SAMPLES_COUNT 10
    static nrf_saadc_value_t m_buffer[SAMPLES_COUNT];

    void saadc_read_data(uint8_t channel){
        uint8_t i = 0;
        uint16_t min_index = 0;
        uint16_t max_index = SAMPLES_COUNT - 1U;
        int16_t min = INT16_MAX;
        int16_t max = INT16_MIN;
        int32_t avg, sum = 0;
        int16_t res = 0;


        for (i = 0 ; i < SAMPLES_COUNT ; i++) {
            (void)nrfx_saadc_sample_convert(channel,&m_buffer[i]);
        }

        //Searching a min or max value
        for (i = 0 ; i < SAMPLES_COUNT ; i++) {
            if (min > m_buffer[i]) {
                min_index = i;
                min = m_buffer[i];
            }

            if (max < m_buffer[i]) {
                max_index = i;
                max = m_buffer[i];
            }

            sum += (int32_t)m_buffer[i];
        }

        //Check index
        if (max_index != min_index) {
            //Get an average value without the max value and the min value
            sum -= (int32_t)m_buffer[max_index];
            sum -= (int32_t)m_buffer[min_index];
            avg = (int32_t)(((double)sum / (SAMPLES_COUNT - 2U)) + 0.5);
        }
        else {
            avg = (int32_t)(((double)sum / SAMPLES_COUNT) + 0.5);
        }

        return ADC_VOLTS(avg);
    }

    The busy_count used in saadc_calibration() is a time out function.
    When busy_count exceeds 100 and s_saadc_cal_state becomes SAADC_CAL_RETRY, saadc_calibration() is called again from another place.
    (However, I get a busy count of 43 in all calibrations, and calibration succeeds.)

    Adc sampling actually reads 10 times and uses 8 averages excluding the minimum and maximum values.

  • I thought about additional correction methods.
    After executing nrfx_saadc_calibrate_offset(), it reads the analog pin set by pull-down and stores the value in cal_val.
    Ideally cal_val would be 0, but the value actually read is not 0.

    Now subtract the cal_val value every time adc sampling data is taken.
    In this way, more stable data with standard deviations of 1.63~2.6 were obtained.

    Is this the best?
    Please reply

  • Hi

    Yes, it is possible to do a manual offset calibration in the way that you describe. 

    The advantage of doing this is that you can sample the offset with higher resolution, and also sample multiple times and do averaging/filtering of the result in order to get a more reliable result. 

    If you run standard calibration for every sample it is expected that you will get higher standard deviation, since calibration is run at 10-bit only, and if the calibrated value keeps jumping between two calibration settings it can introduce noise to the measurements. 

    Normally it should only be necessary to recalibrate if you see a large change in temperature, so if possible you can also trigger calibration based on the temperature provided by the temp sensor in the nRF device. 

    Best regards
    Torbjørn

Related