Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 14 of 14

Thread: Teensy 2.0 With VS1053

  1. #1
    Junior Member
    Join Date
    Aug 2013
    Posts
    7

    Teensy 2.0 With VS1053

    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/Ad...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
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	vs1053-mp3-module.jpg 
Views:	943 
Size:	200.5 KB 
ID:	745  
    Last edited by drMams; 08-01-2013 at 06:56 PM.

  2. #2
    Junior Member
    Join Date
    Aug 2013
    Posts
    7
    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 by drMams; 08-01-2013 at 07:09 PM.

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,985
    Quote Originally Posted by drMams View Post
    with a VS1003/VS1053 board (see attached picture of the exact board)
    Which board is that? It does not look like Adafruit's product. Where did you buy it?

  4. #4
    Junior Member
    Join Date
    Aug 2013
    Posts
    7
    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!
    Attached Files Attached Files

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,985
    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.

  6. #6
    Junior Member
    Join Date
    Aug 2013
    Posts
    7
    Hi again, you can ask for any info, I just didn't want to scare any one with a 20 page long thread

    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>
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	schema.png 
Views:	650 
Size:	26.6 KB 
ID:	748   Click image for larger version. 

Name:	IMG_0001.jpg 
Views:	540 
Size:	209.9 KB 
ID:	749  

    Click image for larger version. 

Name:	IMG_0002.jpg 
Views:	653 
Size:	198.7 KB 
ID:	750   Click image for larger version. 

Name:	IMG_0003.jpg 
Views:	576 
Size:	185.2 KB 
ID:	751  

    Click image for larger version. 

Name:	IMG_0004.jpg 
Views:	673 
Size:	183.7 KB 
ID:	752  

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,985
    Are you able to run the SD library "listfiles" example? Can it access the SD card through this wiring?

  8. #8
    Junior Member
    Join Date
    Aug 2013
    Posts
    7
    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)

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,985
    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.

  10. #10
    Junior Member
    Join Date
    Aug 2013
    Posts
    7
    Thanks alot anyways. 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!

  11. #11

  12. #12
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,985
    I purchased one. It'll probably take a few weeks to arrive. I can't promise I'll be able to use it quickly.

  13. #13
    Junior Member
    Join Date
    Aug 2013
    Posts
    1

    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/...le_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);
    }

  14. #14
    Junior Member
    Join Date
    Nov 2013
    Posts
    1
    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

    Quote Originally Posted by charlie View Post
    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/...le_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);
    }

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •