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

SAADC - Calibration

nrf52832.

SDK14.2

Segger ES V3.34a

I am using nrf_drv_saadc_calibrate_offset() and find the next sample immediately after the calibration is erroneous.

There is an errata for this [86].  This suggests the following...

Workaround

Calibration should follow the pattern STOP -> STOPPED -> CALIBRATEOFFSET -> CALIBRATEDONE -> STOP -> STOPPED -> START.

I have tried to implement this, which has improved the problem, although 1 in 4 calibrations still cause the erroneous first sample.

implemented every 100 ADC events

nrf_drv_saadc_abort();                                                               // Abort all ongoing conversions. Calibration cannot be run if SAADC is busy

NRF_LOG_INFO("SAADC calibration starting... \r\n");

while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS);    //Trigger calibration task

nrf_saadc_disable();
while(NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos))
{}


nrf_saadc_enable();
while(NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos))
{}

Then...continue with ADC samples as normal.

 

I am tempted not to bother with the workaround and just discard the first sample after a calibration.

Has anyone else implemented this workaround successfully?

 

  • Hello,

    I have never personally tested this workaround before. Could you please upload the project where you do the calibration, so that I can test it?

     

    Best regards,

    Edvin

  • I can set the frequency for calibration with an event timer...

    //Evaluate if offset calibration should be performed. Configure the SAADC_CALIBRATION_INTERVAL constant to change the calibration frequency


    if((m_adc_evt_counter % SAADC_CALIBRATION_INTERVAL) == 0 && p_event->type == NRF_DRV_SAADC_EVT_DONE )
    {
    nrf_drv_saadc_abort(); // Abort all ongoing conversions. Calibration cannot be run if SAADC is busy
    //while(NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos))

    m_saadc_calibrate = true; // Set flag to trigger calibration in main context when SAADC is stopped
    }

    In main()...

    if(m_saadc_calibrate == true)
    {
    //Workaround
    //Calibration should follow the pattern STOP -> STOPPED -> CALIBRATEOFFSET -> CALIBRATEDONE -> STOP -> STOPPED -> START.


    NRF_LOG_INFO("SAADC calibration starting... \r\n"); 


    m_saadc_calibrate = false;


    while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS); //Trigger calibration task

    nrf_saadc_disable();
    while(NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos))
    {}


    nrf_saadc_enable();
    while(NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos))
    {}



    }

    It does improve but it doesn't eliminate the problem.  

    These are the readings from Channel 1 ADC with input tied to VDD.  I take five readings so that it can be averaged, but the first reading is -140 (in this case).  This does not happen unless we calibrate.

    <info> app: Calibration Done: 41111
    <info> app: Actual Seconds powered up: 161678


    <info> app: Actual Seconds powered up: 161679
    <info> app: Actual Seconds powered up: 161680
    <info> app: Actual temperature: 23
    <info> app: ADC event number: 41111
    <info> app: Channel -1 value: -140

    <info> app: Channel -1 value: 11387

    <info> app: Channel -1 value: 13027

    <info> app: Channel -1 value: 13018

    <info> app: Channel -1 value: 13028

    My ADC settings for channel 1

    //set configuration for saadc channel 1
    channel_1_config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;
    channel_1_config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;
    channel_1_config.gain = NRF_SAADC_GAIN1_6;
    channel_1_config.reference = NRF_SAADC_REFERENCE_INTERNAL;
    channel_1_config.acq_time = NRF_SAADC_ACQTIME_40US;
    channel_1_config.mode = NRF_SAADC_MODE_SINGLE_ENDED;
    channel_1_config.pin_p = (nrf_saadc_input_t)(NRF_SAADC_INPUT_AIN1);
    channel_1_config.pin_n = NRF_SAADC_INPUT_DISABLED;

    saadc_config.resolution = NRF_SAADC_RESOLUTION_14BIT; //Set SAADC resolution to 12-bit. This will make the SAADC output values from 0 (when input voltage is 0V) to 2^12=2048 (when input voltage is 3.6V for channel gain setting of 1/6).


    saadc_config.oversample = NRF_SAADC_OVERSAMPLE_8X; //Set oversample to 8x. This will make the SAADC output a single averaged value when the SAMPLE task is triggered 8 times.

  • Hello,

    I have tried to run calibration in the saadc example in SDK14.2, but I can't see the same behavior as you. Would it be possible to send the project, or if you can't, maybe a strip down version that is still replicating the issue?

     

    Best regards,

    Edvin

  • Hi Edvin,

    Thanks for trying the workaround.  Does this mean you have seen the first sample error after calibration without the work around and then repeated the test with the work around, resulting in no error ?

    Regards

    Paul

  • Hello Paul,

    No. I have not. I don't see the error when trying to calibrate at all. Probably because the error only occurs in some corner cases, and I think that the ACQTIME is particularly relevant.

    But I have not been able to set up a mix of settings that triggers the issue. If you could send a project where the issue is replicated, then I can look into it. It will go much faster than if I have to create this myself. I am sorry for the inconvenience.

     

    BR,

    Edvin

Related