MSGEQ7-Based DIY Audio Spectrum Analyzer: Construction

Here's a step-by-step guide to constructing a simple 14-band (2 x 7) audio spectrum analyzer using two MSGEQ7s and a chipKIT or Arduino microcontroller development platform.

I recently used a pair of MSGEQ7 seven-band audio spectrum analyzer chips to construct a rather cool display. In this first incarnation, we end up driving 14 LEDs -- seven each for the left and right audio channels.

To set the scene before we leap into the fray, let's take a look at this short video to get an idea of where we will end up.

Since I think this will be of interest to beginners, as well as practicing engineers, I will go slowly and take the time to explain some basic concepts here and there. In these cases, I'll kindly ask anyone who already knows this stuff to bear with me.

Let's start with the fact that my music source is my iPad. Since I want to keep things as simple as possible, I intend to drive everything from the iPad's headphone socket. The problem is that plugging anything into the headphone socket disables the internal speakers. Similarly, if you are using the iPad to drive a Bluetooth boom box, for example, plugging something into the iPad's headphone socket will terminate the Bluetooth audio feed. Thus, my first step was to purchase a stereo splitter cable on Amazon. This allows me to use the output from my headphone socket to drive both an external speaker system and my spectrum analyzer.

Choosing a microcontroller
We can construct this audio spectrum analyzer project using pretty much any microcontroller that supports the required set of features. Assuming we wish to display the left and right audio channels separately, we need at least two analog inputs, two regular digital outputs, and 14 pulse-width modulated (PWM) outputs. You could get by with just one analog input and seven PWM outputs if you merged the two channels (this will be discussed later).

If you wish, you could process the audio data using an eight-bit Arduino Mega microcontroller development platform with 256 Kbytes of Flash and 8 Kbytes of SRAM running at 16 MHz. You could also use an Arduino Uno (which supports only six PWM outputs) if you would be happy combining the left and right channels and losing one of the frequency bands. I decided to use a chipKIT MAX32 platform to process the audio data stream. This little beauty boasts a 32-bit processor running at 80 MHz, along with 512 Kbytes of Flash and 128 Kbytes of RAM.

The chipKIT MAX32 has the same physical footprint and the same input/output (I/O) pins as the Arduino Mega. Also, the integrated development environments (IDEs) for these two platforms are almost identical, which makes our lives a lot easier. The main thing to note is that the chipKIT MAX32 employs a 3.3V supply, while an Arduino Mega uses a 5V supply. This will affect some of the component values, but this will be noted at the appropriate points in the following discussions.

Introducing the MSGEQ7
The MSGEQ7 is a seven-band graphic equalizer chip you can buy for $4.95 from SparkFun. It will work with a 5V supply (like the Arduino Mega) or a 3.3V supply (like the chipKIT MAX32).

Inside the MSGEQ7 are seven band-pass filters tuned to 63 Hz, 160 Hz, 400 Hz, 1,000 Hz, 2,500 Hz, 6,250 Hz, and 16,000 Hz. Each filter has an associated peak detector, as illustrated below. The clever thing is that the outputs from the seven peak detectors are multiplexed together, which explains how everything fits into a teenie-weenie eight-pin package.

Everything is controlled by two digital signals called RESET and STROBE. As shown in the waveform diagram below, a positive-going pulse on the RESET signal kicks everything off. Though the data sheet doesn't say so, my impression is that this pulse takes a copy of the current peak detector outputs and stores (latches) the values. We then apply seven negative-going pulses to the STROBE input. Every time the STROBE input goes low, we can read the value of one of the bands on the DATA_OUT signal, starting with 63 Hz and working out to 16,000 Hz.

The DATA_OUT is an analog value whose magnitude reflects the value from the corresponding peak detector. This value can be read using one of your microcontroller's analog inputs.

Actually, I recreated the timing diagram shown above from the original datasheet. If you read the comments at the bottom of this column, you will see a question by David Ashton. David points out that, as the minimum strobe pulse width of 18µs is less than the minimum output settling time of 36µs, this implies that you can read the data even after the STROBE signal has returned to its HIGH state. Based on this, David notes that you could actually read the data during the "purple times" in the above diagram.

If this were to prove to be correct, then -- based on the timing specifications in the datasheet -- a better representation of the timing relationships and waveforms would be as illustrated below.

Since it's not possible to make a definitive decision based on the existing datasheet, I talked to John Ambrose at Mixed Signal Integration -- the company that makes the MSGEQ7 (along with many other interesting products). John confirmed that applying a positive-going pulse to the RESET signal does indeed latch the current frequency values.

John went on to explain that the DATA_OUT signal is clamped to 0V when the STROBE signal is HIGH. This has several implications, including the fact that you cannot read the data when the STROBE signal is in its HIGH state. Also, this means that the minimum strobe pulse width ("ts") really isn't 18µs; instead, it's equal to the output settling time ("to") plus however long it takes for you to actually read the sample (let's call this "tsr" for "sample read time"). Based on this, the definitive timing diagram is actually as shown below.

With all that behind us, the following illustration reflects the additional components we need to make things work. The resistors are all 1/4 watt, and the capacitors are 50V ceramics. (These components are of the lead-through-hole variety.) In the original data sheet, the value of C2 is shown at 0.01µF, but I ran across an application note somewhere that said it was better to use 0.1µF, so that's what I did.

I decided to use two MSGEQ7s -- one for each audio channel (left and right). If you wish to use a single device for both channels, you can employ the circuit variation that's shown at the bottom of the above illustration.

@mithrandir: I'll see if I can get just the front end filtering running on my Pioneer kit.

Is that a PSoC 4 Pioneer kit, or are you talking about something else?

Alas I don't seem to have many LED's with me right now

I buy bags of them at a time because I seem to use them in so many things.

Weekend project, here I come :)

Have a great time, email me to tell me how you get on (max.maxfield@ubm.com and max@clivemaxfield.com), keep notes and take pictures -- maybe you could even write your experiments up as a column for me to post here on EETimes

My interest is piqued now. I'll see if I can get just the front end filtering running on my Pioneer kit. Alas I don't seem to have many LED's with me right now so time hunt down, scrounge or steal a few!

@mithrandir: I'm curious if you could actually push the MSGEQ7 functionality into the Arduino itself.

I'm sure you could achieve somethging like thsi in the Arduino -- I've seen software DSP versions of spectrum analyzers running on Arduinos. My problem is that this is going to be part of my BADASS Display, so I'll be using my Arduino to drive the display itself.

I'm actually running this on a chipKIT MAX32, which is more than capable of running sophisticated DSP algorithms in software -- that's the longer term plan -- it was just that when I was introduced to these MSGEQ7 chips I thought I'd give them a whirl.

@David: I notice the minimum strobe pulse width is less (18us) than the settling time (36us) - which implies you can read the data even if the strobe has gone back high? (ie you could actually read data during the purple times in your diagram?)

As you say, the minimum strobe pulse of 18us is less rthan the outpout settling time of 36us, so I too assume that you can read the data even afgter the strobe has gone back high (although in my software I delay 40us after the strobe goes low before doing the read).

However, you can't read data during the purple times in my diagram because the minimum tss (strobe-to-strobe delay) is 72us.

Hmmm -- looking at my original diagram (which I re-drew from the one in the data sheet), I see what you mean -- that original diagram implies that the data goes invalid on the rising edge of the strobe.

@David: ...True VU displays - and the LM3915 - have a logarithmic response, whereas MCU ADCs are linear. What does the MSCEQ7 do...

The data sheet doesn't say -- the vertical frequency response axis is simply annotated 0 at the bottomn and 20 at the top.

Actually, thsi is something I can test using my frequency generator -- I can put in a 0.5V peak-to-peak signal, 1.0V pk-pk, 1.5V pk-pk, and 2.0V pk-pk and see what I get -- I'll do that this coming weekend and report back.

I'm curious if you could actually push the MSGEQ7 functionality into the arduino itself. The max frequency is 16KHz, so you could probably get away with a 3~4x oversampling ADC and pushing it through digital filters running in firmware.

There doesn't seem to be a lot of information on the filter charactersitcs on the datasheet so I'm guessing a 2 or 3-tap IIR should do it which will amount to somewhere around 30 cycles(if there's a hardware multiply, sadly not at all familiar with Arduino cores) for each bandpass. That will amount to 8*30 which is 240 cycles roughly for all the 8 parallel bandpasses to run. Plus some latency for the ADC interrupt to run and grab, but that happens only once every cycle so lets put another 20 cycles for that. Since the actual processor is running at 80MHz, you should still be able to have something around 1200 cycles(assuming a 4x oversampled ADC so it gets a new sample at 64ksps) to work with which should leave plenty of processing room to spare for the PWM's to dim according to the filtered output.

2 channels could may be fit in too but I'm presuming too much at this stage :)

Max, another query - the MSGEQ7 timings in your article are all given as "minimum". I assume that as long as you stick to these minimum timings you can extend them a bit (for example if your MCU is busy doing something else, or if it takes a long time to do the ADC conversion) without problems? And as long as you read the ouput at least to (settling time) after the strobe goes low (and before the next strobe pulse) you are ok - I notice the minimum strobe pulse width is less (18us) than the settling time (36us) - which implies you can read the data even if the strobe has gone back high? (ie you could actually read data during the purple times in your diagram?)

I'll go along with that Max, awesome diagrams. I'm still woefully inadequate at Visio.

One thing that occurs to me here, especially after watching the video of your LEDs flickering away. True VU displays - and the LM3915 - have a logarithmic response, whereas MCU ADCs are linear. What does the MSCEQ7 do - the datasheet says the DC output for each band is just an amplified peak detected amplitude of the input - but is it linear or logarithmic? As it does not say, I'm assuming linear, and the way your LEDs are flashing I think goes along with this.

If it is linear, you could do a log conversion in software, either mathematically or via a look-up table. I seem to remember this was touched on in a previous blog - am I right?

Just call me the "King of Visio" because all of the drawings in this blog -- including the block diagrams, schematics, and especially the ones of the breadboards -- were lovingly created by yours truly.