ItsyBitsy M4 Express with ATSAMD51 reading 3 voltages each at 44.1kHz

I am just trying to figure out how I can read and store the voltages off of three pins into arrays. I've seen ways to do this for two analog inputs, but not three. Does anyone have an idea for this? @MartinL seems to be the pro.

Thanks.

int readMic1 = A2;
int readMic2 = A3;
int readMic3 = A4;

int voltage1[200];
int voltage2[200];
int voltage3[200];

void setup() {
  Serial.begin(9600);
  pinMode(readMic1, INPUT);
  pinMode(readMic2, INPUT);
  pinMode(readMic3, INPUT);
}

void loop() {
  for (int i = 0; i < 100; i++) {
    voltage1[i] = analogRead(readMic1);
    voltage2[i] = analogRead(readMic2);
    voltage3[i] = analogRead(readMic3);
  }

  for (int i = 0; i < 100; i++) {
    Serial.print(voltage1[i]);
    Serial.print(",");
    Serial.print(voltage2[i]);
    Serial.print(",");
    Serial.println(voltage3[i]);
  }

}

This is an example of my code that I want to get more samples per time of.

I noticed in Forum - forum.arduino.cc/t/samd51-adc0-and-adc1-multiplexing-with-dma/1238002/3 that MartinL found a way to take 1024 samples (outside of the main loop) at 200KSPS. I am essentially looking for a way to do either 512 or 1024 samples at around 100KSPS and store them in arrays similar to this other forum, but for 3 pins. Is there a way to achieve this?

Post the result of timing the data acquisition portion of the code you have already posted.

  unsigned long now = micros();
 for (int i = 0; i < 100; i++) {
    voltage1[i] = analogRead(readMic1);
    voltage2[i] = analogRead(readMic2);
    voltage3[i] = analogRead(readMic3);
  }
Serial.println(micros() - now);

Hi @builderjd06

As @jremington mentions, the use of the micros() function will give you an idea of the sampling time for the three analog inputs over 100 measurements. You can also use micros() to control the sample rate in the loop().

It's possible to configure the ADCs using their registers for faster operation and/or the DMA to run without CPU intervention, but their use very much depends on your project's requirements.

Hi @builderjd06

I noticed in the title that you mention 44.1kHz, is this for audio sampling?

Hi @MartinL,

I am trying to capture the audio signal of three microphones for post processing. I need the sample rate high enough to determine phase differnce between the microphones. Ideally each single sample between each of the microphones will be very close to each other and the time to take all three separate samples will be small (less than 10 uS) and the overall sample rate at 44.1kHz or faster just known. Let me know if that makes sense or if I need to clear that up.

When I get home I will measure the sample rate for all three inputs but it is about 38kHz for input by itself so I'd imagine it would be at least a third of that for sampling all three.

EDIT: I meant to add that knowing the sample rate with precision would help with the post processing.

  unsigned long now = micros();
  for (int i = 0; i < 100; i++) {
    voltage1[i] = analogRead(readMic1);
    voltage2[i] = analogRead(readMic2);
    voltage3[i] = analogRead(readMic3);
  }
Serial.println(micros() - now);

This returns an average of about 7735 uS.

I also did a couple other tests that you may or may not find helpful:

    unsigned long before;
    unsigned long after = 0;
  for (int i = 0; i < 100; i++) {
    before = micros();
    //voltage1[i] = analogRead(readMic1);
    after = micros() - before + after;
  }
    Serial.println(after);

returns 44uS

    unsigned long before;
    unsigned long after = 0;
  for (int i = 0; i < 100; i++) {
    before = micros();
    voltage1[i] = analogRead(readMic1);
    after = micros() - before + after;
  }
    Serial.println(after);

returns 2620uS

    unsigned long before;
    unsigned long after = 0;
  for (int i = 0; i < 100; i++) {
    before = micros();
    voltage1[i] = analogRead(readMic1);
    voltage2[i] = analogRead(readMic2);
    after = micros() - before + after;
  }
    Serial.println(after);

returns 5195uS

    unsigned long before;
    unsigned long after = 0;
  for (int i = 0; i < 100; i++) {
    before = micros();
    voltage1[i] = analogRead(readMic1);
    voltage2[i] = analogRead(readMic2);
    voltage3[i] = analogRead(readMic3);
    after = micros() - before + after;
  }
    Serial.println(after);

returns 7779 uS

(300 samples)/(7735 us) = 38.8K samples/second. Not bad!

Yeah but split between the three signal sources is only about 13KSPS per signal. I am trying to get a set amount around 40KSPS per signal

Increase the ADC sample clock rate. A factor of four should not be a problem, but it will probably lower the accuracy.

After doing this I seem to get about 24KSPS (per microphone). This is still much less that what Id prefer. I am fairly certain there is a way to get this up on this board, I am just not sure how.

Doing what?

After including this line of code in the setup:

ADC0->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV4_Val;

And what do you suppose that line does?
More importantly, what option did that line override?

My point is, if you didn't get the effect you wanted, the change you made was not the correct change to make.

I apologize. I am new to the SAMD51. I'm used to Arduino nano plug and play but just recently moved on to this for this project. If you could help me out I would really appreciate it.

Hi @builderjd06

I understand that you require 3 microphone outputs to be sampled at 44.1kHz (or thereabouts) and the data to be stored to memory.

Regarding the data capture side of things, are you intending to capture a burst of data then post process it, or continuous capture data and process it on-the-fly so to speak?

I think capturing it as bursts would be easiest.

This thread is of interest: Analog speed in SAMD boards

The SAMD ADC is a very complex peripheral, and evidently, few in the Arduino world have taken much interest in understanding the details in the data sheet. I'm not very interested in digging in either, so have at it! I recommend to start by looking at the Arduino core settings for the analogRead() implementation.

According to the manufacturer's claims, it should be possible to do what you want, but to determine whether you can switch channels sequentially without cross-contamination will take require some careful experimentation.

Yeah I actually read this exact forum already. Even thought it was about the SAMD21 I found it pretty interesting. Not really sure it helped me understand how to get the SAMD51 to work as much as it told me that it should be more than capable to do what I want it to do.