Teensy 2.0 With VS1053

drMams

Member
Hi there. (btw sorry for my english)

Trust me when I said that I've tried alot of libraries, tweaks and readings before posting here. I really like to find my problem on my own, but I think I've exhausted all forum/git/demo/etc that exists.

I am trying to play mp3 files from an SD card with a VS1003/VS1053 board (see attached picture of the exact board)

After alot of trial and error, the closest I've come is: No error, all Serial output trace look ok, weird wub coming out of the speaker that seems to follow the spi transfer of every mp3 block send to buffer.

My last try was with the adafruit_vs1053 revised by Paul to add teensy 2 and 3 support.
(https://github.com/PaulStoffregen/Adafruit_VS1053_Library)

And ued the play file example. (Modified to my need)

I've defined the spi pins (hardware)
#define CLK 1 // SPI Clock, shared with SD card
#define MISO 3 // Input data, from VS1053/SD card
#define MOSI 2 // Output data, to VS1053/SD card

And define all the chip select/reset/dreq as such
#define RESET 9 // VS1053 reset pin (output)
#define CS 10 // VS1053 chip select pin (output)
#define DCS 8 // VS1053 Data/command select pin (output)
#define CARDCS 4 // Card chip select pin
#define DREQ 6 // VS1053 Data request, ideally an Interrupt pin
(For DREQ, I have try 5 also since it's suppose to be Interrupt 0 (and 6 = int1)

I have also try to change: #define VS1053_FILEPLAYER_PIN_INT 5
from 5 to 6 and vice versa. Trying to fit DREQ

I have commented the timer line and uncommented the dreq int
// musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT); // timer int
musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); // DREQ int

Tried with only playFullFile and then only startPlayingFile

All those tests basically give me the same behavior: no error, everything fine, but weird noise wub in speaker while buffering/playing

then it stop wubbing as soon as we arrive at

currentTrack.close()

Then nothing else seems to happen. the file.close works, then I suppose it return to the
while (playingMusic) {
feedBuffer();
}

But never go past here.

In resumé, I feel like everything should works but maybe something really obvious is wrong and I need another pair of eyes.

I don't want to clutter the thread with my example code (think the most important bits are there) but if needed I can post one of my latest variant.

Thanks you alot for any small hint/help/encouragement :p
 

Attachments

  • vs1053-mp3-module.jpg
    vs1053-mp3-module.jpg
    200.5 KB · Views: 961
Last edited:
Just to be sure. I have no problem communicating via SPI to the vs1053, I can change and read the mode/status or any addresss.

Also I can read/write file on the SD without any problem (pretty sure the code block with a !Sd.begin somewhere if it can't read the sd)

And there is the dumpReq

Using Hardware SPI
Mode = 0x4890
Stat = 0x840
ClkF = 0x6000
Vol. = 0x2828
 
Last edited:
Sorry i should mention that, from ebay, I though it was the same chip with a different breakboard. I ve attached the datasheets that came with it. thanks very much!
 

Attachments

  • VS1003英文数据手册.pdf
    464.6 KB · Views: 827
  • VS1003.pdf
    419.8 KB · Views: 696
Here's the other thread where this library was mentioned. So far, there's no verification if my changes actually work.

Looking at the Adafruit board and this one, they are clearly NOT the same. Adafruit's has a SD card, but this one does not.

Can you post a photo of what you have actually connected? Are you use the SD adaptor from PJRC? If you want help, you really must post much better detail about what you have actually connected. The complete modified code would be good too.
 
Hi again, you can ask for any info, I just didn't want to scare any one with a 20 page long thread :D

So I made a schema, I hope it would be less chaotic, hope it completes the photos of the circuit.

On one of the photo, I hold the same SD module but "face-front" just to show

The "schema.png" is a simplification. You can assume all the gnd/5v are connected properly

and the top yellow rectangle, is the left side of a teensy 2.0 (pin 0 to 10)

<code>
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>

// define the pins used
#define CLK 1 // SPI Clock, shared with SD card
#define MISO 3 // Input data, from VS1053/SD card
#define MOSI 2 // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins.
// See http://arduino.cc/en/Reference/SPI "Connections"

// These can be any pins:
#define RESET 9 // VS1053 reset pin (output)
#define CS 10 // VS1053 chip select pin (output)
#define DCS 8 // VS1053 Data/command select pin (output)
#define CARDCS 4 // Card chip select pin
#define DREQ 6 // VS1053 Data request, ideally an Interrupt pin

Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(RESET, CS, DCS, DREQ, CARDCS);

void setup() {
Serial.begin(9600);
Serial.println("Adafruit VS1053 Simple Test");

musicPlayer.begin(); // initialise the music player
SD.begin(CARDCS); // initialise the SD card

musicPlayer.dumpRegs();

// Set volume for left, right channels. lower numbers == louder volume!
musicPlayer.setVolume(20,20);

// musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT); // timer int
musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); // DREQ int

Serial.println("Calling playFullFile");
// Play one file, don't return until complete
musicPlayer.playFullFile("track001.mp3");

Serial.println("setup done");
// Play another file in the background, REQUIRES interrupts!
// musicPlayer.startPlayingFile("track002.mp3");
}

void loop() {
// File is playing in the background
if (! musicPlayer.playingMusic)
Serial.println("Done playing music");

delay(1000);
}
</code>
 

Attachments

  • schema.png
    schema.png
    26.6 KB · Views: 663
  • IMG_0001.jpg
    IMG_0001.jpg
    209.9 KB · Views: 556
  • IMG_0002.jpg
    IMG_0002.jpg
    198.7 KB · Views: 673
  • IMG_0003.jpg
    IMG_0003.jpg
    185.2 KB · Views: 589
  • IMG_0004.jpg
    IMG_0004.jpg
    183.7 KB · Views: 695
yes (sorry took me couple minutes to setup the pins)

Initializing SD card...initialization done.
DCIM/
100CANON/
TRACK001.MP3 1766142
TRACK002.MP3 7110656
TRACK003.MP3 9666560
done!

(same circuit used)
 
That's a good sign. :)

I'm afraid I can't help much with these VS1053 boards. On the other thread, Brandonlynne reported Adafruit's library does work with Teensy 2.0, at least with Adafruit's VS1053 module. Maybe this other VS1053 module is different somehow?

I do not have either of those VS1053 modules, so there's not much more I can do to help.
 
Thanks alot anyways. :D If it wasn't that expensive to ship from my island i would send you a copy of the board Im using. I will continue to try to figure it out.

If I do, are you interested in the info?

Have a nice day!
 
Found a working solution.

Hi,

I bought the same board recently and found a solution to your problem. (I originally came to this page to see if anyone can solve my same problem.)

Basically, I modified a source linked from Sparkfun. I had to modify it because the code is from April 2011 and I am using Arduino 1.0*.

Not sure if it matters in your case, but I used a UNO board where SPI pins (MOSI/MISO/SCK) are defaulted to (PIN 11/12/13).
For simplicity, I didn't change that.
Also, the MP3 board I bought does't have the jumper on LINE in. It looks identical to yours otherwise.
This probably does't make a difference.

For reference, on UNO board, Pin 10 must be set to OUTPUT even if you reassign MOSI/MISO/SCK pins to non-default values. Otherwise, SPI won't work.

One more point regarding this chip/board is that they have 2 chip select pins (CS/DCS).
This means only 1 CS pin should be set to LOW at all times.
The realization of this made me drop another sample code I was using, where mp3 clip is played directly from a small defined array values.
In that particular sample, they are not taking care of the CS pins for other SPI devices (SD/TFT, etc).

Source code is below.
-----------------------
/*
Modified from
//////////////
// http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Dev/Arduino/Shields/MP3_Player_Example_Control.pde
// linked from https://www.sparkfun.com/products/10628
// -> "MP3 Player Control Example"
//
// 4-28-2011
// Spark Fun Electronics 2011
// Nathan Seidle
//////////////

*/

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

char trackName[] = "tomorrow.mp3";
int trackNumber = 1;

char errorMsg[100]; //This is a generic array used for sprintf of error messages

#define TRUE 0
#define FALSE 1

//MP3 Player Shield pin mapping. See the schematic
#define MP3_XCS 9 //Control Chip Select Pin (for accessing SPI Control/Status registers)
#define MP3_XDCS 6 //Data Chip Select / BSYNC Pin
#define MP3_DREQ 8 //Data Request Pin: Player asks for more data
#define MP3_RESET 7 //Reset is active low

#define SD_CS 4 // Chip select line for SD card

//VS10xx SCI Registers
#define SCI_MODE 0x00
#define SCI_STATUS 0x01
#define SCI_BASS 0x02
#define SCI_CLOCKF 0x03
#define SCI_DECODE_TIME 0x04
#define SCI_AUDATA 0x05
#define SCI_WRAM 0x06
#define SCI_WRAMADDR 0x07
#define SCI_HDAT0 0x08
#define SCI_HDAT1 0x09
#define SCI_AIADDR 0x0A
#define SCI_VOL 0x0B
#define SCI_AICTRL0 0x0C
#define SCI_AICTRL1 0x0D
#define SCI_AICTRL2 0x0E
#define SCI_AICTRL3 0x0F

void setup() {
pinMode(MP3_DREQ, INPUT);
pinMode(MP3_XCS, OUTPUT);
pinMode(MP3_XDCS, OUTPUT);
pinMode(MP3_RESET, OUTPUT);

digitalWrite(MP3_XCS, HIGH); //Deselect Control
digitalWrite(MP3_XDCS, HIGH); //Deselect Data
digitalWrite(MP3_RESET, LOW); //Put VS1053 into hardware reset

Serial.begin(9600); //Use serial for debugging
Serial.println("MP3 Testing");

pinMode(10, OUTPUT); //Pin 10 must be set as an output for the SD communication to work.

Serial.print("Initializing SD card...");
if (!SD.begin(SD_CS)) {
Serial.println("failed!");
return;
}
Serial.println("OK!");


//From page 12 of datasheet, max SCI reads are CLKI/7. Input clock is 12.288MHz.
//Internal clock multiplier is 1.0x after power up.
//Therefore, max SPI speed is 1.75MHz. We will use 1MHz to be safe.
SPI.setClockDivider(SPI_CLOCK_DIV16); //Set SPI bus speed to 1MHz (16MHz / 16 = 1MHz)
SPI.transfer(0xFF); //Throw a dummy byte at the bus
//Initialize VS1053 chip
delay(10);
digitalWrite(MP3_RESET, HIGH); //Bring up VS1053
//delay(10); //We don't need this delay because any register changes will check for a high DREQ

//Mp3SetVolume(20, 20); //Set initial volume (20 = -10dB) LOUD
Mp3SetVolume(40, 40); //Set initial volume (20 = -10dB) Manageable
//Mp3SetVolume(80, 80); //Set initial volume (20 = -10dB) More quiet

//Let's check the status of the VS1053
int MP3Mode = Mp3ReadRegister(SCI_MODE);
int MP3Status = Mp3ReadRegister(SCI_STATUS);
int MP3Clock = Mp3ReadRegister(SCI_CLOCKF);

Serial.print("SCI_Mode (0x4800) = 0x");
Serial.println(MP3Mode, HEX);

Serial.print("SCI_Status (0x48) = 0x");
Serial.println(MP3Status, HEX);

int vsVersion = (MP3Status >> 4) & 0x000F; //Mask out only the four version bits
Serial.print("VS Version (VS1053 is 4) = ");
Serial.println(vsVersion, DEC); //The 1053B should respond with 4. VS1001 = 0, VS1011 = 1, VS1002 = 2, VS1003 = 3

Serial.print("SCI_ClockF = 0x");
Serial.println(MP3Clock, HEX);

//Now that we have the VS1053 up and running, increase the internal clock multiplier and up our SPI rate
Mp3WriteRegister(SCI_CLOCKF, 0x60, 0x00); //Set multiplier to 3.0x

//From page 12 of datasheet, max SCI reads are CLKI/7. Input clock is 12.288MHz.
//Internal clock multiplier is now 3x.
//Therefore, max SPI speed is 5MHz. 4MHz will be safe.
SPI.setClockDivider(SPI_CLOCK_DIV4); //Set SPI bus speed to 4MHz (16MHz / 4 = 4MHz)

MP3Clock = Mp3ReadRegister(SCI_CLOCKF);
Serial.print("SCI_ClockF = 0x");
Serial.println(MP3Clock, HEX);

//MP3 IC setup complete

}

void loop(){
playMP3(trackName);

trackNumber++; //When we loop, advance to next track!

if(trackNumber > 1) {
Serial.println("Whoa there cowboy!");
while(1);
}
}

//PlayMP3 pulls 32 byte chunks from the SD card and throws them at the VS1053
//We monitor the DREQ (data request pin). If it goes low then we determine if
//we need new data or not. If yes, pull new from SD card. Then throw the data
//at the VS1053 until it is full.
void playMP3(char* fileName) {
File mp3File;

if ((mp3File = SD.open(fileName)) == NULL) {
Serial.print("File not found");
return;
}
Serial.println("Track open");

uint8_t mp3DataBuffer[32]; //Buffer of 32 bytes. VS1053 can take 32 bytes at a go.
//track.read(mp3DataBuffer, sizeof(mp3DataBuffer)); //Read the first 32 bytes of the song
int need_data = TRUE;
long replenish_time = millis();

Serial.println("Start MP3 decoding");

while(1) {
while(!digitalRead(MP3_DREQ)) {
//DREQ is low while the receive buffer is full
//You can do something else here, the buffer of the MP3 is full and happy.
//Maybe set the volume or test to see how much we can delay before we hear audible glitches

//If the MP3 IC is happy, but we need to read new data from the SD, now is a great time to do so
if(need_data == TRUE) {
if(!mp3File.read(mp3DataBuffer, sizeof(mp3DataBuffer))) { //Try reading 32 new bytes of the song
//Oh no! There is no data left to read!
//Time to exit
break;
}
need_data = FALSE;
}

//Serial.println("."); //Print a character to show we are doing nothing

//This is here to show how much time is spent transferring new bytes to the VS1053 buffer. Relies on replenish_time below.
Serial.print("Time to replenish buffer: ");
Serial.print(millis() - replenish_time, DEC);
Serial.print("ms");

//Test to see just how much we can do before the audio starts to glitch
long start_time = millis();
//delay(150); //Do NOTHING - audible glitches
//delay(135); //Do NOTHING - audible glitches
//delay(120); //Do NOTHING - barely audible glitches
delay(100); //Do NOTHING - sounds fine
Serial.print(" Idle time: ");
Serial.print(millis() - start_time, DEC);
Serial.println("ms");
//Look at that! We can actually do quite a lot without the audio glitching

//Now that we've completely emptied the VS1053 buffer (2048 bytes) let's see how much
//time the VS1053 keeps the DREQ line high, indicating it needs to be fed
replenish_time = millis();
}


if(need_data == TRUE){ //This is here in case we haven't had any free time to load new data
if(!mp3File.read(mp3DataBuffer, sizeof(mp3DataBuffer))) { //Go out to SD card and try reading 32 new bytes of the song
//Oh no! There is no data left to read!
//Time to exit
break;
}
need_data = FALSE;
}

//Once DREQ is released (high) we now feed 32 bytes of data to the VS1053 from our SD read buffer
digitalWrite(MP3_XDCS, LOW); //Select Data
for(int y = 0 ; y < sizeof(mp3DataBuffer) ; y++) {
SPI.transfer(mp3DataBuffer[y]); // Send SPI byte
}

digitalWrite(MP3_XDCS, HIGH); //Deselect Data
need_data = TRUE; //We've just dumped 32 bytes into VS1053 so our SD read buffer is empty. Set flag so we go get more data
}

while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating transfer is complete
digitalWrite(MP3_XDCS, HIGH); //Deselect Data

mp3File.close(); //Close out this track

sprintf(errorMsg, "Track %s done!", fileName);
Serial.println(errorMsg);
}

//Write to VS10xx register
//SCI: Data transfers are always 16bit. When a new SCI operation comes in
//DREQ goes low. We then have to wait for DREQ to go high again.
//XCS should be low for the full duration of operation.
void Mp3WriteRegister(unsigned char addressbyte, unsigned char highbyte, unsigned char lowbyte){
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating IC is available
digitalWrite(MP3_XCS, LOW); //Select control

//SCI consists of instruction byte, address byte, and 16-bit data word.
SPI.transfer(0x02); //Write instruction
SPI.transfer(addressbyte);
SPI.transfer(highbyte);
SPI.transfer(lowbyte);
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating command is complete
digitalWrite(MP3_XCS, HIGH); //Deselect Control
}

//Read the 16-bit value of a VS10xx register
unsigned int Mp3ReadRegister (unsigned char addressbyte){
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating IC is available
digitalWrite(MP3_XCS, LOW); //Select control

//SCI consists of instruction byte, address byte, and 16-bit data word.
SPI.transfer(0x03); //Read instruction
SPI.transfer(addressbyte);

char response1 = SPI.transfer(0xFF); //Read the first byte
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating command is complete
char response2 = SPI.transfer(0xFF); //Read the second byte
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating command is complete

digitalWrite(MP3_XCS, HIGH); //Deselect Control

int resultvalue = response1 << 8;
resultvalue |= response2;
return resultvalue;
}

//Set VS10xx Volume Register
void Mp3SetVolume(unsigned char leftchannel, unsigned char rightchannel){
Mp3WriteRegister(SCI_VOL, leftchannel, rightchannel);
}
 
It is probably starting in MIDI mode. A lot of clone boards have this issue (they skipped a trace and resistor). Bridge pins 33 and 34 together to put it into MP3 mode.

Cheers

Hi,

I bought the same board recently and found a solution to your problem. (I originally came to this page to see if anyone can solve my same problem.)

Basically, I modified a source linked from Sparkfun. I had to modify it because the code is from April 2011 and I am using Arduino 1.0*.

Not sure if it matters in your case, but I used a UNO board where SPI pins (MOSI/MISO/SCK) are defaulted to (PIN 11/12/13).
For simplicity, I didn't change that.
Also, the MP3 board I bought does't have the jumper on LINE in. It looks identical to yours otherwise.
This probably does't make a difference.

For reference, on UNO board, Pin 10 must be set to OUTPUT even if you reassign MOSI/MISO/SCK pins to non-default values. Otherwise, SPI won't work.

One more point regarding this chip/board is that they have 2 chip select pins (CS/DCS).
This means only 1 CS pin should be set to LOW at all times.
The realization of this made me drop another sample code I was using, where mp3 clip is played directly from a small defined array values.
In that particular sample, they are not taking care of the CS pins for other SPI devices (SD/TFT, etc).

Source code is below.
-----------------------
/*
Modified from
//////////////
// http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Dev/Arduino/Shields/MP3_Player_Example_Control.pde
// linked from https://www.sparkfun.com/products/10628
// -> "MP3 Player Control Example"
//
// 4-28-2011
// Spark Fun Electronics 2011
// Nathan Seidle
//////////////

*/

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

char trackName[] = "tomorrow.mp3";
int trackNumber = 1;

char errorMsg[100]; //This is a generic array used for sprintf of error messages

#define TRUE 0
#define FALSE 1

//MP3 Player Shield pin mapping. See the schematic
#define MP3_XCS 9 //Control Chip Select Pin (for accessing SPI Control/Status registers)
#define MP3_XDCS 6 //Data Chip Select / BSYNC Pin
#define MP3_DREQ 8 //Data Request Pin: Player asks for more data
#define MP3_RESET 7 //Reset is active low

#define SD_CS 4 // Chip select line for SD card

//VS10xx SCI Registers
#define SCI_MODE 0x00
#define SCI_STATUS 0x01
#define SCI_BASS 0x02
#define SCI_CLOCKF 0x03
#define SCI_DECODE_TIME 0x04
#define SCI_AUDATA 0x05
#define SCI_WRAM 0x06
#define SCI_WRAMADDR 0x07
#define SCI_HDAT0 0x08
#define SCI_HDAT1 0x09
#define SCI_AIADDR 0x0A
#define SCI_VOL 0x0B
#define SCI_AICTRL0 0x0C
#define SCI_AICTRL1 0x0D
#define SCI_AICTRL2 0x0E
#define SCI_AICTRL3 0x0F

void setup() {
pinMode(MP3_DREQ, INPUT);
pinMode(MP3_XCS, OUTPUT);
pinMode(MP3_XDCS, OUTPUT);
pinMode(MP3_RESET, OUTPUT);

digitalWrite(MP3_XCS, HIGH); //Deselect Control
digitalWrite(MP3_XDCS, HIGH); //Deselect Data
digitalWrite(MP3_RESET, LOW); //Put VS1053 into hardware reset

Serial.begin(9600); //Use serial for debugging
Serial.println("MP3 Testing");

pinMode(10, OUTPUT); //Pin 10 must be set as an output for the SD communication to work.

Serial.print("Initializing SD card...");
if (!SD.begin(SD_CS)) {
Serial.println("failed!");
return;
}
Serial.println("OK!");


//From page 12 of datasheet, max SCI reads are CLKI/7. Input clock is 12.288MHz.
//Internal clock multiplier is 1.0x after power up.
//Therefore, max SPI speed is 1.75MHz. We will use 1MHz to be safe.
SPI.setClockDivider(SPI_CLOCK_DIV16); //Set SPI bus speed to 1MHz (16MHz / 16 = 1MHz)
SPI.transfer(0xFF); //Throw a dummy byte at the bus
//Initialize VS1053 chip
delay(10);
digitalWrite(MP3_RESET, HIGH); //Bring up VS1053
//delay(10); //We don't need this delay because any register changes will check for a high DREQ

//Mp3SetVolume(20, 20); //Set initial volume (20 = -10dB) LOUD
Mp3SetVolume(40, 40); //Set initial volume (20 = -10dB) Manageable
//Mp3SetVolume(80, 80); //Set initial volume (20 = -10dB) More quiet

//Let's check the status of the VS1053
int MP3Mode = Mp3ReadRegister(SCI_MODE);
int MP3Status = Mp3ReadRegister(SCI_STATUS);
int MP3Clock = Mp3ReadRegister(SCI_CLOCKF);

Serial.print("SCI_Mode (0x4800) = 0x");
Serial.println(MP3Mode, HEX);

Serial.print("SCI_Status (0x48) = 0x");
Serial.println(MP3Status, HEX);

int vsVersion = (MP3Status >> 4) & 0x000F; //Mask out only the four version bits
Serial.print("VS Version (VS1053 is 4) = ");
Serial.println(vsVersion, DEC); //The 1053B should respond with 4. VS1001 = 0, VS1011 = 1, VS1002 = 2, VS1003 = 3

Serial.print("SCI_ClockF = 0x");
Serial.println(MP3Clock, HEX);

//Now that we have the VS1053 up and running, increase the internal clock multiplier and up our SPI rate
Mp3WriteRegister(SCI_CLOCKF, 0x60, 0x00); //Set multiplier to 3.0x

//From page 12 of datasheet, max SCI reads are CLKI/7. Input clock is 12.288MHz.
//Internal clock multiplier is now 3x.
//Therefore, max SPI speed is 5MHz. 4MHz will be safe.
SPI.setClockDivider(SPI_CLOCK_DIV4); //Set SPI bus speed to 4MHz (16MHz / 4 = 4MHz)

MP3Clock = Mp3ReadRegister(SCI_CLOCKF);
Serial.print("SCI_ClockF = 0x");
Serial.println(MP3Clock, HEX);

//MP3 IC setup complete

}

void loop(){
playMP3(trackName);

trackNumber++; //When we loop, advance to next track!

if(trackNumber > 1) {
Serial.println("Whoa there cowboy!");
while(1);
}
}

//PlayMP3 pulls 32 byte chunks from the SD card and throws them at the VS1053
//We monitor the DREQ (data request pin). If it goes low then we determine if
//we need new data or not. If yes, pull new from SD card. Then throw the data
//at the VS1053 until it is full.
void playMP3(char* fileName) {
File mp3File;

if ((mp3File = SD.open(fileName)) == NULL) {
Serial.print("File not found");
return;
}
Serial.println("Track open");

uint8_t mp3DataBuffer[32]; //Buffer of 32 bytes. VS1053 can take 32 bytes at a go.
//track.read(mp3DataBuffer, sizeof(mp3DataBuffer)); //Read the first 32 bytes of the song
int need_data = TRUE;
long replenish_time = millis();

Serial.println("Start MP3 decoding");

while(1) {
while(!digitalRead(MP3_DREQ)) {
//DREQ is low while the receive buffer is full
//You can do something else here, the buffer of the MP3 is full and happy.
//Maybe set the volume or test to see how much we can delay before we hear audible glitches

//If the MP3 IC is happy, but we need to read new data from the SD, now is a great time to do so
if(need_data == TRUE) {
if(!mp3File.read(mp3DataBuffer, sizeof(mp3DataBuffer))) { //Try reading 32 new bytes of the song
//Oh no! There is no data left to read!
//Time to exit
break;
}
need_data = FALSE;
}

//Serial.println("."); //Print a character to show we are doing nothing

//This is here to show how much time is spent transferring new bytes to the VS1053 buffer. Relies on replenish_time below.
Serial.print("Time to replenish buffer: ");
Serial.print(millis() - replenish_time, DEC);
Serial.print("ms");

//Test to see just how much we can do before the audio starts to glitch
long start_time = millis();
//delay(150); //Do NOTHING - audible glitches
//delay(135); //Do NOTHING - audible glitches
//delay(120); //Do NOTHING - barely audible glitches
delay(100); //Do NOTHING - sounds fine
Serial.print(" Idle time: ");
Serial.print(millis() - start_time, DEC);
Serial.println("ms");
//Look at that! We can actually do quite a lot without the audio glitching

//Now that we've completely emptied the VS1053 buffer (2048 bytes) let's see how much
//time the VS1053 keeps the DREQ line high, indicating it needs to be fed
replenish_time = millis();
}


if(need_data == TRUE){ //This is here in case we haven't had any free time to load new data
if(!mp3File.read(mp3DataBuffer, sizeof(mp3DataBuffer))) { //Go out to SD card and try reading 32 new bytes of the song
//Oh no! There is no data left to read!
//Time to exit
break;
}
need_data = FALSE;
}

//Once DREQ is released (high) we now feed 32 bytes of data to the VS1053 from our SD read buffer
digitalWrite(MP3_XDCS, LOW); //Select Data
for(int y = 0 ; y < sizeof(mp3DataBuffer) ; y++) {
SPI.transfer(mp3DataBuffer[y]); // Send SPI byte
}

digitalWrite(MP3_XDCS, HIGH); //Deselect Data
need_data = TRUE; //We've just dumped 32 bytes into VS1053 so our SD read buffer is empty. Set flag so we go get more data
}

while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating transfer is complete
digitalWrite(MP3_XDCS, HIGH); //Deselect Data

mp3File.close(); //Close out this track

sprintf(errorMsg, "Track %s done!", fileName);
Serial.println(errorMsg);
}

//Write to VS10xx register
//SCI: Data transfers are always 16bit. When a new SCI operation comes in
//DREQ goes low. We then have to wait for DREQ to go high again.
//XCS should be low for the full duration of operation.
void Mp3WriteRegister(unsigned char addressbyte, unsigned char highbyte, unsigned char lowbyte){
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating IC is available
digitalWrite(MP3_XCS, LOW); //Select control

//SCI consists of instruction byte, address byte, and 16-bit data word.
SPI.transfer(0x02); //Write instruction
SPI.transfer(addressbyte);
SPI.transfer(highbyte);
SPI.transfer(lowbyte);
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating command is complete
digitalWrite(MP3_XCS, HIGH); //Deselect Control
}

//Read the 16-bit value of a VS10xx register
unsigned int Mp3ReadRegister (unsigned char addressbyte){
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating IC is available
digitalWrite(MP3_XCS, LOW); //Select control

//SCI consists of instruction byte, address byte, and 16-bit data word.
SPI.transfer(0x03); //Read instruction
SPI.transfer(addressbyte);

char response1 = SPI.transfer(0xFF); //Read the first byte
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating command is complete
char response2 = SPI.transfer(0xFF); //Read the second byte
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating command is complete

digitalWrite(MP3_XCS, HIGH); //Deselect Control

int resultvalue = response1 << 8;
resultvalue |= response2;
return resultvalue;
}

//Set VS10xx Volume Register
void Mp3SetVolume(unsigned char leftchannel, unsigned char rightchannel){
Mp3WriteRegister(SCI_VOL, leftchannel, rightchannel);
}
 
Back
Top