Noisy ADC data from Xiao SAMD21

Hi @jaishankarm

If you don't require a super high sample rate, you could try accumulating the result over a number of samples then averaging, to reduce noise.

The code example below sets-up the ADC just like analogRead() on A0, however it's also configured to accumulate over 256 samples. This generates a 20-bit value which the ADC auto shifts to the right by 4 (divide by 16), giving a 16-bit result. Setting the AVGCTRL.ADJRES to 0x4, shifts the 16-bit value to the right by a further 4 bits, giving an averaged 12-bit result:

// Set-up the ADC to read analog input on A0 averaged over 256 samples

// The signal is accululated over 256 samples, auto shifted right by 4 generating a 16-bit value
// This value is then divided by 4 to create an averaged 12-bit result

void setup() {
  SerialUSB.begin(115200);                         // Set-up the native serial port at 115200 bit/s
  while(!SerialUSB);                               // Wait for the console to open
  // Selecting the port multiplexer the the ADC doesn't seem necessary on the SAMD21
  //PORT->Group[PORTA].PINCFG[2].bit.PMUXEN = 1;              // Enable the A0 pin multiplexer
  //PORT->Group[PORTA].PMUX[2 >> 1].reg |= PORT_PMUX_PMUXE_B; // Switch the multiplexer to the ADC input
  ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV512 |    // Divide Clock ADC GCLK by 512 (48MHz/512 = 93.7kHz)
                   ADC_CTRLB_RESSEL_16BIT;         // Set ADC resolution to either 16-bit accumulation/averaging mode
  while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for synchronization
  ADC->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(0x4) |     // Divide the accumulated 16-bit value by 4 generating an averaged 12-bit result
                     ADC_AVGCTRL_SAMPLENUM_256;    // Accumulates 256 samples generating 16-bit value
  ADC->SAMPCTRL.reg = 0x3f;                        // Set max Sampling Time Length to half divided ADC clock pulse times SAMPCTRL (341.33us)
  ADC->INPUTCTRL.bit.MUXPOS = 0x0;                 // Set the analog input to A0
  while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for synchronization
  ADC->CTRLA.bit.ENABLE = 1;                       // Enable the ADC
  while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for synchronization
}

void loop() {
  ADC->SWTRIG.bit.START = 1;                       // Initiate a software trigger to start an ADC conversion
  while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for write synchronization
  while(!ADC->INTFLAG.bit.RESRDY);                 // Wait for the conversion to complete
  ADC->INTFLAG.bit.RESRDY = 1;                     // Clear the result ready (RESRDY) interrupt flag
  while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for read synchronization
  int result = ADC->RESULT.reg;                    // Read the ADC result
  SerialUSB.println(result);                       // Output the result
  delay(500);                                      // Wait for 500ms
}

The SAMD21's datasheet gives more information on how to adjust these register values.