Go Down

Topic: [Solved] Wierd data range from ADC on Arduino Due (Read 520 times) previous topic - next topic

ViktorWingqvist

Nov 23, 2017, 12:26 am Last Edit: Dec 01, 2017, 04:37 pm by ViktorWingqvist
I've been trying to read samples from a microphone with my Arduino Due. Somehow the samples are wrong in amplitude and I can't figure out how they end up that way.

Setup is as follows:

Microphone -> filter to make sure the signal is in the range 0-3.3 V -> Arduino Due ADC.

I play a sine with frequency of 1000 Hz to the microphone and measure the output on my oscilloscope. The picture below shows the signal before (yellow) and after (green) my filter. The filter is not the best but that is not important here.



The sampled signal on my Arduino Due is sampled with 48 kHz. In the end my Arduino will take input from 8 different microphones. For now I just feed the same signal (the green one from the picture) to all 8 ADC channels.

This picture below this paragraph shows 1024 samples on channel0 and channel7 (red and blue) that I've sent from the Arduino Due to MATLAB using a USB serial connection. (The figure also shows the difference between the signals in green.) As seen the signals are not completely identical but that's not important to the main problem, although not ideal for the end goal.




There is obviously something wrong here. According to my calculations the green signal on the oscilloscope has a peak-to-peak 0.470-0.313 V (readings from the Measurements tab down right on the oscilloscope) which is 0.157 V.

In my sketch I set the analog read resolution to 8 bits using

Code: [Select]
analogReadResolution(8);


1 bit then corresponds to 3.3/256 = 0,0129 V/bit. Since signal peak-to-peak is 0.157 V it would correspond to a very small signal, read by the ADCs, fluctuating with 0.157/0,0129 = 12 bits in the lower region of the plot. This is not the case as seen in the picture above, the signal amplitude covers almost the whole 256 value range and is overflowing resulting in going from 255->0 over all periods. Is there something I missed?

To be clear, the period of the recorded signal is very satisfying. I've counted the number of samples in the period of the signal in the plot. They are (on average taken over all the displayed periods) almost exactly 48. Since sampling frequency is 48 000 we get the frequency of the recorded signal to 1/(48/48 000) = 1000 Hz.

I've done this test with a lot of different frequencies and its the same type of result.

I attached the images together with the source code. It's 2 sketches, one for the Arduino Due that is sampling the signal, one for the Arduino Due that send's the 48 kHz interrupt-sampling-signal, and the MATLAB code, RecordSamples.m file and a SerialSetup.m script (uploaded as .pdfs here).

The way the sampling works is that one Arduino sends an interrupt signal at 48 kHz to the sampling Arduino, that is because in the end I will have 8 Arduinos recording on 8 channels, that is 64 different microphones. And they all need to record at the same time (+- the time for all 8 channels to take a sample within one Arduino). The sampling needs to be very quick that's why I've had to use register calls rather than normal Arduino wrapping code.

The way I see it it could be 2 things going wrong here

1. Some data type conversion is made wrong somewhere, overflowing the uint8 type, resulting in a weird amplitude but correct period. If so I'd be happy if someone could point to where.

2. Maybe the ADC doesn't read 8-bit, but some larger value that will overflow the 8-bit conversion again resulting in a weird amplitude but correct period. If so maybe someone could explain why, and how to correct it.



I hope the problem is understandable and I hope you will want help me pinpoint the problem or suggest a solution :) I've spent the better part of the day searching for an answer.

Here is the code for the sampling Arduino in text format as well:

Code: [Select]


volatile int sampleCount = 0;   //count samples so we don't get more than 1024
volatile bool measure = false;  //flag to decied if we want to sample or not

const byte interruptPin = 2;    //the interruptsignal comes to this pin

const int channels = 8;                         //the number of analog channels to record on
const int sampleMax = 1024;                     //length of the sample array
uint8_t recordedSamples[channels][sampleMax];   //2D array to store the sampled signals in

void setup() {
  //set interrupt pin
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(interruptPin, readSample, RISING);

  //ADC setup
  ADC->ADC_MR |= 0x80;  //set free running mode on ADC
  ADC->ADC_CHER = 0xFF; //enable ADC on pin A0-A7
  analogReadResolution(8); //<---- this seems to be ignored

  //serial setup and send ready message to MATLAB
  Serial.begin(250000);
  Serial.println("Slave ready");
}

void loop() {
  //In the main loop there is a while loop that checks for serial commands
   while (Serial.available() > 0) {
      //reads a byte from Serial. This byte is a "command" byte telling us  what to do
     char ans=Serial.read();
      if(ans=='r')
      {//In this case MATLAB wants us to begin reading samples
        //and listen to interrupts, 'a' is confirmation char in this case
        sampleCount = 0;
        Serial.write('a');
        measure = true;   //sets the flag to begin listen to interrupts
      }else if(ans == 'd')
      { //In this case MATLAB wants us to send the recorded signals on channel 0 and 7
        Serial.write(recordedSamples[0], sampleMax); 
        Serial.write(recordedSamples[7], sampleMax);
      }
   }

}

//This is the interrupt function
void readSample(){
  if (!measure) return;           //if this flag is false we dont want to begin sampling yet
  if (sampleCount >= sampleMax){  //if we've reached the end of sampling array we dont want to sample anymore
    measure = false;
    Serial.write('r');
    return;
  }

   while((ADC->ADC_ISR & 0xFF)==0); // wait for conversion
   
   for(int i=0; i<channels; i++){                     //goes through the channels
    recordedSamples[i][sampleCount]= ADC->ADC_CDR[i]; //read values into array
   }
   
   sampleCount++;                                     //increment what sample we are taking next time
}


Yours truly

jremington

#1
Nov 23, 2017, 12:38 am Last Edit: Nov 23, 2017, 12:40 am by jremington
What microphone, how is it amplified and how is it connected?
What is the "filter"?

Please post a hand drawn circuit diagram, not Fritzing.

ViktorWingqvist

#2
Nov 23, 2017, 01:31 am Last Edit: Nov 23, 2017, 01:36 am by ViktorWingqvist
What microphone, how is it amplified and how is it connected?
It is a custom built Loudspeaker/Microphone unit supplied with +-12 volts. When in microphone mode it outputs a signal that is greater than what the Arduino can handle, therefore..

What is the "filter"?
Please post a hand drawn circuit diagram, not Fritzing.
.. there is a simple circuit after the microphone that converts the signal down to a range of 0-3.3 V. maybe filter is the wrong word, it's kind of an op-amp with gain less than 1.

Surely I can supply you with diagrams of this, although I don't think it is relevant to the subject. Everything before the signal to the Arduino can be abstracted away, can't it? Since the signal I'm trying to sample is shown on the oscilloscope we can work from that, no? :)
Yours truly

jremington

Quote
although I don't think it is relevant to the subject.
You are quite wrong.

ViktorWingqvist

#4
Nov 23, 2017, 02:03 am Last Edit: Nov 23, 2017, 02:08 am by ViktorWingqvist
You are quite wrong.
You are quite wrong.
Pardon me and pardon my hand writing. Here is a block diagram of the setup. Should you want a component level schematics I can provide that as well, although I still don't think that is relevant. The input to the Arduino will just be a signal between 0 and 3.3 V. :)

EDIT: on the drawing it says 3-3.3 V, it should be 0-3.3 V, its quite late at the moment..



It is also attached as a .jpg
Yours truly

MorganS

That diagram seems sufficient to me. It clearly shows that you are measuring with the scope at the right point.

Just make sure you have the scope set to "DC" and it really is measuring what you think you're measuring. Check the divider switch on the probe (if any) and the other scope settings. I suspect that you still don't have the appropriate DC offset and it's clipping the signal at 0V or 3.3V.
"The problem is in the code you didn't post."

jremington

It appears that the mysterious "filter" is the problem.

ViktorWingqvist

#7
Nov 23, 2017, 02:22 am Last Edit: Nov 23, 2017, 02:37 am by ViktorWingqvist
Just make sure you have the scope set to "DC"
It is DC as shown on the picture, and the oscilloscope is on the same ground as everything else!

Check the divider switch on the probe
This is a mistake I did earlier this week and it was the first thing a checked, it's set to 1 as it should be! :)
Yours truly

ViktorWingqvist

It appears that the mysterious "filter" is the problem.
The signals looks like they should when viewing them on the oscilloscope. If the "filter" is the problem, then the oscilloscope settings are too. I will check this first thing when I'm back in the lab!
Yours truly

ard_newbie

#9
Nov 23, 2017, 05:50 am Last Edit: Nov 23, 2017, 06:02 am by ard_newbie
analogReadResolution(eight) do not exist with the Arduino DUE ! You can choose between 12 or 10 bits resolution.
Do not use magic numbers to program ADC registers, it is very painful to debug.

You will find numerous example sketches of ADC conversions thru registers programming in the Arduino DUE sub forum of this forum.

A 1 KHz sampling can't be an issue.

Wawa

The A/D should return half of the A/D range (512 or 2048) without signal, not clamped to ground as in your graph.

You must use a 1:1 voltage divider from VCC to ground, with center connected to the A/D, to float the input mid-voltage. And a DC blocking capacitor between filter and A/D.
Without those components, audio will be clamped (distorted) to ground by the pin clamping diodes.
Post a diagram of that filter.
Leo..

jremington

Judging from the green oscilloscope trace, the "filter" is oscillating at relatively high frequency. That is why the trace looks so thick.

MarkT

Yes, the filter is definitely oscillating, we need to see its schematic.

You don't need an amplifer to attentuate, and in fact its clearly a bad idea here as there is unwanted
oscillation.

[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

ViktorWingqvist

analogReadResolution(eight) do not exist with the Arduino DUE ! You can choose between 12 or 10 bits resolution.


Really? According to what I found here it seems it should work. Atleast it will automatically convert it to 8 bits by disregarding the LSBits.

https://www.arduino.cc/reference/en/language/functions/zero-due-mkr-family/analogreadresolution/


Do not use magic numbers to program ADC registers, it is very painful to debug.
Hard to debug, yes. But I didn't find another way of getting the desired results in terms of speed. If you have a suggestion on another approach I will gladly take advice from you :)


A 1 KHz sampling can't be an issue.
1 kHz signals is not a problem. However, it should work for 24 kHz (48 kHz sample rate) baseband audio signals.

Yours truly

ViktorWingqvist

The A/D should return half of the A/D range (512 or 2048) without signal, not clamped to ground as in your graph.
I'm not sure what you mean here. Do you mean that the yellow signal on the oscilloscope is centered at ground? It should be.

You must use a 1:1 voltage divider from VCC to ground, with center connected to the A/D, to float the input mid-voltage. And a DC blocking capacitor between filter and A/D.
With a capacitor between filter and A/D the signal will be centered around ground, and the range of the A/D is 0-3.3 so surely it has to be centered at 3.3/2?

Without those components, audio will be clamped (distorted) to ground by the pin clamping diodes.
Post a diagram of that filter.
Leo..
Yes, a lowpass filter you mean? As I said the current thing is not very good and is just put together of things we happened to have laying around in the lab. We will most probably put a lowpass filter there due to the high frequency oscillation displayed on the scope.
Yours truly

Go Up