Lab 6 2010


Barebones MP3 Player

 

Assignment

Work your way through Parts A through D (or E, which is optional).

 

In The Report

Hrm, not much of a report this Lab. Playing a song is sufficient. The 2 deliverables are due one week after your lab session.

 

Part A. Build Your Own Audio Jack

Your first task is to build an audio jack so you can connect headphones or speakers to your player. You'll need 3 components: a red audio jack breakout board, a 3.5mm audio jack and a 5-pin row of the break-away header (just break away the right length from the longer row). This type of jack is called 'TRS' for Tip, Ring and Sleeve.

Go to the cabinets and get your parts. Attach the jack to the top of the board (so you can read the pin labels) and the pins to the bottom (so you can use it in your breadboard). Now head to the soldering iron!

 

When you return, look carefully at the datasheet for the audio jack; in particular, the "schematic" detail and "pcb layout" figure. The "schematic" detail is a graphic representation of the jack. It shows pins 1, 2 and 5, which represent ground, ring and tip, respectively. Imagine inserting an audio plug into the left-hand side of the graphic (maybe even hold a plug over the image onscreen); pin 2 would connect to what looks like a ring on your audio plug and pin 5 would connect to the tip.

 

The "pcb layout" figure shows where on the audio jack these pins layout. Note that the figure represents the jack as viewed from above (that is, with the pins facing away from you).

 

Trace the leads for pins 1 and 5 on the red board in your hand. Do you see something wrong with the board's pin labels compared to the datasheet? The datasheet is correct! Check this before connecting the jack to the decoder, so you know which pins on the audio jack breakout board to connect to left and right channels on the decoder.

 

Part B. Connect And Test Your Decoder

Your second task is to wire up and test your mp3 decoder. We're using a breakout board for the VS1033D, which is based on VLSI's VS1033D decoder chip. You can check out the datasheet here.

1. Install David's Mp3 library in the Arduino's "libraries" folder.

 

2. Wire up the decoder and your audio jack to your breadboard. It's fine if your microSD card is already connected to the Teensy. Just leave it connected and add the new components into the circuit. Remember how in Lab 5 the Graphical LCD and microSD card shared the SPI bus? Well, the audio decoder is about to join them! Connect your new parts like this:

 

Decoder  Connect
Teensy (Arduino)
CS   --> Pin 0
SCLK   --> Pin 1 (SCLK)
SI   --> Pin 2 (MOSI)
SO   --> Pin 3 (MISO)
VCC   --> VCC
GND   --> GND
BSYNC   --> Pin 18 (DCS)
DREQ   --> Pin 19
RESET   --> Pin 20

 

Here you should connect left and right to the correct audio jack pins, not the pins as they're labeled.

 

Decoder  Connect
Audio Jack               
LEFT   --> TIP
GBUF   --> GND
RIGHT   --> RNG

 

3. Run the test program in Examples->MP3->SineTest. If your encoder and jack are connected right, you should hear a tone that lasts for 1 second, then is silent for 1 second, in a repeating pattern.

 

If you're not hearing anything, and you're sure your wiring is correct, try increasing the default volume (described next). Different headphones have different signal-strength sensitivities, so audio that's comfortable on one set may be too quiet to hear on another.

 

 

Now open a serial terminal, press the Teensy's reset button, and check the output. The program should report the following:

 

Wrote 0820 to address 0x2

Wrote 9000 to address 0x3

Wrote 1100 to address 0xB 

 

These are the decoder's operating settings, and the register addresses to write them into. The first setting is the mode. A value of 0x0800 puts the decoder into normal (or so-called 'new') mode. This is the (default) value to use most of the time. We're using 0x0820 here to allow us to run tests (like the sine test).

 

The second setting is the decoder's clock multiplier. There are 2 recommended values for this, so we just chose 1 of them.

 

The third setting is the volume. This works inverse to what you would think: 0 is full volume, while 0xFEFE is nearly silent. The left (most-significant) byte (0x4F) is the value for the left channel, and the right (least-significant) byte (also 0x4F) is for the right channel. They don't have to be the same.

 

Edit the following line in the SineTest code to change the DEFAULT_VOL to 0x1144 (or something similar):

 

void setup() {

...

write_sci(SCI_VOL, DEFAULT_VOL);

...

}

 

If that worked, you now know how to change other settings (which are listed on page 35 of the datasheet), such as left-right channel phase (for an 'expanded stereo' sound, described in section 8.7.1), bass enhancement (described in section 8.7.3),  and even playback speed (for fast-forwarding, described in section 9.10). Neat!

 

Part C. Play Some Music!

Once the sine test is working, your third task is to jam! Er, to play a file from the microSD card. Think of it like this: in Lab 5, we read a block of bytes from a file, then streamed them to the serial terminal or the Graphical LCD. The read() function automatically advanced the read/write pointer for us, so we could loop over these 2 steps until there were no more bytes to be read. Well, we're doing the same thing now, only we're streaming the block of bytes to the decoder instead of the terminal or the LCD. That's it!

 

You should have a file titled song.mp3 on your microSD card already. Run the test program in Examples->MP3->Song. If all goes well, you should be able to share audio bliss with your labmates, friends and family. Congratulations!

 

Tell a member of the teaching team what your song is (or better yet, play it for us). If you don't know the name, just decipher some of the lyrics.

 

Now look at the example code a bit: specifically the play_dir() and loop() functions. Note how it's not only playing song.mp3, but any mp3 or wav it finds in the root directory.

 

Also note that in this example's setup(), we're using the Mp3 library's volume() function. This function re-inverts the decoder's volume setting back to what seems more natural: 0 is nearly silent, while 254 (which equals 0xFE) is full volume.

 

In your own players, you might prefer to store the current volume setting in your EEPROM. Then in your initialization routine, you can fetch that value and use it in the volume() function. Neat!

 

To add other audio files to your microSD card, you can use the Lab's USB card reader, which usually resides in the center beige storage cabinet. The card should auto-mount on your computer, so you can copy over files and check the root directory and make sure the new files are, in fact, there (along with song.mp3 and any files you used and created during Lab 5). When you're done, just re-insert the card into your adapter, the adapter into your player, and return the reader to its home in the cabinet.

 

But wait, there's more...

 

Part D. Pause to Learn About Interrupts

What if you want to play or stop playing a song on command?

 

The Teensyduino has 4 pins with external interrupts built in, on pins 5, 6, 7 and 8 (which correspond with INT0, INT1, INT2 and INT3, respectively). You can use them by using the attachInterrupt() function, which is part of the extended Arduino language.

 

Try the sample code from the attachInterrupt reference page with a button circuit that is tied high with a 10kOhm resistor and that gets pulled to ground when the button is depressed.

 

In general (as in the sample code), when you set or change a variable within an interrupt service routine (ISR), you should declare that variable as volatile, to tell the compiler to load its value from RAM.

 

Draw us a quick sketch of what your circuit looks like.

 

What happens when you press the button? What happens when you press the button 15 times in a row?

 

To debounce the button in software, you can create a "bouncer" object that waits a bit before reading the button: http://www.arduino.cc/playground/Code/Bounce. What are the pros and cons of using this method?

 

To couple interrupts and debouncing, you can modify code at: Arduino Forum on Debouncing & Interrupts

 

Now, take what you learned to make an interrupt driven pause function for your Barebones MP3 player!

 

Part E. Input Knob (Optional)

What if you want to change the volume? You can try out the following code:

 

/*

 * Encoder_test

 * Based on code by Paul Badger

 * ----------------------------

 * WGJ 6MAY10: Updated pins, serial speed for Teensyduino

 *

 * Read a rotary encoder with interrupts

 * Encoder hooked up with common to GROUND,

 * encoder0PinA to pin 6, encoder0PinB to pin 7

 * it doesn't matter which encoder pin you use for A or B

 *

 * Uses Arduino pullups on A & B channel outputs

 * turning on the pullups saves having to hook up resistors

 * to the A & B channel outputs

 */

 

#define encoder0PinA  6

#define encoder0PinB  7

 

volatile unsigned int encoder0Pos = 0;

 

void setup() {

  pinMode(encoder0PinA, INPUT);

  digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor

  pinMode(encoder0PinB, INPUT);

  digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor

 

  attachInterrupt(0, doEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2

  Serial.begin (115200);

  Serial.println("start");

}

 

void loop() {

  /* Do some stuff here - the joy of interrupts is that they

   * take care of themselves

   */

}

 

void doEncoder() {

  /* If pinA and pinB are both high or both low, it is spinning

   * forward. If they're different, it's going backward.

   */

  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {

    encoder0Pos++;

  } else {

    encoder0Pos--;

  }

  Serial.println (encoder0Pos, DEC);

}

http://arduino.cc/en/Reference/Volatile