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

How calibration SAADC Negative Value

hello Dev Zone.

i need help.

now i'm try to make IR Line-tracer and detector

how ever, when my detecting object far then range,

"saadc" value change to Negative

I asume that it will goto 0, but change to "-" Velue
please check my code and help me

int NRF52Pin::initialiseSAADC()
{
    static bool isConfig = false;

    if(!isConfig)
    {
        isConfig = true;
        
        // Configure the SAADC resolution.
        NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_12bit << SAADC_RESOLUTION_VAL_Pos;

        // No automatic sampling, will trigger with TASKS_SAMPLE.
        NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos;

        // Enable SAADC (would capture analog pins if they were used in CH[0].PSELP)
        NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos;
       
        // Calibrate the SAADC (only needs to be done once in a while)
        NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;
        while (NRF_SAADC->EVENTS_CALIBRATEDONE == 0);
        NRF_SAADC->EVENTS_CALIBRATEDONE = 0;
        while (NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy <<SAADC_STATUS_STATUS_Pos));
    }
    // Configure result to be put in RAM at the location of "result" variable.
    NRF_SAADC->RESULT.MAXCNT = 1;
    // adcSample -> int16_t adcSample
    NRF_SAADC->RESULT.PTR = (uint32_t)&adcSample;
    
    return DEVICE_OK;
}

    ...
    ...
    // no existing channel found
    if (channel == -1) return DEVICE_NOT_SUPPORTED;
    else
    {
        initialiseSAADC();
    }

    // Configure the SAADC channel with VDD as positive input, no negative input(single ended).
    NRF_SAADC->CH[0].PSELP = ((unsigned long)channel) << SAADC_CH_PSELP_PSELP_Pos;
    NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;
    
    // Start the SAADC and wait for the started event.
    NRF_SAADC->TASKS_START = 1;
    while (NRF_SAADC->EVENTS_STARTED == 0);
    NRF_SAADC->EVENTS_STARTED = 0;

    // Do a SAADC sample, will put the result in the configured RAM buffer.
    NRF_SAADC->TASKS_SAMPLE = 1;
    while (NRF_SAADC->EVENTS_END == 0);
    NRF_SAADC->EVENTS_END = 0;

    return adcSample;
}
...
...

Thanks,

Best Regards

Empe.

  • Hi,

     

    The effective number of bits (ENOB) is less than 12, meaning that you will get noise; thus you can get negative values when sampling a grounded pin. Please see this thread for more info:

    https://devzone.nordicsemi.com/f/nordic-q-a/12287/nrf52-saadc-noise/46443#46443

     

    PS: Be sure to request the external HFCLK when using the SAADC, then release it after you are done with the conversion. The internal 64 MHz RC oscillator (HFINT) isn't very accurate, thus you measurements might also suffer if you're running using the HFINT

     

    Kind regards,

    Håkon

  • Hello, Håkon

    Thanks for help.

    I need to adjust the Gain and Resolution values well.

    I also checked the contents of the link you wrote down.

    It helped a lot.

    by the way, I am using all 7 SAADC, At this time

    The current method uses only CH [0] to sample one pin ADC per 1 START trigger.

    The time division method is being used.

    Could this be a problem? Now i'm using "Case 1" Format

    do i need to change to "Case 2" Format?

    // Case 1
    // Init Part
    // Channel Value Change 1 to 7 
    Init_SAADC
    {
        ...
        ...
        NRF_SAADC->CH[0].PSELP = ((unsigned long)channel) << SAADC_CH_PSELP_PSELP_Pos;
        NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;
        ...
        NRF_SAADC->TASKS_START = 1;
        while (NRF_SAADC->EVENTS_STARTED == 0);
        NRF_SAADC->EVENTS_STARTED = 0;
    
        // Do a SAADC sample, will put the result in the configured RAM buffer.
        NRF_SAADC->TASKS_SAMPLE = 1;
        while (NRF_SAADC->EVENTS_END == 0);
        NRF_SAADC->EVENTS_END = 0;
    
        return adcSample;
    }
    
    
    // Case 2
    // Init Part
    Init_SAADC
    {
        ...
        ...
        NRF_SAADC->CH[channel].PSELP = ((unsigned long)channel#1) << SAADC_CH_PSELP_PSELP_Pos;
        NRF_SAADC->CH[channel].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;
        ...
        ...
    }

    Best Regards,

    Empe.

  • Hi Empe,

     

    Empe said:

    by the way, I am using all 7 SAADC, At this time

    The current method uses only CH [0] to sample one pin ADC per 1 START trigger.

    It shouldn't matter wrt. the result on a specific pin, if you time-mux the sampling, or if you let the SAADC sample each input for you. SAADC will do time-multiplexing when several inputs are selected.

     

    What value are you sampling? It is to be expected that you can get a negative number from the SAADC.

     

    Kind regards,

    Håkon

  • Hello, Håkon

    i'm try to sampling IR Receive value,

    minimum 130mv to max 3.05V

    so i was changed the setting Gain 1/4, Ref VDD/4, 14Bit resolution.

    What value are you sampling? It is to be expected that you can get a negative number from the SAADC.

    yes, I modified it according to your advice, my saadc looks like more stable,

    but as you say still negative input value is looking.

    Best Regards,

    Empe.

Related