PDA

View Full Version : Audio library without Audio adapter - ADC to RMS



nejohnson2
06-19-2016, 01:44 AM
I'm not much of an audio expert and I'm looking for a little advice on an issue. I've connected an ADMP401 MEMS mic to the Teensy 3.2 ADC pin A9 and I'm using the audio library to connect and calculate the RMS value of the incoming signal. The setup works, though the RMS output sits at 0.37 in quiet environments and max output is around 0.80. I expected the min and max values of 0-1 and I'm wondering why this is and how to resolve it.

I see in the Audio System Design documentation that the input signal range is 0 - 1.2v and since the mic specs indicate that the output signal sits at half of the VCC - 1.65v, I'm guessing this is the issue. Is this the case? And why is the input range 0-1.2v when I thought ADC input range is 0-3.3v?

Also, I'm still a bit perplexed on the sample rate and bit depth when using the ADC and/or the audio library. The audio library by default captures at 16bit/44.1k? I've come across the ADC library which enables various settings but I'm wondering if that applies and how to control sample rate and bit depth when using the Audio Library.

Thanks so much for the help!

Ben
06-19-2016, 01:58 AM
Hi,

the Audio Library switches the reference voltage to an internal reference which is more precise and less noisy that the 3.3V generated by Teensys voltage regulator. This enhances ADC performance but limits the input voltage to 0...1.2V.
The mic has an offset voltage of 0.8 volts (datasheet (https://www.pololu.com/file/download/ADMP401-datasheet.pdf?file_id=0J395)), not ideal since it's not exactly half the ADC voltage range, but it's ok. But with loud signals you will possibly overdrive the ADC because the signal will get larger than 1.2V, and you won't be able to use the full 0...1.2V range without overdriving the ADC (clipping).

To my knowledge the Audio Library is fixed at 44.1/16. The ADC is technically capable of sampling with 16 bit, but the lower bits are noisy, the effectively usable resolution is about 12 bits.

duff
06-19-2016, 04:40 AM
I see in the Audio System Design documentation that the input signal range is 0 - 1.2v and since the mic specs indicate that the output signal sits at half of the VCC - 1.65v, I'm guessing this is the issue. Is this the case? And why is the input range 0-1.2v when I thought ADC input range is 0-3.3v?

I'm using the same microphone just use this circuit:
7401
This will bias the signal at .6V DC. This one uses A2 but just connect it to whatever one you want. This mic will overdrive the ADC if is held close and talking loudly using the internal reference. If you have the sparkfun breakout (https://www.sparkfun.com/products/9868) you might be able to lower the gain by some circuit rework also.:D

Or you can wait for the update to the Audio library where it will let you change which reference you want i.e..(0->1.2V) or (0->3.3V).

PaulStoffregen
06-22-2016, 01:02 AM
I've come across the ADC library which enables various settings but I'm wondering if that applies and how to control sample rate and bit depth when using the Audio Library.

The functions to access in Arduino normalize the signal levels to a 1.0 scale with floating point numbers. Likewise, the sample rate isn't supposed to be exposed to Arduino code. Well, not unless you use the queue objects which provide access to raw data. Otherwise, the Arduino functions are meant to always work the same way, regardless of what sample rate and bit depth the library actually uses.

The sample rate is fixed. So is the bit depth. In theory you could edit the library code to change these, but it's not simple. The sample rate as a #define in AudioStream.h, but there's also device-level code in the input & output objects which is hard-coded for 44.1 kHz. You'd need to change all of that stuff. Likewise, the entire library is designed for 16 bits.

There is a high res 32 bit sine wave... and someday we'll have a 32 bit I2S output and maybe some other 32 bit stuff, which use a pair of 16 bit connections to move 32 bit data. Creating these takes a lot of programming work, and they run much slower, partly because they have to move twice as much data, but also because the Cortex-M4 DSP extensions are optimized to speed up 16 bit samples.

t3man
07-29-2016, 06:33 PM
HI,

I'm trying to read a couple of digital mics using the audio lib. I have the mics connected to the teensy with a i2s to pdm adapter and the i2s signals from the adapter are connected to the proper nets on the teensy.

When I use the AudioInputI2s class to create an input object I loose the usb serial on the teensy and the teensy is completely unresponsive.
I'm using Visual Studio 12 with Visual Micro with the Teensyduino load, not sure if that plays into the equation or not.

Here is the code..

#include "c:\Teensy 3.1\ICT\common\Audio\Audio.h"
#include "c:\Teensy 3.1\ICT\common\Audio\analyze_rms.h"

int s_line_flags;

AudioInputI2S micIn;
AudioAnalyzeRMS leftRMS;
AudioAnalyzePeak leftPeak;

AudioAnalyzeRMS rightRMS;
AudioAnalyzePeak rightPeak;


AudioConnection c1(micIn, 0, leftPeak, 0); //source, sourcePort, destination, destinationPort
AudioConnection c2(micIn, 1, rightPeak, 1);
AudioConnection c3(micIn, 0, leftPeak, 0); //source, sourcePort, destination, destinationPort
AudioConnection c4(micIn, 1, rightPeak, 1);

void p_main()
{
int inVal;

Serial.begin(115200);
//turn on LED so I know it's at least got power

AudioMemory(10); //declare audio blocks; 1 block is about 2.9ms of playback
micIn.begin();

while (1)
{
digitalWrite(4,!digitalRead(4));
Serial.printf(".");

if (leftPeak.available())
{
inVal = leftPeak.read();
Serial.printf(" LeftPeak = %d\r\n", inVal);
}

if (rightPeak.available())
{
inVal = rightPeak.read();
Serial.printf(" RightPeak = %d\r\n", inVal);
}
delay(50);
}
}

WMXZ
07-29-2016, 07:00 PM
HI,

I'm trying to read a couple of digital mics using the audio lib. I have the mics connected to the teensy with a i2s to pdm adapter and the i2s signals from the adapter are connected to the proper nets on the teensy.

When I use the AudioInputI2s class to create an input object I loose the usb serial on the teensy and the teensy is completely unresponsive.
I'm using Visual Studio 12 with Visual Micro with the Teensyduino load, not sure if that plays into the equation or not.



As you seem to have issues with VS, I suggest to try it out first with standard Arduino IDE, which is the official platform supported by PJRC; all others approaches are only useful if you are familiar with their usage. I, myself use plain makefile and NO IDE, but for technical questions on this forum I convert to Arduino IDE, so others can easily reproduce the problem and advice.

t3man
07-29-2016, 10:38 PM
Hi,

OK , that makes sense.
I ported the code to Arduino 1.6.7. When I load the code, the USB serial port come up but the code doesn't appear to run.
At a minimum, it should print out a dot on every loop and DOUT 4 should toggle, but nothing comes out the port and the OUTPUT 4 stays HIGH.

What am I missing?

Thanks
Tim


Here is the code.

#include <Audio.h>

AudioInputI2S micIn;
AudioAnalyzeRMS leftRMS;
AudioAnalyzePeak leftPeak;

AudioAnalyzeRMS rightRMS;
AudioAnalyzePeak rightPeak;

//AudioConnection c1(micIn, 0, leftPeak, 0); //source, sourcePort, destination, destinationPort
//AudioConnection c2(micIn, 1, rightPeak, 1);
//AudioConnection c3(micIn, 0, leftPeak, 0); //source, sourcePort, destination, destinationPort
//AudioConnection c4(micIn, 1, rightPeak, 1);

int s_line_flags;

void setup() {
// put your setup code here, to run once:

Serial.begin(115200);
Serial.println("Audio test Start UP");

pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);

AudioMemory(10); //declare audio blocks; 1 block is about 2.9ms of playback
micIn.begin();

digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);

}

void loop()
{
int inVal;

digitalWrite(4,!digitalRead(4));
Serial.printf(".");

if (leftPeak.available())
{
inVal = leftPeak.read();
Serial.printf(" LeftPeak = %d\r\n", inVal);
}

if (rightPeak.available())
{
inVal = rightPeak.read();
Serial.printf(" RightPeak = %d\r\n", inVal);
}
delay(50);
}

WMXZ
07-30-2016, 07:27 AM
Hi,

OK , that makes sense.
I ported the code to Arduino 1.6.7. When I load the code, the USB serial port come up but the code doesn't appear to run.
At a minimum, it should print out a dot on every loop and DOUT 4 should toggle, but nothing comes out the port and the OUTPUT 4 stays HIGH.

What am I missing?

Thanks
Tim


Here is the code.


#include <Audio.h>

AudioInputI2S micIn;
AudioAnalyzeRMS leftRMS;
AudioAnalyzePeak leftPeak;

AudioAnalyzeRMS rightRMS;
AudioAnalyzePeak rightPeak;

//AudioConnection c1(micIn, 0, leftPeak, 0); //source, sourcePort, destination, destinationPort
//AudioConnection c2(micIn, 1, rightPeak, 1);
//AudioConnection c3(micIn, 0, leftPeak, 0); //source, sourcePort, destination, destinationPort
//AudioConnection c4(micIn, 1, rightPeak, 1);

int s_line_flags;

void setup() {
// put your setup code here, to run once:

Serial.begin(115200);
Serial.println("Audio test Start UP");

pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);

AudioMemory(10); //declare audio blocks; 1 block is about 2.9ms of playback
micIn.begin();

digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);

}

void loop()
{
int inVal;

digitalWrite(4,!digitalRead(4));
Serial.printf(".");

if (leftPeak.available())
{
inVal = leftPeak.read();
Serial.printf(" LeftPeak = %d\r\n", inVal);
}

if (rightPeak.available())
{
inVal = rightPeak.read();
Serial.printf(" RightPeak = %d\r\n", inVal);
}
delay(50);
}

Tim,
to help the reader, try to wrap code into code tags use

... or '#' in advanced.

As Teensy is too fast to see early prints on terminal I replaced the Serial.begin with

while(!Serial);
delay(1000);
// Serial.begin(115200);

(note USB serial does not need baudrate setting)
Then you can see the setup printout and a single dot.
This means that program hangs early in loop

to know why
I simply put an additional print into the first if statement

if (leftPeak.available())
{
Serial.printf("L");
inVal = leftPeak.read();
Serial.printf(" LeftPeak = %d\r\n", inVal);
}

The letter 'L' is never printed, meaning that leftPeak.available() never returns with true.
As left/rightPeak.available() never return with 0 (otherwise this part would simply be skipped and dots printed),you can assume that leftPeak.available() crashes.

This no surprise, as you commented the connection

//AudioConnection c1(micIn, 0, leftPeak, 0); //source, sourcePort, destination, destinationPort
//AudioConnection c2(micIn, 1, rightPeak, 1);

Also, if you using I2S on audio card, you have to use SGTL5000 to set the chip (audio examples may help on settings)

Now, I do not have an Audioboard available, so I cannot go further and determine the reason of the crash

note that the c3/c4 connections are also going to left/rightPeak but you may have intended left/rightRMS?

defragster
07-30-2016, 09:29 AM
WMXZ: good notes - I learned that html wrap lets this show:

...

One thing that can cause trouble is infinite : while(!Serial);

This is a problem when running on battery for blink test or unconnected I like giving a timeout:

while (!Serial && (millis () <= 3000));

That also let me see that a recent TYQT change was not seeing the Teensy start and a borrowed sketch with the infinite while() never started and left me blind . . . I just got Koromix email that says it should be fixed . . .

WMXZ
07-30-2016, 10:45 AM
This is a problem when running on battery for blink test or unconnected I like giving a timeout:

while (!Serial && (millis () <= 3000));


Agreed, but I was too lazy to type it in.