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

SAADC nrf52832

hello, I have two questions for SAADC of nrf52832 when we use nrf52832 SAADC for voltage measurement.

The AIN0 is connected to the pin to be measured(the voltage is about 1.5V, use SE mode, so the negative
input will be shorted to ground internally ), the output of SAADC is 850(the result beating frequently between 850 to 856).

my SAADC config is bellow:
NRF_SAADC->CH[channel].CONFIG = ((SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos)|
(SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos)|
(SAADC_CH_CONFIG_GAIN_Gain1_3<< SAADC_CH_CONFIG_GAIN_Pos)|
(SAADC_CH_CONFIG_REFSEL_Internal<<SAADC_CH_CONFIG_REFSEL_Pos)|
(SAADC_CH_CONFIG_TACQ_10us<< SAADC_CH_CONFIG_TACQ_Pos)|
(SAADC_CH_CONFIG_MODE_SE<<SAADC_CH_CONFIG_MODE_Pos) );
NRF_SAADC->CH[channel].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput0;
NRF_SAADC->CH[channel].PSELN = SAADC_CH_PSELP_PSELP_NC;
NRF_SAADC->RESULT.MAXCNT = 1;
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_10bit;
NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Bypass;
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
NRF_SAADC->INTENSET = SAADC_INTENSET_END_Msk;

then read the result:

NRF_SAADC->TASKS_START = 1;
NRF_SAADC->TASKS_SAMPLE = 1;

uint32_t saadc_timeout = 100000;
while ((NRF_SAADC->EVENTS_END == 0U)&& (saadc_timeout > 0))
{
saadc_timeout--;
}
NRF_SAADC->EVENTS_END = 0;

NRF_SAADC->RESULT.PTR = (uint32_t)saadc_value_data;


My question is :
1) RESULT = [V(P) – V(N) ] * GAIN/REFERENCE * 2(RESOLUTION - m)
RESULT = 850/1024 = 0.83
[V(P) – V(N) ] * GAIN/REFERENCE * 2(RESOLUTION - m) = 1.5V * Gain1_3 / (0.6V * 2) = 0.417, it's not equall to RESULT, why?


2) The SAADC output is beating frequently between 850 to 856(for example 851,853,855...), is it normal?

Parents
    1. The statement "m=0 if CONFIG.MODE=SE, or m=1 if CONFIG.MODE=Diff" in the PS is wrong, and should be reversed, ie. m=1 if MODE == SE. 

      I tested with both SE and DIFF, and SE outputs a result that is double that of DIFF, which makes sense as DIFF has a range of +/- 0.6V over 1024 codes whereas SE only uses +0.6V over 1024 bits. 

    2. There is a fair amount of Gain error in the ADC core, there's also Integral and Differential Non-Linearity. See Electrical specification for details. 

      Other possible error sources is noise in the signal, or too short acquisition time with regards to the source impedance(see Acquisition time). 

    You should also wait for the STARTED event before you trigger the SAMPLE task, otherwise, you might get a hardfault if the EasyDMA controller tries to write data to address 0x00000000, the default value of RESULT.PTR. This might happen if a conversion is completed before the SAADC has updated the RAM address of the EasyDMA controller.

  • thank you, I have add an wait for the STARTED event before you trigger the SAMPLE task.
    and I also tried to extend the acquisition time, but the SAADC output is beating frequently between 850 to 856 too.

    there is another question:
    we have used nrf51822 before, the environment is the same as nrf52832, but the ADC output seems more stable than nrf52832, it only switch between 851 and 852,why nrf52832 seems not as good as nrf51822?

  • thank you, I seemed the example, the RESULT registers is set prior to enabling the START task.

    and the EVENTS_END does not fire when oversampling is OVERSAMPLE x is because the  BURST mode must be set.

    now the OVERSAMPLE mode works, but the result seems not better than bypass mode, both of them are  beating frequently between 850 to 856.

  • How much oversampling are you using? 

    Can you share your current SAADC driver code?

  • The oversampling is SAADC_OVERSAMPLE_OVERSAMPLE_Over2x

    void nrf_drv_saadc_init(void)
    {
    uint8_t channel = 0;

    NRF_SAADC->CH[channel].CONFIG = ((SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos)|
    (SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos)|
    (SAADC_CH_CONFIG_GAIN_Gain1_3<< SAADC_CH_CONFIG_GAIN_Pos)|
    (SAADC_CH_CONFIG_REFSEL_Internal<<SAADC_CH_CONFIG_REFSEL_Pos)|
    (SAADC_CH_CONFIG_TACQ_10us<< SAADC_CH_CONFIG_TACQ_Pos)|
    (1<< 24)|
    (SAADC_CH_CONFIG_MODE_SE<<SAADC_CH_CONFIG_MODE_Pos) );
    NRF_SAADC->CH[channel].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput0;
    NRF_SAADC->CH[channel].PSELN = SAADC_CH_PSELP_PSELP_NC;
    NRF_SAADC->RESULT.MAXCNT = 1;
    NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_10bit;
    NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Over2x;
    NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
    NRF_SAADC->INTENSET = SAADC_INTENSET_END_Msk;
    }

    Then read:

    NRF_SAADC->RESULT.PTR = (uint32_t)saadc_value_data;
    NRF_SAADC->TASKS_START = 1;
    while (NRF_SAADC->EVENTS_STARTED == 0U);
    NRF_SAADC->TASKS_SAMPLE = 1;
    //
    uint32_t saadc_timeout = 100000;
    while ((NRF_SAADC->EVENTS_END == 0U)&& (saadc_timeout > 0))
    {
    saadc_timeout--;
    }
    NRF_SAADC->EVENTS_END = 0;
    NRF_SAADC->TASKS_STOP = 1;

  • That looks good. I suggest you increase oversampling to at least 16x. Right now you take the average of two samples which won't improve the variance much. 

Reply Children
No Data
Related