Arduino and MSGEQ7 based equalizer pedal

Today’s project consists, as the title says, in the creation of an arduino/MSGEQ7 based pedal to be used with your guitar/bass/whatever. I’m going to show you how to use the MSGEQ7 (a 7 bands equalizer), how to display the result on a graphical LCD and, icing on the cake, how to make your own arduino shield.

Step 1: MSGEQ7.

Let’s dive deep into the subject: I’m going to show you how this nifty lil’chip works. First: where to find it. You can grab it at Sparkfun of on eBay. It’s pretty common.

Once you got it, just search for the datasheet and check the pinout:

Screen Shot 2013-02-24 at 6.06.08 PM

But especially the wiring diagram:

Screen Shot 2013-02-24 at 6.07.40 PM

This might sound a bit scary, but I found an easier to understand schematic here:

schem1-450x600

I wired this schematic on a breadboard, here’s what it looks like:

IMG_2585

The most observant of you might remark that I used 3 100pf condos to make a 33pf one, and two 100kohms resistor to make a 200k one. I mays have thousands of resistors, I don’t even have a 200k…

Now, the code…

Step 2: software

We have 3 pins to use:

  • STROBE, connected to Digital 2 pin on the arduino,
  • RESET, connected to Digital 3,
  • OUT, connected to Analog 0.

You can use the pins you want, the MSGEQ7 doesn’t need any interrupt, I2C or SPI. Each pin has a specific use, as seen on this chronogram I found in the datasheet:

Screen Shot 2013-02-24 at 9.28.00 PM

What this chronogram tells us:

  1. the chip spits out values for each band on the output pin.  There are 7 of them, hence the “7” of “MSGEQ7″.
  2. to do so, we must reset the chip before every reading by switching the RESET pin to HIGH and then LOW.
  3. then, switch the STROBE pin to LOW
  4. wait 36 microseconds for the chip to put the value on OUT
  5. switch STROBE to HIGH
  6. continue to step 3.

In terms of Arduino, here’s what it looks like:

const int ANALOG = 0;
const int STROBE = 4;
const int RESET = 5;
int outputValues[7];

void setup(void) {
  //setup MSGEQ7
  pinMode(ANALOG, INPUT);
  pinMode(STROBE, OUTPUT);
  pinMode(RESET, OUTPUT);

  analogReference(DEFAULT);

  digitalWrite(RESET, LOW);
  digitalWrite(STROBE, HIGH);

}

void loop(void) {
  //reset chip
  digitalWrite(RESET, HIGH);
  digitalWrite(RESET, LOW);

  for (int i = 0; i < 7; i++) {
    digitalWrite(STROBE, LOW);
    delayMicroseconds(30);
    outputValues[i] = analogRead(ANALOG);
    digitalWrite(STROBE, HIGH);
  }
}

Ok, fair enough, but how do we know that it works? That’s simple: add a Serial.begin(9600) in the setup and some Serial.print within the loop to display values on the serial monitor. Then you’ll certainly notice that the MSGEQ7 is really a cool chip: give it some sound, it will do the rest. I tried with a high output level bass guitar and the output from my iMac, it worked fine with both. But shall we not display the values elseway?

Step 3: LCD

LCD screens to be used with arduinos are very common. You can find a whole lot of them on Sparkfun for instance…but if you want something cool and cheap, you must dig deeper.

Little aside.

I’d like to thanks from the bottom of my heart our chinese friends, without whom this would have cost a leg, an arm and maybe a kidney. Thanks to all the chinese people that sell incredible stuff at stupefying prices on eBay, all of that with no shipping charges. I love you guys, sincerely.

Ok. All of this to says that I found this gem on eBay:

IMG_2618

Specs: 128*64 blue pixels, backlight, about 9$, where adafruit or sparkfun would charge you almose 35$ for an equivalent model! And it has dual serial/parallel mode! Parallel mode = at least 15 pins needed (and thus an Arduino Mega), serial = 8 pins!

For an arduino uno or equivalent, here’s the wiring:

  • pin 10 (SS) to RS
  • pin 11 (MOSI) to R/W
  • pin 12 (MISO) to E
  • +5V to VDD and BLA (BLA is backlight’s anode)
  • GND to VSS, PSB (PSB to LOW = serial mode) et BLK (backlight’s cathode).

Simple, uh? No, here’s the time where code part gets a bit more complicated. To display something on that LCD display, you’ll need a library, available here: http://code.google.com/p/u8glib/ . Next tip: for this LCD, the constructor to use is  “U8GLIB_ST7920_128X64 u8g(12, 11, 10, U8G_PIN_NONE);”. For all the rest, ie how to draw on the screen, take a look at the library’s wiki. Here’s the code of the equalizer:

#include "U8glib.h"

U8GLIB_ST7920_128X64 u8g(12, 11, 10, U8G_PIN_NONE);

const int ANALOG = 0;
const int STROBE = 4;
const int RESET = 5;
const int outputValues[7];

void drawMediumBars(void) {
  for (int i = 0; i < 7; i++) {
    u8g.drawBox(5+18*i, 64-(outputValues[i]/16), 10, outputValues[i]/16);
  }
}

void setup(void) {
  //setup MSGEQ7
  pinMode(ANALOG, INPUT);
  pinMode(STROBE, OUTPUT);
  pinMode(RESET, OUTPUT);
  analogReference(DEFAULT);
  digitalWrite(RESET, LOW);
  digitalWrite(STROBE, HIGH);
}

void loop(void) {
  u8g.firstPage();  
  do {
    //reset chip
    digitalWrite(RESET, HIGH);
    digitalWrite(RESET, LOW);

    for (int i = 0; i < 7; i++) {
      digitalWrite(STROBE, LOW);
      delayMicroseconds(30); // to allow the output to settle
      outputValues[i] = analogRead(ANALOG);
      digitalWrite(STROBE, HIGH);
    }

    //draw values
    drawMediumBars();
  } while(u8g.nextPage());
}

With this you should display nice bars on the screen, something like this:

IMG_2597

Nice! But what if we could change the design of the equalizer?

Step 4: buttons and interrupts

What the heck is an interrupt? It’s a simple piece of code that’s attached to a hardware event, like a pins switching from HIGH to LOW for instance. When the event is triggered, the code is executed. The aim of what follows is to modify the routine that draws the equalizer using an interrupt.

Here’s the code with the modifications:

#include “U8glib.h”

U8GLIB_ST7920_128X64 u8g(12, 11, 10, U8G_PIN_NONE);

const int ANALOG = 0;
const int STROBE = 4;
const int RESET = 5;
int outputValues[7];

const int BT1 = 0;
const int DEBOUNCE_DELAY = 200;

uint8_t mode = 0;
uint8_t nModes = 3;

void drawJointFatBars(void) {
  for (int i = 0; i < 7; i++) {
    u8g.drawBox(1+18*i, 64-(outputValues[i]/16), 18, outputValues[i]/16);
  }
}

void drawMediumBars(void) {
  for (int i = 0; i < 7; i++) {
    u8g.drawBox(5+18*i, 64-(outputValues[i]/16), 10, outputValues[i]/16);
  }
}

void drawTopLine(void) {
  for (int i = 0; i < 6; i++) {
    u8g.drawLine(10+18*i, 64-(outputValues[i]/16), 10+18*(i+1), 64-(outputValues[i+1]/16));
  }
}

void setup(void) {
  //setup MSGEQ7
  pinMode(ANALOG, INPUT);
  pinMode(STROBE, OUTPUT);
  pinMode(RESET, OUTPUT);
  analogReference(DEFAULT);
  digitalWrite(RESET, LOW);
  digitalWrite(STROBE, HIGH);

  //change mode button
  attachInterrupt(BT1, button1, FALLING);
}

void loop(void) {
  u8g.firstPage();  
  do {
    //reset chip
    digitalWrite(RESET, HIGH);
    digitalWrite(RESET, LOW);

    for (int i = 0; i < 7; i++) {
      digitalWrite(STROBE, LOW);
      delayMicroseconds(30); // to allow the output to settle
      outputValues[i] = analogRead(ANALOG);
      digitalWrite(STROBE, HIGH);
    }

    //draw values
    if (mode == 0) drawJointFatBars();
    else if (mode == 1) drawMediumBars();
    else if (mode == 2) drawTopLine();

  } while(u8g.nextPage());
}

void button1() {
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > DEBOUNCE_DELAY) {
    last_interrupt_time = interrupt_time;

    //interrupt code
    if (mode == (nModes-1)) mode = 0;
    else mode++;

  }
}

The “attachInterrupt” links a function (here named “button1″) to an event (FALLING = from HIGH to LOW) on a given interrupt. Here, interrupt 0, corresponding to DIGITAL pin 2. Check arduino reference for more infos.

About the “button1″ function: I use a variable to measure time between two calls to the function. Why? Because pushbuttons ain’t perfect and can trigger twice where ppushed once, because of their internal mechanic. Here, the delay between two calls must be greater than 200ms.

To wire the interrupt, here’s the schematic:

IMG_2619

Simple, no?

You should end with something like this:

IMG_2599

Step 5: transforme a prototype into a shield

What a satisfaction to transform a project that works into a final product! And our prototype deserves to be converted into a nice shield. You can find blank shields almost anywhere you can find arduinos.

Just one advice: position your components and solder once you’re 100% sure of what you did. Here’s how mine looks:

IMG_2603

IMG_2607

IMG_2606

Step 6: casing.

I wanted a small, transparent and tough enclosure for my project. So I choose to use an otterbox I grabbed a while ago in a PX. These boxes are awesome. You can find some at adafruit.

The toughest part was to cut a tidy rectangle in it. Here’s how I proceed (this works for wood, plastic and metal):

  • trace the contours
  • make a rough cutting inside of this contour. Any mean will do: dremel, metal saw…the aim is to approach roughly the final contour.
  • finish the edges with a flat file.

Using this method you’ll achieve very accurate cuttings into almost any material:

IMG_2621

Here’s my box:

IMG_2613

IMG_2612

I used hot glue to stick the arduino to the box:

IMG_2620

A peice of velcro and there you go:

IMG_2617

8 comments

  1. Good job buddy! Just one thing I don’t think I got properly… This is a 7 band audio SPECTRUM ANALYZER right? Not an equalizer… I mean you have no control over the amplitude of each band… Is that correct?
    BTW I love the Chinese for their immense contributions to our hobbies!

    1. True! The datasheet says “equalizer”, but the MSGEQ7 equalizes nothing, it displays a spectrum over 7 bands. To control the amplitude of the signal you can use software filtering, the MSGEQ7 does nothing about this ;)

    1. Owwww, nice! That’s bashit crazy, I love it! But I sincerely hope that those watching you aren’t epileptic :D
      I also thought of giant EQ made of RGB LED stripes, that would kick ass!

Leave a Reply