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?

  • the source resistance is 100kOhm, so we use 10us acquisition time

    we tested both Voltage source and battery(I am not sure about the source impedance), the result is beating frequently the same.

    I just tested using SAADC_OVERSAMPLE_OVERSAMPLE_Over2x, the result now beating frequently from 642 to 695, when at the same environment and configuration setting SAADC_OVERSAMPLE_OVERSAMPLE_Bypass get the result from 694 - 698, is that normal?

  • "I just tested using SAADC_OVERSAMPLE_OVERSAMPLE_Over2x, the result now beating frequently from 642 to 695,"

    That's not what I expect at all. Hmm, what kind of battery are you using?
    I suggest you power the VBAT-ON net from a benchtop PSU to remove any issue related to an under-specced battery. 
     

    "when at the same environment and configuration setting SAADC_OVERSAMPLE_OVERSAMPLE_Bypass get the result from 694 - 698"

    In a previous test, you reported 850 - 856, what has changed since then? 

  • In a previous test, you reported 850 - 856, what has changed since then? ” It's because I add an data processing after the adc result,  the result now beating frequently from 642 to 695 is because of this data processing . To avoid the impact of that, I delete the data processing this time, and do the experiment again.

    This time I use Voltage source, not battery.

    I use SAADC_CH_CONFIG_TACQ_10us and SAADC_OVERSAMPLE_OVERSAMPLE_Bypass, the SAADC output is beating frequently between 850 to 856.

    then I config SAADC_CH_CONFIG_TACQ_10us and SAADC_OVERSAMPLE_OVERSAMPLE_Over2x, I found that sometimes, it timeout. then I config SAADC_CH_CONFIG_TACQ_40us , it also  timeout sometimes. (the SAADC output is beating  between 855 to 856,but timeout is problem). 

    My question is :
    1) how to avoid timeout when I use SAADC_OVERSAMPLE_OVERSAMPLE_Over2x.

    2) when I use SAADC_OVERSAMPLE_OVERSAMPLE_Over2x, is the SAADC acquisition time  longer than SAADC_OVERSAMPLE_OVERSAMPLE_Bypass? 

    how long it takes in acquisition when I config SAADC_OVERSAMPLE_OVERSAMPLE_Over2x and SAADC_OVERSAMPLE_OVERSAMPLE_Bypass?

    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;

    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->RESULT.PTR = (uint32_t)saadc_value_data;

  • 1)
    What do you mean by timeout? That the EVENTS_END does not fire? 

    Why do you set RESULT.PTR after you've completed the sample conversion? The RESULT registers need to be set prior to enabling the START task. 

    2)
    Oversampling means that you take x times more samples and average them out. The time it takes to sample and convert one data point with oversampling is OVERSAMPLE x (Acquisition time + Conversion time), where the Conversion time is less than 2µs. 


  • NRF_SAADC->RESULT.PTR = (uint32_t)saadc_value_data; is to get the result in saadc_value_data,not to set the result.

    when I use (uint32_t)saadc_value_data[0] = NRF_SAADC->RESULT.PTR, I get 0, but when I use NRF_SAADC->RESULT.PTR = (uint32_t)saadc_value_data; I get the result. So there's a problem?

    timeout means EVENTS_END does not fire.

Reply Children
  • That's not how the SAADC works, the RESULT registers need to be set prior to enabling the START task.  see EasyDMA.

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

Related