SAMD51 multiplexer read issue

I am using the Martin L code (Setting up ISR for ADC on Zero - #5 by MartinL, Post 5). However, I have a problem. The sketch repeats a lot the output values. Below are two outputs: real values first (A4) and then the values generated by the sketch (A4). As can it be seen the values displayed by the sketch repeat too much.

Real Data:

3880,3952,260,66,64,3894,3944,1076,86,76,3894,3946,3912,242,80,3904,3952,3944,264,57,3885,3939,3939,257,61,65,3893,3945,259,57,73,3897,3953,2059,129,65,3888,3946,3938,259,57,3887,3945,3945,259,57,3891,3951,3949,265,59,73,3891,3944,788,74,72,3882,3938,3281,201,71,3893,3953,3945,261,59,3891,3945,3945,264,58,68,3891,3945,251,88,76,3896,3953,1691,109,77,3893,3945,3945,257,58,3882,3930,3936,250,90,3892,3948,3952,258,66,72,3891,3945,523,69,67,3896,3944,2762,175,71,3893,3949,3949,259,65,3891,3945,3944,256,58,3209,3929,3936,248,88,68,3896,3946,1331,97,77,3897,3947,3947,258,58,3884,3944,3944,265,56,3888,3937,3945,259,56,64,3896,3953,329,73,74,3888,3944,2309,131,58,3881,3945,3945,258,64,3892,3952,3946,264,56,3896,3944,3944,258,52,72,3893,3947,955,90,78,3890,3954,3755,217,73,3889,3945,3945,257,59,3881,3937,3936,260,56,66,3892,3954,245,86,74,3892,3947,1845,119,83,3891,3945,3945,256,58,3890,3947,3947,259,64,3893,3939,3938,248,82,68,3889,3937,649,69,72,3892,3948,3032,192,74,3888,3945,3945,261,64,3884,3945,3944,258,52,297,3890,3946,266,59,73,3905,3947,1474,104,76,3884,3944,3937,259,61,3888,3944,3947,259,56,3896,3946,3944,251,88,70,3892,3945,427,68,74,3892,3944,3938,251,86,3897,3952,3946,265,56,3891,3945,3944,256,58,71,3888,3944,715,89,74,3891,3948,3120,183,65,3889,3938,3945,257,58,3888,3946,3945,261,65,66,3889,3953,274,65,73,3892,3946,1546,95,79,3885,3936,3944,264,56,3892,3944,3947,259,65,3889,3945,3945,264,56,64,3888,3944,472,88,76,3891,3947,2665,180,66,3892,3945,3945,259,56,3882,3928,3937,249,89,3889,3945,3946,260,60,3944,3952,3944...,264,56,66,3892,3944,1152,78,76,3890,3947,3945,256,56,3896,3949,3949,265,65,3885,3945,3937,249,89,71,3895,3945,274,64,73,3904,3946,2168,158,66,3883,3945,3945,265,59,3891,3945,3945,257,56,3904,3953,3947,261,56,75,3889,3944,896,74,73,67,73,73,3897,3949,3954,270,65,66,3896,3944,1545,93,75,3890,3944,3944,256,58,3885,3945,3945,256,64,3905,3949,3947,260,56,64,3888,3936,452,76,77,3889,3948

The values do not repeat

Data displayed by the sketch:

118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3940,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3939,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,3943,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948,3948

Values repeat a lot.

The code (based in the Martin L code):

/*
  Notes:
  Source: https://forum.arduino.cc/t/setting-up-isr-for-adc-on-zero/655967/5
*/

#include <SPI.h>
#include <Wire.h>
#include <math.h>

//#define DEBUG

#define SAMPLES_TO_READ 20000L

char getGoing = 'N';
unsigned long timeStartReading,timeEndReading;
int sampleValue[2*SAMPLES_TO_READ];

uint16_t adcResult[2];                                                          // A4 and A5 result array
uint32_t inputCtrl[] = { ADC_INPUTCTRL_MUXPOS_AIN4,                             // ADC0 INPUTCTRL register MUXPOS settings AIN0 = A0, AIN5 = A1
                         ADC_INPUTCTRL_MUXPOS_AIN6 };   

typedef struct           // DMAC descriptor structure
{
  uint16_t btctrl;
  uint16_t btcnt;
  uint32_t srcaddr;
  uint32_t dstaddr;
  uint32_t descaddr;
} dmacdescriptor ;

volatile dmacdescriptor wrb[DMAC_CH_NUM] __attribute__ ((aligned (16)));        // Write-back DMAC descriptors
dmacdescriptor descriptor_section[DMAC_CH_NUM] __attribute__ ((aligned (16)));  // DMAC channel descriptors
dmacdescriptor descriptor __attribute__ ((aligned (16)));                       // Place holder descriptor

void ADC_Init()
{
  DMAC->BASEADDR.reg = (uint32_t)descriptor_section;                            // Specify the location of the descriptors
  DMAC->WRBADDR.reg = (uint32_t)wrb;                                            // Specify the location of the write back descriptors
  DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf);                  // Enable the DMAC peripheral

  DMAC->Channel[0].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(ADC0_DMAC_ID_SEQ) |       // Set DMAC to trigger on ADC0 DMAC sequence
                                 DMAC_CHCTRLA_TRIGACT_BURST;                    // DMAC burst transfer
  descriptor.descaddr = (uint32_t)&descriptor_section[0];                       // Set up a circular descriptor
  descriptor.srcaddr = (uint32_t)inputCtrl + sizeof(uint32_t) * 2;              // Configure the DMAC to set the
  descriptor.dstaddr = (uint32_t)&ADC0->DSEQDATA.reg;                           // Write the INPUT CTRL 
  descriptor.btcnt = 2;                                                         // Beat count is 2
  descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_WORD |                               // Beat size is WORD (32-bits)
                      DMAC_BTCTRL_SRCINC |                                      // Increment the source address
                      DMAC_BTCTRL_VALID;                                        // Descriptor is valid
  memcpy(&descriptor_section[0], &descriptor, sizeof(descriptor));              // Copy the descriptor to the descriptor section
   
  DMAC->Channel[1].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(ADC0_DMAC_ID_RESRDY) |    // Set DMAC to trigger when ADC0 result is ready
                                 DMAC_CHCTRLA_TRIGACT_BURST;                    // DMAC burst transfer
  descriptor.descaddr = (uint32_t)&descriptor_section[1];                       // Set up a circular descriptor
  descriptor.srcaddr = (uint32_t)&ADC0->RESULT.reg;                             // Take the result from the ADC0 RESULT register
  descriptor.dstaddr = (uint32_t)adcResult + sizeof(uint16_t) * 2;              // Place it in the adcResult array
  descriptor.btcnt = 2;                                                         // Beat count is 1
  descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD |                              // Beat size is HWORD (16-bits)
                      DMAC_BTCTRL_DSTINC |                                      // Increment the destination address
                      DMAC_BTCTRL_VALID;                                        // Descriptor is valid
  memcpy(&descriptor_section[1], &descriptor, sizeof(descriptor));              // Copy the descriptor to the descriptor section

  ADC0->INPUTCTRL.bit.MUXPOS = 0x0;                                             // Set the analog input to A0
  while(ADC0->SYNCBUSY.bit.INPUTCTRL);                                          // Wait for synchronization
  ADC0->SAMPCTRL.bit.SAMPLEN = 0x00;                                            // Set max Sampling Time Length to half divided ADC clock pulse (2.66us)
  while(ADC0->SYNCBUSY.bit.SAMPCTRL);                                           // Wait for synchronization  
  ADC0->DSEQCTRL.reg = ADC_DSEQCTRL_AUTOSTART |                                 // Auto start a DMAC conversion upon ADC0 DMAC sequence completion
                       ADC_DSEQCTRL_INPUTCTRL;                                  // Change the ADC0 INPUTCTRL register on DMAC sequence
  ADC0->CTRLA.reg = ADC_CTRLA_PRESCALER_DIV256;                                 // Divide Clock ADC GCLK by 256 (48MHz/256 = 187.5kHz)
  ADC0->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT;                                     // Set ADC resolution to 12 bits 
  while(ADC0->SYNCBUSY.bit.CTRLB);                                              // Wait for synchronization
  ADC0->CTRLA.bit.ENABLE = 1;                                                   // Enable the ADC
  while(ADC0->SYNCBUSY.bit.ENABLE);                                             // Wait for synchronization
  ADC0->SWTRIG.bit.START = 1;                                                   // Initiate a software trigger to start an ADC conversion
  while(ADC0->SYNCBUSY.bit.SWTRIG);                                             // Wait for synchronization
  DMAC->Channel[0].CHCTRLA.bit.ENABLE = 1;                                      // Enable DMAC Sequencing on channel 0
  DMAC->Channel[1].CHCTRLA.bit.ENABLE = 1;                                      // Enable DMAC ADC on channel1
  delay(1);                                                                     // Wait a millisecond
}

void setup()
{
  Serial.begin(115200);
  while(!Serial);

  ADC_Init();

  Serial.println("Begin ...");
}

void loop()
{
  if (Serial.available() > 0 )
  {
    getGoing = Serial.read();
    if (getGoing=='x')
    {
      readNOAnalogRead();
      #if defined DEBUG
        print100Samples();
      #endif
      Serial.write('K');
    }
    
    else if(getGoing=='z')
    {
      for(long i=0;i<SAMPLES_TO_READ;i++)
      {
        Serial.print(sampleValue[i]);
        if(i<SAMPLES_TO_READ-1)
          Serial.print(",");
      }
    }
    while(Serial.available()> 0)
      Serial.read();
  }
}

void readNOAnalogRead()
{
  timeStartReading = micros();
  for(long i=0;i<SAMPLES_TO_READ;i++)
  {
    sampleValue[i] = adcResult[0];                                              // Save the A4 result
    sampleValue[SAMPLES_TO_READ+i] = adcResult[1];                              // Save the A5 result
    delayMicroseconds(1);
  }
  timeEndReading = micros();
  Serial.print("Samples per second (channel): ");   Serial.println(1000000./(float((timeEndReading-timeStartReading))/SAMPLES_TO_READ),0);
}


#if defined DEBUG
char iStr[6];
void print100Samples()
{
  Serial.println("\n  i       A4       A5");
  for(long i=0;i<1000;i++)
  {
    sprintf(iStr,"%4d",i+1);
    Serial.print(iStr);   Serial.print("     ");   Serial.print(sampleValue[i]);   Serial.print("     ");   Serial.println(sampleValue[SAMPLES_TO_READ+i]);
  }
  Serial.println("");
}
#endif

Hi @LMario28

To get a general idea of what you're trying to achieve with your project, I've just got a few questions:

Please could you tell me what SAMD51 board you're using?

Please could you explain what input waveform the real data represents and at what frequency?

Also, are you intending to use both analog channels or just one? (The title of your post suggests two).

What sort of ADC sampling rate do you require?

Thanks.

Hi MartinL,

  1. I am using the Adafruit Itsy-Bitsy M4 board.

  2. I am using for development a square wave. Its frequency is about 1,300 cycles per second. It is achieved using around 170,000 samples in a second.

  3. Two channels.

  4. At least 200,000 samples/sec.

Thanks for your help.

By the way, one final question.

I noticed that you capture around 20000 results to an array. Are you intending on capturing a snapshot of analog input information for post-processing?

If that's the case the DMAC descriptors can be changed to do that without any CPU intervention. This automates the process, makes it independent of the loop() function and ensures that samples are taken at the correct sample rate.

Also, if you're reading two analog inputs, it might be more efficient to use both the SAMD51's ADCs (ADC0 and ADC1), rather than employing a single ADC and multiplexing between channels.

  1. Yes, we need a snapshot of the input information.

  2. Yes, the data is going to be post-processed.

  3. I am going to try using the two SAMD51's ADCs

I have added the second ADC to the sketch. The result I get are:

4040,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095
1198,1198,1155,1034,961,1025,929,935,945,964,1026,923,921,918,909,896,864,1013,1145,1208,1121,1146,1213,1136,1189,1079,1040,954,993,1092,1079,1035,940,965,1027,922,921,917,908,896,866,1012,1143,1199,1098,1091,1069,1024,923,921,919,911,899,867,1015,1145,1208,1120,1147,1210,1124,1163,1025,929,935,945,965,1026,921,919,911,897,867,1012,1144,1209,1121,1147,1217,1140,1204,1115,1131,1173,1046,969,1039,952,989,1091,1066,1004,1131,1168,1034,943,968,1036,949,978,1052,982,1067,1005,1131,1169,1033,943,968,1035,939,955,987,1077,1033,939,953,987,1074,1024,922,920,917,911,897,866,1013,1145,1208,1121,1147,1217,1141,1203,1103,1108,1120,1146,1217,1140,1204,1114,1132,1185,1069,1025,925,937,950,979,1051,971,1036,950,978,1054,983,1067,1002,1117,1140,1202,1102,1107,1109,1120,1145,1211,1122,1152,1002,1120,1145,1210,1122,1153,1001,1120,1147,1210,1122,1152,1001,1121,1145,1211,1122,1152,1001,1120,1145,1211,1123,1152,1003,1121,1144,1213,1136,1188,1078,1038,955,992,1092,1079,1037,952,989,1090,1064,1005,1133,1185,1067,1008,1135,1184,1067,1008,1137,1187,1069,1024,925,933,944,965,1027,922,920,919,908,897,864,1012,1144,1208,1121,1146,1216,1141,1205,1115,1131,1173,1049,974,1057,985,1076,1034,941,966,1027,922,921,917,909,896,864,1013,1145,1209,1120,1153,999,1111,1120,1145,1213,1136,1188,1080,1049,972,1052,984,1077,1034,940,968,1035,939,952,986,1075,1025,921,918,912,898,867,1015,1144,1208,1121,1153,1000,1120,1144,1211,1122,1153,1000,1120,1144,1210,1122,1152,1000,1121,1144,1213,1136,1189,1080,1046,968,1039,952,988,1091,1064,1005,1133,1185,1065,1006,1135,1186,1066,1010,1136,1187,1066,1008,1137,1187,1067,1009,1136,1185,1066,1009,1134,1187,1066,1009,1138,1187,1066,1007,1135,1185,1066,1008,1135,1184,1067,1008,1134,1184,1066,1008,1136,1186,1066,1006,1134,1185,1066,1008,1136,1187,1067,1008,1136,1185,1066,1009,1137,1187,1067,1009,1135,1185,1066,1009,1137,1186,1066,1008,1137,1186,1067,1009,1136,1187,1068,1025,923,923,921,916,911,899,867,1014,1144,1208,1121,1146,1217,1143,1205,1116,1144,1217,1140,1205,1114,1133,1187,1066,1010,1136,1186,1066,1009,1136,1187,1066,1010,1136,1185,1067,1008,1136,1186,1067,1009,1136,1186,1067,1007,1134,1185,1066,1008,1137,1186,1064,1008,1137,1186,1066,1008,1136,1187,1066,1009,1134,1185,1067,1008,1137,1187,1067,1007,1134,1184,1067,1009,1136,1187,1066,1009,1136,1184,1066,1011,1137,1187,1067,1008,1137,1184,1066,1011,1136,1187,1067,1008,1136,1186,1067,1008,1138,1186,1066,1009,1134,1185,1066,1009,1137,1187,1066,1009,1137,1186,1066,1006,1137,1187,1066,1011,1136,1187,1066,1008,1136,1187,1066,1008,1137,1185,1067,1008,1134,1186,1066,1009,1137,1186,1066,1006,1135,1184,1066,1009,1137,1187,1066,1008,1134,1184,1066,1009,1136,1186,1067,1008,1134,1184,1067,1009,1137,1184,1066,1008,1136,1184,1067,1011,1136,1187,1067,1009,1135,1185,1066,1008,1134,1184,1066,1008,1136,1187,1067,1010,1136,1187,1067,1009,1136,1187,1067,1008,1136,1186,1067,1009,1137,1185,1066,1006,1135,1184,1067,1010,1136,1184,1067,1009,1137,1186,1066,1008,1134,1184,1067,1006,1134,1185,1067,1010,1136,1185,1066,1008,1136,1186,1066,1008,1136,1185,1067,1008,1135,1185,1067,1008,1137,1186,1067,1009,1137,1186,1067,1009,1137,1187,1066,1008,1137,1185,1067,1010,1136,1187,1066,1008,1135,1184,1066,1009,1137,1186,1067,1008,1134,1185,1066,1008,1136,1186,1067,1009,1137,1185,1067,1009,1137,1186,1067,1009,1136,1187,1067,1009,1139,1186,1067,1010,1136,1186,1067,1009,1137,1187,1066,1009,1137,1187,1067,1007,1134,1185,1066,1009,1136,1187,1066,1008,1136,1186,1067,1008,1135,1185,1066,1009,1135,1184,1067,1006,1136,1186,1066,1008,1135,1184,1067,1008,1137,1186,1067,1009,1137,1185,1067,1011,1136,1187,1066,1009,1135,1184,1067,1008,1136,1186,1066,1008,1137,1186,1067,1011,1137,1186,1069,1024,922,923,919,913,896,867,1014,1147,1209,1120,1147,1210,1125,1162,1024,929,932,945,965,1026,922,920,917,908,896,867,1015,1145,1206,1114,1130,1171,1037,955,992,1091,1067,1004,1132,1184,1065,1009,1135,1184,1064,1008,1136,1186,1066,1010,1134,1184,1067,1009,1137,1186,1066,1008,1134,1184,1066,1006,1134,1185,1067,1011,1137,1187,1067,1008,1136,1186,1066,1008,1136,1185,1067,1009,1135,1185,1066,1008,1136,1187,1067,1007,1134,1184,1066,1009,1137,1185,1066,1008,1136,1185,1067,1008,1136,1186,1066,1008,1134,1184,1066,1008,1136,1186,1066,1008,1136,1184,1066,1010,1137,1186,1066,1009,1135,1185,1065,1009,1137,1187,1067,1009,1137,1187,1067,1009,1137,1186,1069,1025,923,922,920,917,911,899,867,1015,1145,1209,1121,1145,1217,1143,1204,1115,1133,1184,1066,1008,1137,1186,1066,1009,1137,1187,1067,1009,1137,1187,1067,1008,1139,1187,1067,1008,1136,1186,1067,1009,1137,1186,1066,1009,1137,1185,1067,1009,1136,1187,1067,1008,1134,1184,1066,1008,1136,1186,1066,1008,1137,1184,1066,1011,1137,1186,1069,1025,923,922,920,917,911,897,867,1015,1145,1208,1121,1147,1217,1142,1205,1115,1133,1184,1066,1008,1139,1186,1066,1009,1137,1187,1066,1007,1135,1184,1066,1011,1137,1184,1066,1008,1136,1186,1067,1009,1135,1184,1066,1008

The first line is OK (3.3V) but the second not (0V). (I am using A4 and A5)

No doubt, I have configured incorrectly the ADC1. Here is the code.

#include <SPI.h>
#include <Wire.h>
#include <math.h>

#define SAMPLES_TO_READ 1000L

char getGoing = 'N';
unsigned long timeStartReading,timeEndReading;
int sampleValue[2*SAMPLES_TO_READ];

void ADC0_Init(void)
{
  //////////////////////////////////////////////////////////////////////////
   ///ADC Clock Config
   //////////////////////////////////////////////////////////////////////////

   MCLK->APBDMASK.bit.ADC0_ = 1;
   //Use GCLK1, channel it for ADC0, select DFLL(48MHz) as source and make sure no divider is selected
   GCLK->PCHCTRL[ADC0_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); // enable gen clock 1 as source for ADC channel
   GCLK->GENCTRL[0].reg = GCLK_GENCTRL_SRC_DFLL | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(1);
   GCLK->GENCTRL[0].bit.DIVSEL = 0;
   GCLK->GENCTRL[0].bit.DIV = 0;

  //Divide 8MHz clock by 4 to obtain 2MHz clock to adc
  ADC0->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV4_Val;

  //Choose 12-bit resolution
  ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
  //Ensuring freerun is activated
  ADC0->CTRLB.bit.FREERUN = 1;

  //waiting for synchronisation
  while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB);

  //Sampletime set to 0
  ADC0->SAMPCTRL.reg = 0;

  //Waiting for synchronisation
  while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_SAMPCTRL);

  ADC0->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_AIN4_Val;
  //ADC0->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND;   // No Negative input (Internal Ground)

  while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL );  //wait for sync

  // Averaging (see datasheet table in AVGCTRL register description)
  ADC0->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 |    // 1 sample only (no oversampling nor averaging)
              ADC_AVGCTRL_ADJRES(0x0ul);   // Adjusting result by 0

  //Wait for synchronisation
  while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_AVGCTRL)

  //Select VDDANA (3.3V chip supply voltage as reference)
  ADC0->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1;

  //Enable ADC
  ADC0->SWTRIG.bit.START = 1;
  ADC0->CTRLA.bit.ENABLE = 1;

  //wait for ADC to be ready
  while(ADC0->SYNCBUSY.bit.ENABLE);
}

void ADC1_Init(void)
{
  //////////////////////////////////////////////////////////////////////////
   ///ADC Clock Config
   //////////////////////////////////////////////////////////////////////////

   MCLK->APBDMASK.bit.ADC1_ = 1;
   //Use GCLK1, channel it for ADC1, select DFLL(48MHz) as source and make sure no divider is selected
   GCLK->PCHCTRL[ADC1_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); // enable gen clock 1 as source for ADC channel
   GCLK->GENCTRL[0].reg = GCLK_GENCTRL_SRC_DFLL | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(1);
   GCLK->GENCTRL[0].bit.DIVSEL = 0;
   GCLK->GENCTRL[0].bit.DIV = 0;

  //Divide 8MHz clock by 4 to obtain 2MHz clock to adc
  ADC1->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV4_Val;

  //Choose 12-bit resolution
  ADC1->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
  //Ensuring freerun is activated
  ADC1->CTRLB.bit.FREERUN = 1;

  //waiting for synchronisation
  while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB);

  //Sampletime set to 0
  ADC1->SAMPCTRL.reg = 0;

  //Waiting for synchronisation
  while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_SAMPCTRL);

  ADC1->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_AIN6_Val;
  //ADC0->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND;   // No Negative input (Internal Ground)

  while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL );  //wait for sync

  // Averaging (see datasheet table in AVGCTRL register description)
  ADC1->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 |    // 1 sample only (no oversampling nor averaging)
              ADC_AVGCTRL_ADJRES(0x0ul);   // Adjusting result by 0

  //Wait for synchronisation
  while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_AVGCTRL)

  //Select VDDANA (3.3V chip supply voltage as reference)
  ADC1->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1;

  //Enable ADC1
  ADC1->SWTRIG.bit.START = 1;
  ADC1->CTRLA.bit.ENABLE = 1;

  //wait for ADC1 to be ready
  while(ADC1->SYNCBUSY.bit.ENABLE);
}

void setup()
{
  ADC0_Init();
  ADC1_Init();

  Serial.begin(115200);
  while(!Serial);

  Serial.println("Begin ...");
}

void loop()
{
  if (Serial.available() > 0 )
  {
    getGoing = Serial.read();
    if (getGoing=='x') {
     
      readNOAnalogRead();
      Serial.write('K');
    }
    
    if(getGoing=='z')
    {
      //Serial.println("BUFFER CONTENTS:");
      for(int i=0;i<SAMPLES_TO_READ;i++)
      {
        Serial.print(sampleValue[i]);
        if(i<SAMPLES_TO_READ-1)
          Serial.print(",");
      }
      Serial.println();
      for(int i=SAMPLES_TO_READ;i<2*SAMPLES_TO_READ;i++)
      {
        Serial.print(sampleValue[i]);
        if(i<2*SAMPLES_TO_READ-1)
          Serial.print(",");
      }
    }
    while(Serial.available()> 0)
      Serial.read();
  }
}

void readNOAnalogRead()
{
  timeStartReading = micros();
  for(int i=0;i<SAMPLES_TO_READ;i++)
  {
    // Reading ADC0
    ADC0->SWTRIG.bit.START = 1;
    while(!ADC0->INTFLAG.bit.RESRDY);
    sampleValue[i] = ADC0->RESULT.reg;
    // Reading ADC1
    ADC1->SWTRIG.bit.START = 1;
    while(!ADC1->INTFLAG.bit.RESRDY);
    sampleValue[SAMPLES_TO_READ+i] = ADC1->RESULT.reg;
  }
  timeEndReading = micros();
  Serial.print("\nTime per read (analogRead): ");   Serial.print((float((timeEndReading-timeStartReading))/SAMPLES_TO_READ),2);   Serial.print(" us (");
         Serial.print(SAMPLES_TO_READ);   Serial.println(" samples)");
}

Hi @LMario28

Here's some example code that samples the Itsy Bitsy (or Feather) M4's A2 an A3 analog inputs at 200kHz. It uses the DMAC (Direct Memory Access Controller) to read both inputs and store the results at this sample rate to two 1024 element arrays, once every second. The results can be displayed on the Arduino IDE's serial plotter. As this uses the SAMD51's DMAC, the capture process and transfer to memory itself takes place without any CPU intervention.

Here's the code:

// Use SAMD51's DMAC to read the ADC0 and ADC1 on A4 and A5 (Metro M4 or A2 and A3 on Feather/Itsy Bitsy M4) respectively

volatile boolean results0Ready = false;                      // Results ready flags
volatile boolean results1Ready = false;
uint16_t adcResults0[1024];                                  // ADC results array 0
uint16_t adcResults1[1024];                                  // ADC results array 1

typedef struct           // DMAC descriptor structure
{
  uint16_t btctrl;
  uint16_t btcnt;
  uint32_t srcaddr;
  uint32_t dstaddr;
  uint32_t descaddr;
} dmacdescriptor ;

volatile dmacdescriptor wrb[DMAC_CH_NUM] __attribute__ ((aligned (16)));          // Write-back DMAC descriptors
dmacdescriptor descriptor_section[DMAC_CH_NUM] __attribute__ ((aligned (16)));    // DMAC channel descriptors
dmacdescriptor descriptor __attribute__ ((aligned (16)));                         // Place holder descriptor

void setup() {
  Serial.begin(115200);                                                       // Start the native USB port
  while(!Serial);                                                             // Wait for the console to open
  
  DMAC->BASEADDR.reg = (uint32_t)descriptor_section;                          // Specify the location of the descriptors
  DMAC->WRBADDR.reg = (uint32_t)wrb;                                          // Specify the location of the write back descriptors
  DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf);                // Enable the DMAC peripheral
   
  DMAC->Channel[0].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(ADC0_DMAC_ID_RESRDY) |  // Set DMAC to trigger when ADC0 result is ready
                                 DMAC_CHCTRLA_TRIGACT_BURST;                  // DMAC burst transfer
  descriptor.descaddr = (uint32_t)0;                                           // Run descriptor only once
  descriptor.srcaddr = (uint32_t)&ADC0->RESULT.reg;                           // Take the result from the ADC0 RESULT register
  descriptor.dstaddr = (uint32_t)adcResults0 + sizeof(uint16_t) * 1024;       // Place it in the adcResults0 array
  descriptor.btcnt = 1024;                                                     // Beat count
  descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD |                            // Beat size is HWORD (16-bits)
                      DMAC_BTCTRL_DSTINC |                                    // Increment the destination address
                      DMAC_BTCTRL_VALID;                                      // Descriptor is valid                    
  memcpy(&descriptor_section[0], &descriptor, sizeof(descriptor));            // Copy the descriptor to the descriptor section

  NVIC_SetPriority(DMAC_0_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for DMAC Channel 0
  NVIC_EnableIRQ(DMAC_0_IRQn);         // Connect DMAC Channel 0 to Nested Vector Interrupt Controller (NVIC)
  
  DMAC->Channel[0].CHINTENSET.reg = DMAC_CHINTENSET_TCMPL;                    // Activate the transfer complete (TCMPL) interrupt on DMAC channel 0
  DMAC->Channel[1].CHPRILVL.reg = DMAC_CHPRILVL_PRILVL_LVL0;
  
  DMAC->Channel[1].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(ADC1_DMAC_ID_RESRDY) |  // Set DMAC to trigger when ADC1 result is ready
                                 DMAC_CHCTRLA_TRIGACT_BURST;                  // DMAC burst transfer
  descriptor.descaddr = (uint32_t)0;                                          // Set up a circular descriptor
  descriptor.srcaddr = (uint32_t)&ADC1->RESULT.reg;                           // Take the result from the ADC1 RESULT register
  descriptor.dstaddr = (uint32_t)adcResults1 + sizeof(uint16_t) * 1024;       // Place it in the adcResults1 array
  descriptor.btcnt = 1024;                                                    // Beat count
  descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD |                            // Beat size is HWORD (16-bits)
                      DMAC_BTCTRL_DSTINC |                                    // Increment the destination address
                      DMAC_BTCTRL_VALID;                                      // Descriptor is valid                  
  memcpy(&descriptor_section[1], &descriptor, sizeof(descriptor));            // Copy the descriptor to the descriptor section
  
  NVIC_SetPriority(DMAC_1_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for DMAC Channel 1
  NVIC_EnableIRQ(DMAC_1_IRQn);         // Connect DMAC Channel 1 to Nested Vector Interrupt Controller (NVIC)
  
  DMAC->Channel[1].CHINTENSET.reg = DMAC_CHINTENSET_TCMPL;                    // Activate the transfer complete (TCMPL) interrupt on DMAC channel 1
  DMAC->Channel[1].CHPRILVL.reg = DMAC_CHPRILVL_PRILVL_LVL0;
  
  ADC1->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_AIN1_Val;   // Set the analog input to A3
  while(ADC1->SYNCBUSY.bit.INPUTCTRL);                // Wait for synchronization
  ADC1->SAMPCTRL.bit.SAMPLEN = 0x02;                  // Extend sampling time by SAMPCTRL ADC cycles (12 + 1 + 2)/3MHz = 5.0us sample time = 200kHz 
  while(ADC1->SYNCBUSY.bit.SAMPCTRL);                 // Wait for synchronization
  ADC1->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT |          // Set ADC resolution to 12 bits 
                    ADC_CTRLB_FREERUN;                // Set ADC to free run mode  
  while(ADC1->SYNCBUSY.bit.CTRLB);                    // Wait for synchronization
  ADC1->CTRLA.bit.SLAVEEN = 1;                        // Set ADC1 to slave, ADC0 to master, both share CTRLA register
  
  ADC0->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_AIN2_Val;     // Set the analog input to A2
  while(ADC0->SYNCBUSY.bit.INPUTCTRL);                // Wait for synchronization
  ADC0->SAMPCTRL.bit.SAMPLEN = 0x02;                  // Extend sampling time by SAMPCTRL ADC cycles (12 + 1 + 2)/3MHz = 5.0us sample time = 200kHz
  while(ADC0->SYNCBUSY.bit.SAMPCTRL);                 // Wait for synchronization  
  ADC0->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT |          // Set ADC resolution to 12 bits 
                    ADC_CTRLB_FREERUN;                // Set ADC to free run mode        
  while(ADC0->SYNCBUSY.bit.CTRLB);                    // Wait for synchronization
  ADC0->CTRLA.reg = ADC_CTRLA_PRESCALER_DIV16;        // Divide Clock ADC GCLK by 16 (48MHz/16 = 3MHz) (12 + 1 + 2)/3MHz = 5.0us sample time 
  ADC0->CTRLA.bit.ENABLE = 1;                         // Enable the ADC
  while(ADC0->SYNCBUSY.bit.ENABLE);                   // Wait for synchronization
  ADC0->SWTRIG.bit.START = 1;                         // Initiate a software trigger to start an ADC conversion
  while(ADC0->SYNCBUSY.bit.SWTRIG);                   // Wait for synchronization
  DMAC->Channel[0].CHCTRLA.bit.ENABLE = 1;            // Enable DMAC channel 0
  DMAC->Channel[1].CHCTRLA.bit.ENABLE = 1;            // Enable DMAC channel 1
}

void loop() 
{  
  while (!(results0Ready && results1Ready));          // Wait for both sets of results to be ready
  
  for (uint32_t i = 0; i < 1024; i++)
  {
    Serial.print(adcResults0[i]);                     // Output the results to the Serial plotter
    Serial.print(F(","));
    Serial.println(adcResults1[i]);
  }
  results0Ready = false;                              // Clear the results0 ready flag
  results1Ready = false;                              // Clear the results1 ready flag
    
  delay(1000);                                        // Wait for 1 second
  DMAC->Channel[0].CHCTRLA.bit.ENABLE = 1;            // Enable DMAC channel 0
  DMAC->Channel[1].CHCTRLA.bit.ENABLE = 1;            // Enable DMAC channel 1
}

void DMAC_0_Handler()                                 // Interrupt handler for DMAC channel 0
{
  if (DMAC->Channel[0].CHINTFLAG.bit.TCMPL)           // Check if DMAC channel 0 transfer is complete
  {  
    DMAC->Channel[0].CHINTFLAG.bit.TCMPL = 1;         // Clear the transfer complete (TCMPL) interrupt flag
    results0Ready = true;                             // Set the results 0 ready flag
  }
}

void DMAC_1_Handler()                                 // Interrupt handler for DMAC channel 1
{
  if (DMAC->Channel[1].CHINTFLAG.bit.TCMPL)           // Check if DMAC channel 1 has been suspended (SUSP) 
  {    
    DMAC->Channel[1].CHINTFLAG.bit.TCMPL = 1;         // Clear the transfer complete (TCMPL) interrupt flag
    results1Ready = true;                             // Set the results 1 ready flag  
  }
}

Testing using a 1kHz, 0V to 3.3V sine wave on inputs A2 and A3:

Sine

Here's the output from the arrays for A2 (blue) and A3 (red) inputs on the Ardunino IDE's serial plotter (Tool->Serial Plotter):

As you can see both A2 (blue) and A3 (red) analog inputs sucessfully capture the sine wave.

The sketch runs very well.

Thank you.

Is there a way to read 4 analog inputs using the 2 adc's? I am currently doing it using multiplexing but I am having trouble setting up the arrays for saving the data

Hi @raidersnake

Yes, it's possible with the ADCs' DMA sequencing feature that allows each ADC to mutliplex beteen two input channels. DMA sequencing provides a mechanism for the DMAC to configure the ADCs during operation without CPU intervention.

How this is implemented however, depends on your application, such as the SAMD51 board you're using, which ADC inputs, ADC sample rate, continuous or burst data capture and the size of storage arrays?

I am using a custom feather m4. It has the standard pinout but the spi flash has been upgraded and an sd card has been added to give more storage. I would like to sample A0 and A1 using ADC0 and sample A2 and A3 using ADC1. The event I am trying to record is random and has a very fast rise time (<100us) so I need to sample continuously unless I can find a way to set up a trigger voltage

Have you considered the SAMD51's Analog Comparators?

If you're goal is to trigger an event or interrupt when the input passes through a given threshold voltage, then the Analog Comparators might be a better fit.

It's possible to compare the input with an internally scaled voltage at various thresholds.

That's a great idea! Do you have any examples of setting up the Analog Comparator for triggering DMAC?

The Analog Comparators don't use the DMAC, since the only information they're producing is a trigger, that occurs when the input voltage passes a certain threshold.

One issue might be that you're using 4 analog inputs, while the SAMD51 only has two comparators, each with two analog inputs. However, since the ACs don't implement DMAC sequencing, it means that it would be necessary to manually (with CPU intervention) switch between them.

Here's some example code that sets up an AC on channel 0 to trigger when input voltage exceeds 103mV on A4 (AIN[0]). Also there's a comparator trigger output on D6 and an optional (commented out) trigger interrupt:

// Set-up Adafruit Feather M4 Analog Comparator 0 with rising edge trigger at 103mV, input on A4, output on D6 
void setup() {
 
  // Analog Comparator ///////////////////////////////////////////////////////////////////////
   
  MCLK->APBCMASK.reg |= MCLK_APBCMASK_AC;                       // Activate the analog comparator peripheral

  GCLK->PCHCTRL[AC_GCLK_ID].reg = GCLK_PCHCTRL_CHEN |           // Enable perhipheral channel
                                  GCLK_PCHCTRL_GEN_GCLK2;       // Connect generic clock 2 at 100MHz to Analog Comparator (AC)

  // Enable the port multiplexer for the Analog Comparator channel 0 input AIN[0] on analog pin A4 (PA04)
  PORT->Group[g_APinDescription[A4].ulPort].PINCFG[g_APinDescription[A4].ulPin].bit.PMUXEN = 1; 
 
  // Connect the AIN[0] input to A4 - port pins are paired odd PMUXO and even PMUXE
  // B specifies the AC channel 0 input: AIN[0]
  PORT->Group[g_APinDescription[A4].ulPort].PMUX[g_APinDescription[A4].ulPin >> 1].reg |= PORT_PMUX_PMUXE(MUX_PA04B_AC_AIN0);

  // Enable the port multiplexer for the Analog Comparator channel 0 output on digital pin D6 (PA18)
  PORT->Group[g_APinDescription[6].ulPort].PINCFG[g_APinDescription[6].ulPin].bit.PMUXEN = 1;

  // Connect the AC/CMP[0] output to D6 - port pins are paired odd PMUXO and even PMUXE
  // H specifies the AC channel 0 and 1 outputs: AC/CMP[0] & AC/CMP[1]
  PORT->Group[g_APinDescription[6].ulPort].PMUX[g_APinDescription[6].ulPin >> 1].reg |= PORT_PMUX_PMUXE(MUX_PA18M_AC_CMP0);
                                                                                      
  AC->CALIB.bit.BIAS0 = (*(RoReg  *)0x00800080UL) & 0x03;   // Calibrate the Analog Comparator: load Non Volatile Memory Calibration Area AC Bias
  
  AC->COMPCTRL[0].reg = AC_COMPCTRL_OUT_ASYNC |       // Enable comparator output in asynchronous mode
                        AC_COMPCTRL_HYSTEN |          // Enable input hysteresis
                        AC_COMPCTRL_SPEED_HIGH |      // Place the comparator into high speed mode
                        AC_COMPCTRL_MUXPOS_PIN0 |     // Set the positive input multiplexer to pin 0
                        AC_COMPCTRL_MUXNEG_VSCALE |   // Set the negative input multiplexer to the voltage scaler                        
                        AC_COMPCTRL_INTSEL_RISING;    // Trigger event on the rising edge
  while (AC->SYNCBUSY.bit.COMPCTRL0);                 // Wait for synchronization

  AC->SCALER[0].reg = AC_SCALER_VALUE(1);  // Set the negative input voltage scale to 103mV
                                           // Vscale = Vdd * (VALUE + 1) / 64 = 3.3V * (1 + 1) / 64 = 103mV 
  
  //NVIC_SetPriority(AC_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for the Analog Comparator
  //NVIC_EnableIRQ(AC_IRQn);         // Connect AC to Nested Vector Interrupt Controller (NVIC)
  
  //AC->INTENSET.reg = AC_INTENSET_COMP0;             // Enable interrupt on comparator 0

  AC->CTRLA.bit.ENABLE = 1;                // Enable the analog comparator peripheral
  while (AC->SYNCBUSY.bit.ENABLE);         // Wait for synchronization

  AC->COMPCTRL[0].bit.ENABLE = 1;          // Enable the analog comparator channel 0
  while (AC->SYNCBUSY.bit.COMPCTRL0);      // Wait for synchronization
}

void loop() {}

void AC_Handler() {                                  // Analog Comparator interrupt handler function
  if (AC->INTFLAG.bit.COMP0)                         // Test if the comparator 0 interrupt flag has been set 
  {
    AC->INTFLAG.bit.COMP0 = 1;                       // Clear the comparator 1 interrupt flag
    //
    // Add interrupt handler code here ...
    //
  }
}

Thank you so much for the example! In my case, I believe I would only need one AC because when the event happens I would like to record all 4 inputs until the AC pin goes below the threshold again. I will try my hand at using the AC interrupt to trigger the ADC's to start. Does the AC pin have to be separate from the pins used by the ADC?

I'm not sure, as I've never tried it. The ADC and AC share the same pin mutliplexer switch, so it might be possible?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.