Analog signal issues with migration from Arduino UNO to Teesny 3.1. Help requested.

Status
Not open for further replies.
Edit 5/27/14 5:10 pm PST: Thank you for all of the responses, I've increased the size of the serial monitor screen shots to make them more legible and added the code I'm using at the bottom of the post. Also, to clarify, each column in the serial monitor corresponds to a frequency band of the audio signal, low on the left, high on the right, ranging from ~120hz to 24khz (I think, can't remember exactly) Thanks again!



Hello all,

I'm using MSGEQ7 audio spectrum analyzer ICs to turn a strip of LEDs into a audio spectrum visualizer. I had originally designed this project to use an arduino UNO but due to other aspects of the project I switched to using a Teensy 3.1 for this portion. Switching back is not an option.

The hardware is pretty simple, I'm using a MAX4466 electret microphone with adjustable gain, input voltage from 3-5v (5v recommended, though I've had better results in all cases with 3.3v input). The output from the microphone goes to the MSGEQ7, 3-5v input (5v recommended) which breaks the audio signal into 7 analog signals, one for each frequency band. Those signals are then read by the controller and mapped to brightness values on the LED strip.

To get additional frequency bands I'm using 5 MSGEQ7's total with their clocks shifted by various capacitors and resistors to give me a total of 35 bands. I built this on a homemade double sided circuit board (probably not relevant but I'm proud of it so I'll post it below).

20140526_103847-2.jpg



When using the UNO I powered the microphone with 3.3v, the MSGEQ7s with 5v, and was able to read all of the analog outputs with acceptable levels of noise without any fuss. BUT, now that I've migrated to Teensy, I run into a problem (about problem number 300 on this project).

I've tried many combinations of input voltages to the devices and using the analog or digital ground for either the microphone or the analyzer or both. I've also tried using a voltage divider to bring the signal from the MSGEQ7s down to the 0 - 3.3v range.

I've tried:

Microphone............MSGEQ7s...........AGND/GND...................OTHER.....................................................Result

5v........................5v........................GND........................n/a...................................................Unacceptable noise
3.3v......................5v.......................GND........................n/a...................................................Unacceptable noise
5v........................3.3v.....................GND........................n/a...................................................Unacceptable noise
3.3v......................3.3v.....................GND........................n/a...................................................Unacceptable noise
5v........................5v........................AGND ......................n/a...................................................Unacceptable noise
3.3v......................5v.......................AGND.......................n/a...................................................Unacceptable noise
5v........................3.3v.....................AGND.......................n/a...................................................Unacceptable noise
3.3v......................3.3v.....................AGND.......................n/a...................................................Unacceptable noise
5v........................5v........................GND........................Voltage divider 47k & 91k.......................Unacceptable noise
3.3v......................5v.......................GND........................Voltage divider 47k & 91k.......................Unacceptable noise
5v........................5v........................AGND......................Voltage divider 47k & 91k.......................Unacceptable noise
3.3v......................5v.......................AGND......................Voltage divider 47k & 91k....................... Unacceptable noise




Here's what my values look like in the serial monitor in a few different setups. (they're legible on my screen, let me know if they aren't on yours):


UNO, microphone: 3.3v, MSGEQ7s: 5v.
UNO2.jpg

Teensy 3.1, microphone: 3.3v, MSGEQ7s: 5v.
Teensy2.jpg

Teensy 3.1, microphone: 3.3v, MSGEQ7s: 5v w/voltage divider.
TeensyWithVoltageDivider2.jpg

The other options I'm looking at are:

A) Use an op-amp to shift the voltage levels down (I'm not familiar with using op-amps for anything so this would take some additional learning on my part)
B) Use an external ADC to read the signals then read the data from the external ADC via i2c to get my values. I am a little worried that getting 35 values this way and displaying them in as near to real time as possible on 288 LEDs might be an issue, but I don't know of any way to calculate that risk without just trying it.

I don't understand why the Teensy would be getting so much more noise even with the signals brought down to the proper range. The teensy isn't just fundamentally noisier is it? Could it have something to do with the resolution of the Teensy's ADC vs. the UNOs ADC? I can't help but think that I'm just missing something about the Teensy that differs from an Arduino UNO. I'm completely self taught when it comes to electronics other than my basic electrical knowledge from being an electrician so ignorance is VERY possibly the root of the problem here.

I don't think my code is relevant in this case since I don't have any issues with it but it is available if anyone thinks it could help.

And of course, thank you very much for taking the time to look at this and know that your help will be greatly appreciated.





Here is the code I'm using below:

Code:
int analogPins[5] = {
  0, 1, 2, 3, 4}; // MSGEQ7 OUT 3
int strobePin = 2; // MSGEQ7 STROBE 4
int resetPin = 4; // MSGEQ7 RESET 7 
int spectrumValue[35];

// MSGEQ7 OUT pin produces values around 50-80
// when there is no input, so use this value to
// filter out a lot of the chaff.
int filterValue = 94;



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

  // Read from MSGEQ7 OUT
    for (int i = 0; i <5; i++)
    {   
    pinMode(analogPins[i], INPUT);
    }
  // Write to MSGEQ7 STROBE and RESET
  pinMode(strobePin, OUTPUT);
  pinMode(resetPin, OUTPUT);

  // Set startup values for pins
  digitalWrite(resetPin, LOW);
  digitalWrite(strobePin, HIGH);
}

void loop()
{
  digitalWrite(resetPin, HIGH);
  digitalWrite(resetPin, LOW);
  for ( int i = 0; i < 7; i++)
  {
    digitalWrite(strobePin, LOW);
    delayMicroseconds(30); // Allow output to settle  
    for (int j = 0; j < 5; j++)
    {
      spectrumValue[(i*5)+j] = analogRead(analogPins[j]);
      spectrumValue[(i*5)+j] = constrain(spectrumValue[(i*5)+j], filterValue, 1023);
      spectrumValue[(i*5)+j] = map(spectrumValue[(i*5)+j], filterValue, 1023, 0, 255);
      Serial.print(spectrumValue[(i*5)+j]);
      if (spectrumValue[(i*5)+j] < 10)
      {
        Serial.print("   ");
      } 
      else if ((spectrumValue[(i*5)+j] < 100))
      {
        Serial.print("  ");
      } 
      else 
      {
        Serial.print(" ");
      }       
    }
    digitalWrite(strobePin, HIGH);
  } 
  Serial.println(" ");
}
 
Last edited:
Your screen dump are unreadable -- too small.

I don't think ADC noise is likely your issue. Check your signals with a single tone input (use a Teensy to generate one if you don't have a whistle), and see if the expected output is there.

If you don't have an oscilloscope, use a Teensy 3.1's DAC to send the output from a selected channel to a pin that you can read with a meter.
 
Analog noise problems are always tough to diagnose, even with all the parts present, but especially over the internet!

One possible issue is the source impedance. 47K and 91K resistors are far too high. Try using 2.2K and 4.7K.

Another possibility you might consider is the 1024 point FFT in the audio library. You might be able to bring the audio signal directly into a single ADC pin or one channel on the audio shield and let Teensy 3.1 do all the spectral analysis in software. Then you wouldn't need any MSGEQ7 chips!

I had this running at Maker Faire, displaying the spectrum on a 60x32 LED board. Here's some photos:

http://dorkbotpdx.org/blog/paul/maker_faire_2014

I'll attach the code that was running on that Teensy 3.1 doing the spectral analysis and LED control.
 

Attachments

  • FFT_LEDs_2.ino
    6.1 KB · Views: 248
What's the resolution and the number of averages of the ADC? Increasing the latter will have a big impact on the noise.
 
I don't understand why the Teensy would be getting so much more noise even with the signals brought down to the proper range. The teensy isn't just fundamentally noisier is it? Could it have something to do with the resolution of the Teensy's ADC vs. the UNOs ADC? I can't help but think that I'm just missing something about the Teensy that differs from an Arduino UNO.

Yes, there is a significant difference between them.

Arduino Uno ADC theoretical resolution is 10bits. Values are in the range 0 to 1023 (2 to the power 10, minus 1).
Teensy 3.1 ADC theoretical resolution is 16bits. Values are in the range 0 to 65,535 (2 to the power 16, minus 1).

This means that a noise value of say 4 on the Uno (4/1024) is in percentage terms the same as a value of 256 (256/65535) on the Teensy 3.1. From what I can see on the screendump, you are getting values up to 30 or so. Which on the Uno would be a value of less than one (30/64). You aren't getting more noise; you are getting a lot less (but larger numbers).

I don't think my code is relevant in this case since I don't have any issues with it but it is available if anyone thinks it could help.
Without your code (which is barely readable in the screen dump) we don't know how you are using the ADC (at what bit depth? How much averaging?)
 
Thank you all for the responses! I already have many more solutions to explore than I had on my own.

Jp3141:
"Your screen dump are unreadable -- too small." - I have increased the size of the screenshots.

"Check your signals with a single tone input (use a Teensy to generate one if you don't have a whistle), and see if the expected output is there." - I have been using a tone generator (onlinetonegenerator.com) to check the signals. The signals do increase as volume does, as expected, though "relative" quiet gives far higher signals than with the UNO. I could definitely compare the magnitude of the signals at a given volume between setups to see what kind of difference there is. That could give me another clue. Thanks for the idea!

"If you don't have an oscilloscope, " - I do not have an oscilloscope. I've been thinking about taking the plunge on a decent Rigol or something for a while now. Here's one more reason to.

"use a Teensy 3.1's DAC to send the output from a selected channel to a pin that you can read with a meter." - I'm not sure what you mean by "to a pin you can read with a meter" are you saying to take the input of a single frequency band, generate an analog signal with the teensy's DAC using that signal, then read that output with a simple multimeter? I thought the Teensy's DAC could only output on the DAC pin. If that is what you mean, I could definitely do that but I'm not sure what it would be telling me.


PaulStoffregen:
"One possible issue is the source impedance. 47K and 91K resistors are far too high. Try using 2.2K and 4.7K." - I was wondering about that. That combination was a suggestion I saw for someone else's problem on another forum. I will definitely give that a try!

"Another possibility you might consider is the 1024 point FFT in the audio library. You might be able to bring the audio signal directly into a single ADC pin or one channel on the audio shield and let Teensy 3.1 do all the spectral analysis in software. Then you wouldn't need any MSGEQ7 chips!" - That was one of the options I had considered for this portion of the project. While playing with it, I did use the FFT and the FHT libraries and Processing to visualize the frequencies but I found the library to be a bit intimidating. I had no clue how to shift the range of frequencies to more useful ones (inside the range of human hearing and with greater resolution in that range) or even how to pull out values that I could use to drive the LEDs. I was also concerned that having the Teensy (at the time, UNO) do all the heavy lifting with processing the audio while performing other tasks and still being responsive to user input. Using MSGEQ7's was a far simpler solution for this small part of the project (which I thought I had nailed until I switched to Teensy). This is another option if I don't make headway with the problem at hand though.

"I had this running at Maker Faire, displaying the spectrum on a 60x32 LED board. Here's some photos:" - That looks awesome! Great work getting the LEDs evenly spaced and aligned. I'm using WS2812b's and the strips came soldered together in some places. I didn't find out until after I had them all cut up that the distance between LED's across a solder is different than the rest of the strip. That's a headache that I have yet to deal with.

"I'll attach the code that was running on that Teensy 3.1 doing the spectral analysis and LED control." - Thanks! That'll be a huge help if I end up using the FFT/FHT method for this or any project. And for if I try to do video with LEDs at some point.


Pedvide:
"What's the resolution and the number of averages of the ADC? Increasing the latter will have a big impact on the noise." - That's a good question. From PJRCs "changes in Teensy 3.1" I can see that the resolution is 16 bits with 13 usable. As to the number of averages, I have no idea. Is that something I can alter through code? I'll have to look into that. Up until now, I didn't even realize that I would have to handle the Teensy any differently from an UNO for this part of the project. Doing some research on the Teensy's ADC vs. the UNO's and analog to digital conversion in general is definitely in order.


Nantonos:
"Yes, there is a significant difference between them." - I thought that might be the case. The Teensy is so much more capable but no where near as idiot proof (to my dismay). I'm learning way more this way though.

"Arduino Uno ADC theoretical resolution is 10bits. Values are in the range 0 to 1023 (2 to the power 10, minus 1).
Teensy 3.1 ADC theoretical resolution is 16bits. Values are in the range 0 to 65,535 (2 to the power 16, minus 1).

This means that a noise value of say 4 on the Uno (4/1024) is in percentage terms the same as a value of 256 (256/65535) on the Teensy 3.1. From what I can see on the screendump, you are getting values up to 30 or so. Which on the Uno would be a value of less than one (30/64). You aren't getting more noise; you are getting a lot less (but larger numbers)." - Gotcha. I will definitely review my code (which I have added to the bottom of my original post) and see what sort of changes I should make in response. I'm spending all the free time I have tonight responding to the awesome people helping me though. I will look into this shortly. I also plan to see what sort of signal I get at a given volume and frequency between the UNO and the Teensy.

"Without your code..." - Code added to OP.



Thank you everyone again for your help. I've spent all the free time I have tonight thoroughly responding to everyone's comments so I wont be able to test anything until tomorrow at the earliest. I will update as soon as possible.
 
Last edited:
Looking at your code you are using the default settings for the ADC, which are 10 bits resolution and 4 averages. You can change the averages with analogReadAveraging(x), with x=0, 4, 8, 16 or 32. This will increase the time that a conversion needs, but it will also smooth out the noise.
What's the resolution you need? Higher resolution also takes more time to convert, so it's better to increase the averages and decrease the resolution if you can.

The last thing on the software side is to use the internal 1.2 V reference. For that you need to scale down you signals to the range (0, 1.2) V and call analogReference(INTERNAL). In principle this reference is more stable and has lower noise, specially if you are powering the Teensy from USB.

In order to really know if the noise is going down or not, you need to actually calculate some magnitude of noise and define what's acceptable and what's not. In the last screenshot I can see an average value of about 15, so that's a noise level of 1.5%, which I think is low (it corresponds to 50 mV in 3.3V).

In the table with all your tests you seem to have tried to measure inputs of 5V! That's not possible!! The ADC only works in the range (0, 3.3) V or (0, 1.2) V. Teensy 3.1 is 5 V tolerant in the digital pins, but it will measure voltages from 3.3 to 5 V as 1023 (with 10 bit resolution)!

In the code it appears that you are already subtracting some background from the chip. How did you measure this value? with the Teensy or ONO? In the setup of your script you could measure this background to account for changing conditions.
 
Pedvide:

"You can change the averages with analogReadAveraging(x)" - Great info. When I've needed to average samples before I've tossed X number of them into an array then add, divide, shift, repeat, etc. This sounds much less code intensive.

"The last thing on the software side is to use the internal 1.2 V reference. For that you need to scale down you signals to the range (0, 1.2) V and call analogReference(INTERNAL)." - Can do. Would a voltage divider of say 3.8kohm->series and 1.2kOhm->ground be a reasonable method for this? I don't know what the theory is for resistance values for this (or any other, really) situation besides maintaining the desired ratio. I'm guessing lower is better in most cases?

"In principle this reference is more stable and has lower noise, specially if you are powering the Teensy from USB." Testing is on USB, final product will be a 5v power supply. Definitely something to try.

"In order to really know if the noise is going down or not, you need to actually calculate some magnitude of noise and define what's acceptable and what's not. In the last screenshot I can see an average value of about 15, so that's a noise level of 1.5%, which I think is low (it corresponds to 50 mV in 3.3V)." -The code cuts off X lower range of the signal and maps what's left back to the 0 - 1024 range. Something I forgot to mention was that even taking this lower filter value up to around 200 still produces non-zero values in "relative" silence. The screenshots don't do a very good job of capturing the fact that the signal varies wildly.

"In the table with all your tests you seem to have tried to measure inputs of 5V! That's not possible!! The ADC only works in the range (0, 3.3) V or (0, 1.2) V. Teensy 3.1 is 5 V tolerant in the digital pins, but it will measure voltages from 3.3 to 5 V as 1023 (with 10 bit resolution)!" - My thought here was that the output of the MSGEQ7s probably rarely goes over the 3.3v range (although I guess it will in very loud situations). Also, the data sheet of the MSGEQ7 recommends an input of 5v and since the Teensy's non analog only pins are 5v tolerant I thought I would give that a try since I had success with that before.

"In the code it appears that you are already subtracting some background from the chip. How did you measure this value? with the Teensy or ONO? In the setup of your script you could measure this background to account for changing conditions." - I simply kept raising that number until the "massaged" values were ~0 in relative silence. The value of 94 was a number I settled on with the UNO for sensitive yet noise free values. As for automatically setting that number, a stray sound during setup could be problematic.
 
Last edited:
I simplified my code to only print raw values to the serial monitor and I'm currently only reading the data from one of the 5 MSGEQ7s until I get this noise issue settled.

I ran a bunch more tests with some of the suggestions above. All tests are with the microphone input voltage at 3.3v, and using the analog ground of the Teensy. Any test tones are at a fixed volume and speaker to microphone distance for all tests. Here are my results compiled into 3 images:

Tests 1 - 4:

UnoTests.jpg


#1) The original setup using an Arduino UNO. Microphone VDD: 3.3v, MSGEQ7 VDD: 5v. Pretty consistent values, maximum high/low difference of ~30. Max relative silence values around ~ 110.
#2) Same setup as #2 with a 440hz tone. Pretty consistent values, maximum high/low difference of ~30 as above.
#3) I powered the microphone and the MSGEQ7 with the 3.3v and 5v (respectively) pins of the UNO played a 440hz tone. The output of the MSGEQ7 was read by the Teensy after transforming the max signal voltage to ~3.3v with a (2.2kOhm --> series, 4.7kOhm --> ground) voltage divider. Grounds of the Uno and Teensy were tied together. This is probably my best setup with the Teensy so far with max high/low differences of ~100.
#4) Same setup as #3 with no test tone. Max high/low differences of ~60. Max relative silence values around ~ 150.

Tests 5 - 8:

TestsWithSound.jpg

#5) MSGEQ7 VDD: 5v, (3.8kOhm --> series and 1.2kOhm --> ground) voltage divider brings the signal range to ~0 - 1.2v. The internal analog reference of the Teensy is used. Max high/low differences of ~180. Max relative silence values around ~ 400.
#6) MSGEQ7 VDD: 3.3v. No voltage divider. 440hz test tone. Default analog reference. Max high/low differences of ~200.
#7) MSGEQ7 VDD: 5v, (2.2kOhm --> series, 4.7kOhm --> ground) voltage divider brings the signal range to ~0 - 3.3v. 440hz test tone. Max high/low differences of ~150.
#8) MSGEQ7 VDD: 5v, (3.8kOhm --> series and 1.2kOhm --> ground) voltage divider brings the signal range to ~0 - 1.2v. The internal analog reference of the Teensy is used. 440hz test tone. Max high/low differences of ~300.


Tests 9 -12:

OtherTests.jpg

#9) MSGEQ7 VDD: 3.3v. No voltage divider. Default analog reference. Max high/low differences of ~120. Max relative silence values around ~ 160.
#10) Same setup as #9. analogReadAveraging(32) is called. Max high/low differences of ~110. Max relative silence values around ~ 180.
#11) MSGEQ7 VDD: 5v, (2.2kOhm --> series, 4.7kOhm --> ground) voltage divider brings the signal range to ~0 - 3.3v. Max high/low differences of ~120. Max relative silence values around ~ 170.
#12) Same setup as #11 with 1 millisecond delays added after any pin state change or reading. Max high/low differences of ~80. Max relative silence values around ~ 250. This one is odd as only altering the code increased the maximum relative silence values and substantially smoothed the high/low difference. This slowed the program way down though.

A table sorted by test #.
TableTestSort.jpg

A table sorted by max high/low difference
TableHighLowSort.jpg


To do:

1) Try an external regulated 3.3v supply. The regulated 5v output of the UNO seemed to give better results than the 5v from the USB.
2) Play with adding delays to the code (maybe the teensy is reading the MSGEQ7s faster than they can take readings? Shot in the dark)
3) Drink alchohol.


As a side note, I got a couple of external ADCs that can be read via i2c in the mail. I haven't had good results so far.
 
I've had a look at the datasheet https://www.sparkfun.com/datasheets/Components/General/MSGEQ7.pdf.
It says:
Output Offset 600 mV
Band Offset Difference 200 mV

Does this mean that the output zero is actually 600 mV? In this case with a supply of 3.3V this would correspond to 180 counts, which is what you see with a Teensy and 32 averages.
There's something else I don't understand: "The multiplexor read rate is also the output decay time control. Each read decays that channel approximately 10%." So maybe timing is important.
I've found two tutorials for arduino that have code, maybe have a look at them, if you haven't:
http://nuewire.com/info-archive/msgeq7-by-j-skoba/
http://tronixstuff.com/2013/01/31/tutorial-arduino-and-the-msgeq7-spectrum-analyzer/
 
In the datasheet it explains the timing requirements as follows:

tr - Reset Pulse Width 100 nS min .................................................................Reset HIGH ---> (100nS delay min) ---> Reset LOW
trs - Reset to Strobe Delay 72 uS min ............................................................Reset LOW ---> (72uS delay min) ---> Strobe LOW
ts - Strobe Pulse Width 18 uS min .................................................................Strobe LOW ---> (18uS delay min) ---> Strobe HIGH
tss - Strobe to Strobe Delay 72 uS min ..........................................................Strobe LOW ---> (7uS dealy min) ----> Strobe LOW
to - Output Settling Time 36 uS min (with Cload = 22 pF and Rload = 1 Mohm) ......Strobe LOW ---> (36uS settling time) ---> AnalogRead

I tried making some adjustments to the code to ensure that it complies with these requirements. It doesn't specify any maximum times so I added a little headroom. Here's the loop of my code with some comments.

Code:
void loop()
{
  digitalWrite(resetPin, HIGH);
  delayMicroseconds(1);               // ------------------------------------------------ Added  
  digitalWrite(resetPin, LOW);
  delayMicroseconds(75);             // ------------------------------------------------ Added  
  for (int i = 0; i < 7; i++)
  {
    digitalWrite(strobePin, LOW);
    delayMicroseconds(40);           // ------------------------------------------------ Changed from 30 to 40uS
    spectrumValue[i] = analogRead(analogPin);
    if (spectrumValue[i] < 10)
    {
      Serial.print("    ");
      Serial.print(spectrumValue[i]);
    }
    else if (spectrumValue[i] < 100 )
    {
      Serial.print("   ");
      Serial.print(spectrumValue[i]);
    }
    else if (spectrumValue[i] < 1000 )
    {
      Serial.print("  ");
      Serial.print(spectrumValue[i]);
    }
    else
    {
      Serial.print(" ");
      Serial.print(spectrumValue[i]);
    }
    digitalWrite(strobePin, HIGH);
    delayMicroseconds(75);             // ------------------------------------------------ Added
  }
  Serial.println("");
}

Sadly, this doesn't seem to give much or any improvement with a maximum high/low difference of ~60 in the screenshot and worse in live tests.

TimingTest.jpg

I noticed that in this screenshot, taken in relative silence, the "noise" on the lower two frequencies seems to be roughly the shape of a sine wave. Odd.


Does this mean that the output zero is actually 600 mV? In this case with a supply of 3.3V this would correspond to 180 counts, which is what you see with a Teensy and 32 averages.
I believe so, yes. I'm guessing this is why a 5v supply is recommended. I'm not sure why I would be getting such high values still with the supply voltage at 5v and the signal sent though a voltage divider though.

There's something else I don't understand: "The multiplexor read rate is also the output decay time control. Each read decays that channel approximately 10%." So maybe timing is important.
I was hoping that that was the case but, beyond what I just tried, I don't know what else I could do in this department.

I've found two tutorials for arduino that have code, maybe have a look at them, if you haven't:
http://nuewire.com/info-archive/msgeq7-by-j-skoba/
http://tronixstuff.com/2013/01/31/tu...trum-analyzer/

I'm actually using a modified version of J Skoba's code in the first link. The code in the two links is nearly identical other than the second being for a "shield" version from Sparkfun.

I did notice something odd in a test I did earlier. I used my original code in two different setups, then simply blew on the microphone to max out all the values. With all 5 MSGEQ7s being read, each one is responsible for every 5th frequency.

1) Original setup, all 5 MSGEQ7s
2) UNO powering the msgeq7s (at 5v) and microphone with the Teensy taking the readings (grounds tied together, no voltage divider). My understanding with not using a voltage divider here is that the signal should read, and any fluctuations should be, proportionally higher up until the 3.3v mark where it will just read as ~1024. This doesn't explain the crazy erratic values I get.

1)
UNOblowTest.jpg

2)
TeensyBlowTest.jpg

Using the Teensy, the MSGEQ7 that's shifted the lowest, frequency wise, gives extremely erratic values for each frequency it's responsible for. The lowest frequency of the other 4 are erratic as well. I have no idea why it would do this when being read by the Teensy and not when read by the UNO while being powered by the same source in each test.

I'm considering de-soldering one of the MSGEQ7s from the board I made to test it in isolation with it's default clock frequency. I'm not confident that would be revealing though.
I'm also considering a way to switch control of the LEDs in my project to an UNO when the project is in "Audio Analysis" mode as a workaround. I'm trying to think of a simple way to have the data input of the LEDs connected to two microcontrollers but have them driven by only one at a time. There's probably a dead simple way to do this but this problem's making my brain hurt.

Any recommendations on a hobby level oscilloscope? If I got one, I'd want it to also be useful for troubleshooting things like digital communications too. Or is an oscilloscope and separate logic analyzer the way to go for that?

Thanks a bunch for the suggestions Pedvide and anyone else that's lent a hand. I'll report back with anything else I find.
 
Well I tested out the work-around solution and that appears to be a viable option.

This post of mine in the Arduino forums details what I might do: http://forum.arduino.cc/index.php?topic=244005.new;topicseen#new

In summary, rather than swapping the UNO for a Teensy as I had intended, I'll have both of them in the project simultaneously. When the project switches to "Audio Analysis" mode, the Teensy will "hand off" control of the LED's to the UNO which will be running the Audio Analysis code, the microphone and the MSGEQ7s.To perform the "hand off" the Teensy and UNO will be connected via i2c with the UNO as a slave device. The "data out" pins of both controllers will be connected together and to the LED strip they're driving. When it's time to swap, the Teensy will set the pins sending data to the LEDs to INPUTs, then tell the UNO to set it's pins to OUTPUTs and begin doing it's thing. When it's time to swap back the reverse happens.

This IS a work-around and it tastes like defeat, but on the plus side, I won't have to use any of the underside pins of the Teensy. I'm going to test this out tomorrow and if it works I won't be actively pursuing a solution to this particular issue.

I'd still love to hear anyone's suggestions and if a solution does present itself I'd probably prefer to implement that rather than the work-around.

Thanks for all the help, I'll continue to update if anything new happens with this and maybe post the finished product here when it's done. It should be pretty cool.
 
I can't comment on the code or the methods used. But I do recommend you consider the use of a TXS series voltage translator (IIRC, it's the I2C equivalent to the TXB series that I have used use for SPI and serial) when communicating between a 5V uno and a 3.3V Teensy 3.1 using I2C. see http://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=scea044

Additionally, consider EasyTransfer from Bill Porter as a means of easily transferring said data. He makes transferring large chunks of data very easy, on serial and I2C, and the CRC checks ensure that everything you sent actually gets there. see http://www.billporter.info/2011/05/30/easytransfer-arduino-library/

As for whether to consider your solution a kludge or not, I can't say. The question of what solution to pursue will always depend heavily on available resources, expected manufacturing volumes, etc. Especially for one-off solutions, it frequently makes sense to pursue something that works (with extra $$$ hardware thrown at the problem) versus engineering the perfect solution (lots of overhead, life if short, and so on). Congrats on an interesting project, hope it works!
 
Last edited:
I can't comment on the code or the methods used. But I do recommend you consider the use of a TXS series voltage translator (IIRC, it's the I2C equivalent to the TXB series that I have used use for SPI and serial) when communicating between a 5V uno and a 3.3V Teensy 3.1 using I2C. see http://www.ti.com/general/docs/lit/g...Number=scea044

I've had good luck so far with this logic level converter (https://www.adafruit.com/product/757) from Adafruit. They warn that it's not great for high speed transfers but for this simple of an application it should work fine. As for the TXS series device you mentioned, if I have anything more complicated I'll definitely consider it. Although, with a quick search, it looks like they only come in SMD packages.

Additionally, consider EasyTransfer from Bill Porter as a means of easily transferring said data. He makes transferring large chunks of data very easy, on serial and I2C, and the CRC checks ensure that everything you sent actually gets there. see http://www.billporter.info/2011/05/3...duino-library/

That will definitely come in handy in the future. I've been writing my own crude communication protocols until now. Looks like someones even making a VirtualWire version of it too.

As for whether to consider your solution a kludge or not, I can't say. The question of what solution to pursue will always depend heavily on available resources, expected manufacturing volumes, etc. Especially for one-off solutions, it frequently makes sense to pursue something that works (with extra $$$ hardware thrown at the problem) versus engineering the perfect solution (lots of overhead, life if short, and so on). Congrats on an interesting project, hope it works!

Yeah, progress is the ultimate goal here but gaining a deeper understanding of the things I'm working with is a close second. And thanks!
 
I was wondering that too, so I just tried powering it from my laptop (not plugged in) and got the same result. So much for that. That doesn't explain why that would happen with the Teensy and not the UNO either.
 
Yes the BSS138 approach to level shifting works well also. I've used it for i2c as well as other applications. And given that adafruit has it as a fully-fleshed out solution, that's even better. Just remember that the boards will still need to be connected by a common ground.
 
I was wondering that too, so I just tried powering it from my laptop (not plugged in) and got the same result. So much for that. That doesn't explain why that would happen with the Teensy and not the UNO either.

Many, many years ago when I was trying to read from a Temp sensor which put out a current signal ( voltage drop over long wires not a problem ) I experienced this problem. It was my first attempt at using an A/D. The read temperature was all over the place. Then I realised it was probably mains hum. I read 8 readings over a complete mains cycle, 50Hz in my case, then averaged. Lo and behold accurate readings with no mains hum. It is absolutely imperative that you sync with the mains cycle otherwise you will get a slowly increasing and decreasing reading i.e. you will be getting mains hum but at a much lower frequency as the points that you are reading precess around the mains cycle.

I was using Z80 assembler at the time and padded my read cycles with delay code so that all 8 readings started and stopped at the correct place. If the A/D cannot take 8 readings in 20ms (50Hz) or 16.66666ms (60Hz) then make sure that you take readings at successive points on the mains cycle i.e. 0Deg, 360+45Deg, 360+360+90deg, 360+360+360+135deg... etc. Take 8 ( or do I mean 9!! ) cycles to read your 8 readings.
I hope this makes sense to you.
 
Many, many years ago when I was trying to read from a Temp sensor which put out a current signal ( voltage drop over long wires not a problem ) I experienced this problem. It was my first attempt at using an A/D. The read temperature was all over the place. Then I realised it was probably mains hum. I read 8 readings over a complete mains cycle, 50Hz in my case, then averaged. Lo and behold accurate readings with no mains hum. It is absolutely imperative that you sync with the mains cycle otherwise you will get a slowly increasing and decreasing reading i.e. you will be getting mains hum but at a much lower frequency as the points that you are reading precess around the mains cycle.

I was using Z80 assembler at the time and padded my read cycles with delay code so that all 8 readings started and stopped at the correct place. If the A/D cannot take 8 readings in 20ms (50Hz) or 16.66666ms (60Hz) then make sure that you take readings at successive points on the mains cycle i.e. 0Deg, 360+45Deg, 360+360+90deg, 360+360+360+135deg... etc. Take 8 ( or do I mean 9!! ) cycles to read your 8 readings.
I hope this makes sense to you.

The reading and averaging technique you mentioned makes great sense. It seems that powering everything from a laptop not connected to mains should eliminate the possibility of that being the issue though right? Also, for this application, ~17ms per reading would probably be far too long. With the 35 readings being taken per loop I'd have a delay of ~581ms. Far too long for a visually responsive system. My display would effectively be 1.72hz!

That does seem like a really useful technique for an application that's not so time critical though.
 
Each time you take a reading add it to an array, throwing away the oldest reading. Divide the array by the number of readings each time you take a reading. This way you are updating your value each time you take a reading. Don't do any averaging with the library that you are using.
Bye the way I would not be surprised to see mains hum even if you are using a battery as a power source. 50Hz of 60Hz mains hum is all around us, any piece of wire or circuit can pick it up from the surroundings.
 
Good point. Though I do wonder what would make a Teensy more sensitive to "mains hum" than an Arduino UNO.

Depends on a number of issues: Sensitivity of ADC is one… by default, even if you set the resolution of the Teensy to the same as the AVR, your V/LSB is going to be ⅔ that of the UNO. That's because the UNO resolves to a max of 5V and the Teensy to a max. of 3.3V. Once you start using higher resolutions, the differential ADC inputs in the Teensy should be used. The Teensy ADC inputs may only be single-ended but adding a op-amp makes great buffer but it can also level shift all signals into the positive (i.e. Teensy-suitable) voltage domain. Differential ADC inputs can zero out a lot of the ambient noise.

Another consideration is circuit layout, power supply, and decoupling. Some circuit layouts, wires, etc. do a great job of picking up hum by virtue of their layout looking like an antenna. See the Henry Ott publications on this subject, he's researched this stuff a lot and has some practical tips. You will likely find that as you transition from a breadboard (with lots of wires) to a more controlled PCB layout that your noise issues will generally abate a good deal.

I strongly recommend dedicated external power supplies both for the Teensy and any high-bit external ADCs or Op-Amps. I use voltage regulators with high PSSRRs to keep the nasties out, especially important if your power source is a USB-bus or a switch-mode power supply.

De-coupling capacitors and the proper layout to maximize their performance can also make a big difference. Basically, a de-coupling capacitor serves as a temporary power source whenever the chip is cycling, so the caps need to be close to the VDD and VSS pins to minimize impedance. Every IC on my board gets a de-coupling capacitor for every power pin. Overkill? Perhaps, but 0,1uF ceramic capacitors (even nice ones) are simply too inexpensive to take the risk.
 
Last edited:
Some more thoughts on dealing with hummmm....

If you take two readings 180deg apart on the mains cycle and average them, this should remove any mains noise. i.e. take a reading wait 1/2 mains cycle , take another reading.

As an alternative, I believe that both the A/Ds on Teensy can do a conversion at the same time. Use one for your data and the other one to read a mains noisy input. The level of noise on the noisy input will tell you where you are in the mains cycle and how much to add/subtract from your data signal to take out mains hum. Obviously this latter method will require some experiment to determine the levels to be added/subtracted.
 
Well the work-around is working flawlessly and I can continue to make progress on my project. Thank you everyone for your advice and suggestions, I'll definitely make use of them on future projects for years to come.

BriComp: Your suggestions for dealing with "mains hum" are great. I never even considered that you could use techniques in code rather than physical components for this.

Constantin: Great advice. I'm quickly gaining an appreciation for noise reduction techniques. Your suggestions also turned me onto the "ADC library" which looks like a great resource. Written by Pedvide, who's was helping my earlier too. Thanks Pedvide for the help and the great looking library!
 
Status
Not open for further replies.
Back
Top