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

SAADC consistnetly reads low, regardless of source

The SAADC on the nRF52832 consistently reads 20-30mV low, regardless of the source (AIN channel or VCC), Tacq, Resolution, or gain. All of the measurements are using the internal 0.6v reference. The readings are low even after calibrating the ADC. This happens across multiple devices.

I am bare-metal programming. Here's an example program:

int main(void)
{
  SEGGER_RTT_Init();

  NRF_SAADC->ENABLE = 1;

  NRF_SAADC->EVENTS_STOPPED = 0;
  NRF_SAADC->TASKS_STOP = 1;
  while (NRF_SAADC->EVENTS_STOPPED != 1) {}

  NRF_SAADC->EVENTS_CALIBRATEDONE = 0;
  NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;
  while (NRF_SAADC->EVENTS_CALIBRATEDONE != 1) {}

  NRF_SAADC->EVENTS_STOPPED = 0;
  NRF_SAADC->TASKS_STOP = 1;
  while (NRF_SAADC->EVENTS_STOPPED != 1) {}

  SEGGER_RTT_printf(0, "Calibrate done\n");

  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;

  float internalReference = 0.6f;
  float gain = 1.0f / 6.0f;
  uint32_t resolutionDigits = 14;
  NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_14bit << SAADC_RESOLUTION_VAL_Pos;
  NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Over256x << SAADC_OVERSAMPLE_OVERSAMPLE_Pos;
  NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos;

  uint16_t sample = 0;
  NRF_SAADC->RESULT.PTR = uint32_t(&sample); //sample is a uint16_t
  NRF_SAADC->RESULT.MAXCNT = 1;

  NRF_SAADC->CH[0].CONFIG =
    (SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos) |
    (SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos) |
    (SAADC_CH_CONFIG_GAIN_Gain1_6 << SAADC_CH_CONFIG_GAIN_Pos) |
    (SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) |
    (SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos) |
    (SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) |
    (SAADC_CH_CONFIG_BURST_Enabled << SAADC_CH_CONFIG_BURST_Pos);

  SEGGER_RTT_printf(0, "SAADC configuration complete\n");

  while (true)
  {
    NRF_SAADC->EVENTS_STARTED = 0;
    NRF_SAADC->TASKS_START = 1;
    while (NRF_SAADC->EVENTS_STARTED != 1) {}

    NRF_SAADC->EVENTS_RESULTDONE = 0;
    NRF_SAADC->TASKS_SAMPLE = 1;
    while (NRF_SAADC->EVENTS_RESULTDONE != 1) {}

    float vcc = sample * (internalReference / (1 << resolutionDigits) / gain);
    SEGGER_RTT_printf(0, "VCC: %d mV\n", (uint32_t)(vcc * 1000));

    NRF_SAADC->EVENTS_STOPPED = 0;
    NRF_SAADC->TASKS_STOP = 1;
    while (NRF_SAADC->EVENTS_STOPPED != 1) {}
  }
}

There doesn't appear to be any difference in the ADC results between uncalibrated and calibrated. Do I have the calibration sequence set correctly? I followed the workaround in this errata: infocenter.nordicsemi.com/.../anomaly_832_86.html

On the PCA10040 dev kit, this above code is showing VCC of 2.814V. My Tektronix DMM-4050 and Fluke 115 multimeters are showing VCC at 2.825V across C8 (decoupling cap close to the nRF52832).

Parents
  • @Jørgen Holmefjord By "consistently reads 20-30mV low", I mean that the ADC will read 20-30mV low regardless of channel, gain, reference, acquisition time, resolution, etc. before and after calibrating the ADC. I see the same behavior on the custom nRF52832-based board and on the dev kit. I'll reformat the code into a complete example (with "main") so it's easier to follow.

Reply
  • @Jørgen Holmefjord By "consistently reads 20-30mV low", I mean that the ADC will read 20-30mV low regardless of channel, gain, reference, acquisition time, resolution, etc. before and after calibrating the ADC. I see the same behavior on the custom nRF52832-based board and on the dev kit. I'll reformat the code into a complete example (with "main") so it's easier to follow.

Children
No Data
Related