Options for AnalogRead while AudioInputAnalog in Audio Library

Status
Not open for further replies.

mcivan

Active member
With my teensy3.1 and existing PCB for my interactive sound/light project I am attempting to implement the fantastic Audio library FFT analysis. My T3.1 takes input from an Adafruit mic, an analog light sensor, and also analog Read from a voltage divider. The current audio library 1.02 does not support the use of analogRead() as it crashes AudioInputAnalog. I put in a request on github, and haven't found a solution else where. I've considered the ADC library however just adding #include <ADC.h> breaks Audio Input Analog. Pedvide, any thoughts?

In my next hardware iteration I could consider I2C solutions to solve the current incompatibility, but I'm wondering if there is a simple software solution to get this running now. I'm only looking for 1 sample of each, every time the FFT is complete, they don't have to be averaged and are not time sensitive.

1) What is the cause of the core conflict? - My guess is something to do with interrupts and analogRead() waits for the conversion, which may be getting interrupted.

2) How difficult or possible would it be to implement a work around?


Code:
// FFT Test
//
// Compute a 1024 point Fast Fourier Transform (spectrum analysis)
// on audio connected to the Left Line-In pin.  By changing code,
// a synthetic sine wave can be input instead.
//
// The first 40 (of 512) frequency analysis bins are printed to
// the Arduino Serial Monitor.  Viewing the raw data can help you
// understand how the FFT works and what results to expect when
// using the data to control LEDs, motors, or other fun things!
//
// This example code is in the public domain.

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>

//#include <ADC.h>
//ADC *adc = new ADC(); // adc object

// Create the Audio components.  These should be created in the
// order data flows, inputs/sources -> processing -> outputs
// Using adafruit mic-amp, edit library to turn-off internal voltage reference in 
// inputAnalog.cpp 

AudioInputAnalog       adc1(15);
AudioSynthWaveformSine sinewave;
AudioAnalyzeFFT1024    myFFT;


// Connect either the live input or synthesized sine wave
AudioConnection patchCord1(adc1, 0, myFFT, 0);
//AudioConnection patchCord1(sinewave, 0, myFFT, 0);


void setup() {
  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(12);
  
  pinMode(15, INPUT);
  pinMode(14, INPUT);



  // Configure the window algorithm to use
  //myFFT.windowFunction(AudioWindowHanning1024);
  myFFT.windowFunction(NULL);

  // Create a synthetic sine wave, for testing
  // To use this, edit the connections above
  sinewave.amplitude(0.8);
  sinewave.frequency(1034.007);
}


void loop() {
  float n;
  int i;

  if (myFFT.available()) {
    // each time new FFT data is available
    // print it all to the Arduino Serial Monitor
    //Serial.print("T: "); //Testing touchRead
    //Serial.print(touchRead(0));
    Serial.print("\t FFT: ");
    for (i=0; i<40; i++) {
      n = myFFT.read(i);
      if (n >= 0.005) {
        Serial.print(n);
        Serial.print(" ");
      } else {
        Serial.print("  -  "); // don't print "0.00"
      }
    }
    Serial.println();        
  }
}

Interesting aside: touchRead works! I have five touch pins, { 0, 1, 16, 17, 33 } and I was able to read all of them while the FFT was running.
 
Last edited:
For documentation's sake, here is what doesn't work on my Teensy3.1:
- Initially tried the interrupt disable commands, this seems wrong after trying to understand the analog input functions.

Code:
AudioNoInterrupts();
analogRead(anyPin);
AudioInterrupts();

//also
__disable_irq();
analogRead(anyPin);
__enable_irq();

- It seems AudioInputAnalog demands a persistent configuration, and only one instance can exist. Again, this idea also failed:
Code:
AudioInputAnalog       micIn(15);
AudioInputAnalog       light(14);  // <<adding second instance/object breaks original, regardless of pin(?)
AudioSynthWaveformSine sinewave;
AudioAnalyzeFFT1024    myFFT;
AudioAnalyzePeak       peakTest;

AudioConnection patchCord1(micIn, myFFT);
AudioConnection patchCord2(light, peakTest);

Is there any reasonable solution to having additional analog inputs while analog audio is being streamed? With the T3.1 could only one ADC be configured with AudioInputAnalog, leaving some pins free for analogRead()? I'm ready to put a bounty on this, if so!
 
Last edited:
Hi Paul,

I've put a PM out to Pedro, but presently even " #include <ADC.h> " will break the AudioInputAnalog object/ADC configuration.
I'll keep everyone updated, but presently it looks like I'll have to find something else for FFT analysis from an analog Mic. The interface and performance of the Audio Library is temping... I'd rather contract a software solution than implement the Audio Shield when I really only need 1 channel of audio in, and no out.
 
analogRead ( A15-A20 ) works!
I'm not sure if there is any interference, but the 6 analog input pins ( 26-31 ) can by used in parallel with Audio Input Analog + FFT analysis.

I noticed AudioInputAnalog didn't have any of the #ifdef for the dual-adc Teensy 3.1 in the analog input setup... Sure enough it is only configured for the ADC0 and won't take input from A15-A20...

Edit:
I looked at attempting to edit the library, I was curious if it was as simple as replacing everything pertaining to ADC0 with ADC1, but editing this massive library seems impossible in the Arduino IDE.

I cut a trace and soldered a jumper, I can report that the A15-A20 do work in parallel with the FFT. However it returns a noisy 16bit value, and analogReadRes can't be used. Returns consistantly about +/- 3% Definitely a bit of a compromise.
 
Last edited:
Pedvide, as you've been looking into making the ADC library compatible with the Audio Library (or AudioInputAnalog), do you expect to only be able to access the other ADC that isn't being used to sample/stream audio? Is it possible to perform an analogRead in-between audio sampling? Or is that basically impossible?

Paul, thanks for the ADC select suggestion on GitHub! I agree! ^_^
 
Hi,

I've updated the ADC library and now it supports the Audio library, see more information at the ADC library forum post.

mcivan, so far the easy fix makes possible to use ADC_1 when Audio library is using ADC0. It might be possible to use ADC_0 to read in between Audio library samplings, but I think that'll be difficult.
One thing that Paul may want to do is to give an option to use ADC_1 with the Audio library.
 
One thing that Paul may want to do is to give an option to use ADC_1 with the Audio library.

There are currently 3 issues open on the audio library, regarding analog input stuff.

https://github.com/PaulStoffregen/Audio/issues/94

https://github.com/PaulStoffregen/Audio/issues/90

https://github.com/PaulStoffregen/Audio/issues/89

If it's related to any of those, please add a comment on github. Or if there's something else needed, feel free to open a new issue on the audio lib.

Please understand, at the moment I'm working on other non-audio stuff. I will get back to the audio library, and add a lot of stuff, but that'll probably be December or early next year. Anything important needs to be posted as an issue on github, where I'll see it in a couple months.
 
Thank you to both!
I've closed issue 90, it is not really relevant anymore. If issue 94 is solved I think we'd be in a great spot for flexibility and functionality, and I completely understand your timeline Paul! You are a busy guy and I believe all of us Teensy users are grateful for it!

Pedvide, I'm looking at the code you posted, I'll try it out soon and put any further questions on your ADC Library post.
 
I'm reposting this here, just for the sake of anyone Googling, it's sure to get lost in the ADC Master thread.
http://forum.pjrc.com/threads/25532-ADC-library-update-now-with-support-for-Teensy-3-1

Update: Now it works with the Audio library:
Teensy 3.0 is compatible, except if you try to use the Audio library ADC input (AudioInputAnalog), because there's only one ADC module so you can't use it for two things.
Teensy 3.1 is compatible. If you want to use AudioInputAnalog and the ADC you have to use the ADC_1 module, the Audio library uses ADC_0. Any calls to functions that use ADC_0 will most likely crash the program. Note: make sure that you're using pins that ADC_1 can read (see pictures above)! Otherwise the library will try to use ADC_0 and it won't work!!

Pedvide, this works fantastic! I numbers I get from my log scale light sensor are much more stable. Your library is certainly advanced but the more I read, I realized it is incredibly well documented! Thank you!

I found this image helpful for those trying to figure out which pins are on ADC0, ADC1, or both!
View attachment 2881
I have a jumper to cut and solder to change my mic pin, but this edit gets my two earlier prototypes running with ADC+Audio libraries!

Also, I went ahead and cleaned up the example code below. It's based on PRJC's FFT example but configured for taking audio from a mic without the Audio Board and taking an analog reading from ADC1 which currently isn't used by InputAudioAnalog. New Users: currently AnalogReference(INTERNAL) is currently hard coded into the library, depending on you wiring/mic you may need to edit the library. See: https://github.com/PaulStoffregen/Audio/issues/89
Important note from Paul on the topic:
I had originally intended to include an adc1.analogReference() function, like the DAC object has. Somehow, this never happened. It'll come in some future version. Pull requests are welcome.... (hint, hint)

However, changing the reference to 3.3V will reduce the signal amplitude by 3. For hardware where the signal is already very low, you might be better off using the recommended circuit. Those 2 extra capacitors and 4 resistors will buy your 3X the signal gain.

Code:
// FFT Test for Analog Mic
//
// Use PRJC's Audio library to compute audio spectrum analysis 
// from an analog mic input on ADC0 while taking an analog read 
// sample from a pin on ADC1 using Pedvide's ADC library. 
// Download the latest copy at:
// https://github.com/pedvide/ADC
//
// Compute a 1024 point Fast Fourier Transform (spectrum analysis)
// on audio connected to the Left Line-In pin.  By changing code,
// a synthetic sine wave can be input instead.
//
// The first 40 (of 512) frequency analysis bins are printed to
// the Arduino Serial Monitor.  Viewing the raw data can help you
// understand how the FFT works and what results to expect when
// using the data to control LEDs, motors, or other fun things!
//
// This example code is in the public domain. 


#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>

#include <ADC.h>

// CREATE THE ADC OBJECT FIRST, BEFORE ALL AUDIO STUFF!!
ADC *adc = new ADC(); // adc object
const int readPin = 30; // ADC1, Choose a pin the can be accessed by the ADC *NOT* being used to stream audio.
                        // Currently this must be a pin on ADC1, but has been suggested as a fix for the audio library.

// Create the Audio components.  These should be created in the
// order data flows, inputs/sources -> processing -> outputs
// Using adafruit mic-amp, edit library to turn-off internal voltage reference in 
// inputAnalog.cpp 

AudioInputAnalog       analogAudioIn(15); //Pin 15, mic pin, currently must be on ADC0
AudioSynthWaveformSine sinewave;
AudioAnalyzeFFT1024    myFFT;



// Connect either the live input or synthesized sine wave
AudioConnection patchCord1(analogAudioIn, 0, myFFT, 0);
//AudioConnection patchCord1(sinewave, 0, myFFT, 0);




void setup() {
  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(12);



  // Configure the window algorithm to use
  //myFFT.windowFunction(AudioWindowHanning1024);
  myFFT.windowFunction(NULL);

  // Create a synthetic sine wave, for testing
  // To use this, edit the connections above
  sinewave.amplitude(0.8);
  sinewave.frequency(1034.007);


  adc->setAveraging(8, ADC_1); // set number of averages
  adc->setResolution(12, ADC_1); // set bits of resolution
  adc->setConversionSpeed(ADC_VERY_LOW_SPEED, ADC_1); // change the conversion speed
  adc->setSamplingSpeed(ADC_VERY_LOW_SPEED, ADC_1); // change the sampling speed

}

int value = 0;

void loop() {
  float n;
  int i;

  value = adc->analogRead(readPin, ADC_1); // read a new value, will return ADC_ERROR_VALUE if the comparison is false.

  if (myFFT.available()) {
    // each time new FFT data is available
    // print it all to the Arduino Serial Monitor
    //Serial.print("T: "); //Testing touchRead
    //Serial.print(touchRead(0));
    Serial.print("Pin: ");
    Serial.print(readPin);
    Serial.print(" = ");
    Serial.print(value*3.3/adc->getMaxValue(ADC_1), DEC); //assuming 3.3v reference voltage
    Serial.print("v   FFT: ");
    for (i=0; i<40; i++) {
      n = myFFT.read(i);
      if (n >= 0.008) {
        Serial.print(n);
        Serial.print(" ");
      } 
      else {
        Serial.print("  -  "); // don't print "0.00"
      }
    }
    Serial.print("\n"); 
  }
}

I've learned a lot from this issue! Thanks to everyone who helped!
 
Status
Not open for further replies.
Back
Top