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?

 

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

Reply Children
Related