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

Understandin SAADC example

Hello,

I am having trouble understanding the SAADC example in the description. Can anybody tell me what do the following instructions in the code do?

1. NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos; /* does this mean that the sampling of the input voltage to the analog pin      will only happen when I set a certain bit?*/

2. NRF_SAADC->TASKS_SAMPLE = 1;                            // does this instruction make the sampler sample the input voltage?
    while (NRF_SAADC->EVENTS_END == 0);                  // what is this for?
    NRF_SAADC->EVENTS_END = 0;                                // what is this for?     

3. NRF_SAADC->TASKS_START = 1;                               //why do i need these lines of code since i already enabled the SAADC? do I need to call them every time I make a sample?
    while (NRF_SAADC->EVENTS_STARTED == 0);
    NRF_SAADC->EVENTS_STARTED = 0;                    

4. NRF_SAADC->TASKS_STOP = 1;                                 //do i need to call these lines of code every time I make a sample?
    while (NRF_SAADC->EVENTS_STOPPED == 0);
    NRF_SAADC->EVENTS_STOPPED = 0;    

5.  __WFE();                                                                       //what does the waiting for event macro do in this example?

6.  NRF_SAADC->RESULT.MAXCNT = 1;                        //what does this line do?
     NRF_SAADC->RESULT.PTR = (uint32_t)&result;       //why doesn't the result change its value, since I tried to print the value of it when I connect P0.02 to GND and then to VDD?

#include <nrf.h>

int main(void)
{
  volatile int16_t result = 0;
  volatile float precise_result = 0;

  // Start HFCLK from crystal oscillator, this will give the SAADC higher accuracy
  NRF_CLOCK->TASKS_HFCLKSTART = 1;
  while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
  NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;

  // Configure SAADC singled-ended channel, Internal reference (0.6V) and 1/6 gain.
  NRF_SAADC->CH[0].CONFIG = (SAADC_CH_CONFIG_GAIN_Gain1_6    << SAADC_CH_CONFIG_GAIN_Pos) |
                            (SAADC_CH_CONFIG_MODE_SE         << SAADC_CH_CONFIG_MODE_Pos) |
                            (SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) |
                            (SAADC_CH_CONFIG_RESN_Bypass     << SAADC_CH_CONFIG_RESN_Pos) |
                            (SAADC_CH_CONFIG_RESP_Bypass     << SAADC_CH_CONFIG_RESP_Pos) |
                            (SAADC_CH_CONFIG_TACQ_3us        << SAADC_CH_CONFIG_TACQ_Pos);

  // Configure the SAADC channel with VDD as positive input, no negative input(single ended).
  NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_VDD << SAADC_CH_PSELP_PSELP_Pos;
  NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;

  // Configure the SAADC resolution.
  NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_14bit << SAADC_RESOLUTION_VAL_Pos;

  // Configure result to be put in RAM at the location of "result" variable.
  NRF_SAADC->RESULT.MAXCNT = 1;
  NRF_SAADC->RESULT.PTR = (uint32_t)&result;

  // 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));

  // 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;

  // Convert the result to voltage
  // Result = [V(p) - V(n)] * GAIN/REFERENCE * 2^(RESOLUTION)
  // Result = (VDD - 0) * ((1/6) / 0.6) * 2^14
  // VDD = Result / 4551.1
  precise_result = (float)result / 4551.1f;
  precise_result; // to get rid of set but not used warning

  // Stop the SAADC, since it's not used anymore.
  NRF_SAADC->TASKS_STOP = 1;
  while (NRF_SAADC->EVENTS_STOPPED == 0);
  NRF_SAADC->EVENTS_STOPPED = 0;


  while (1)
  {
    __WFE();
  }
}

Parents
  • Hi,

    Where does this example come from?

    1. NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos; /* does this mean that the sampling of the input voltage to the analog pin      will only happen when I set a certain bit?*/

    Here you configure that sampling is controlled by triggering the SAMPLE task. So sampling will only occur when the SAMPLE task is triggered via PPI or SW.

    2. NRF_SAADC->TASKS_SAMPLE = 1;                            // does this instruction make the sampler sample the input voltage?
        while (NRF_SAADC->EVENTS_END == 0);                  // what is this for?
        NRF_SAADC->EVENTS_END = 0;                                // what is this for?     

    The first line writes 1 to the SAMPLE task, triggering it so that the SAADC to sample the input. The second line reads it back until it is actually set to 1. The third line writes it back to 0 so that it is ready to be triggered at a later stage.

    3. NRF_SAADC->TASKS_START = 1;                               //why do i need these lines of code since i already enabled the SAADC? do I need to call them every time I make a sample?
        while (NRF_SAADC->EVENTS_STARTED == 0);
        NRF_SAADC->EVENTS_STARTED = 0;                    

    This triggers the START task in the same way as the SAMPLE task. It is triggered before the SAMPLE task, though (which is correct), but the order you ask about it might cause some confusion. You can read more details about the different tasks etc. in the SAADC chapter in the PS.

    5.  __WFE();                                                                       //what does the waiting for event macro do in this example?

    This makes the CPU enter low power sleep mode, where it sleeps until there is a new interrupt/event. It is not directly related to the usage of the SAADC.

    6.  NRF_SAADC->RESULT.MAXCNT = 1;                        //what does this line do?
         NRF_SAADC->RESULT.PTR = (uint32_t)&result;       //why doesn't the result change its value, since I tried to print the value of it when I connect P0.02 to GND and then to VDD?

    Specifies the maximum number of samples that can be written in RAM via DMA. Since it is just one, that means that you need to read the result after every sampling.

    The result doe snot change depending on P0.02 because you have not configured the SAADC to measure on P0.02. You have configured it to measure VDD using this line:

    NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_VDD << SAADC_CH_PSELP_PSELP_Pos;

  • I found the example somewhere on the forum, I do not remember where.

Reply Children
No Data
Related