Tutorial: como utilizar o MP3 Player Shield com Arduino

Adquira estes componentes na Loja do Lab de Garagem

Neste tutorial, vamos mostrar como utilizar o MP3 Player Shield com Arduino.

O MP3 Player Shield é um Shield que você acopla no Arduino e este vira um player de MP3.

Antes de mais nada, é necessário baixar a biblioteca SDfat, disponível aqui. Depois de baixar a biblioteca, extraia para a pasta "libraries" dentro da pasta da IDE do Arduino. Dentro da pasta do SDfat que você extraiu, abra o arquivo "Sd2PinMap.h" e localize o seguinte comentário: "// 168 and 328 Arduinos" para Arduino UNO e Duemilanove. Abaixo deste comentário tem uma linha escrito: "uint8_t const SS_PIN = 10;", mude o número 10 para 9, salve e feche o arquivo.

Com um cartão MicroSD, coloque uma música .mp3 e nomeie como track001.mp3. Coloque o cartão MicroSD no MP3 Player Shield.

Agora abra a IDE do Arduino e cole a programação exemplo disponibilizada aqui, vá para a linha destacada em vermelho, como mostrado abaixo, e verifique se é o número 10:

/*
4-28-2011
Spark Fun Electronics 2011
Nathan Seidle

This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

This example code plays a MP3 from the SD card called 'track001.mp3'. The theory is that you can load a
microSD card up with a bunch of MP3s and then play a given 'track' depending on some sort of input such
as which pin is pulled low.

It relies on the sdfatlib from Bill Greiman:
http://code.google.com/p/sdfatlib/
You will need to download and install his library. To compile, you MUST change Sd2PinMap.h of the SDfatlib!
The default SS_PIN = 10;. You must change this line under the ATmega328/Arduino area of code to
uint8_t const SS_PIN = 9;. This will cause the sdfatlib to use pin 9 as the 'chip select' for the
microSD card on pin 9 of the Arduino so that the layout of the shield works.

Attach the shield to an Arduino. Load code (after editing Sd2PinMap.h) then open the terminal at 57600bps. This
example shows that it takes ~30ms to load up the VS1053 buffer. We can then do whatever we want for ~100ms
before we need to return to filling the buffer (for another 30ms).

This code is heavily based on the example code I wrote to control the MP3 shield found here:
http://www.sparkfun.com/products/9736
This example code extends the previous example by reading the MP3 from an SD card and file rather than from internal
memory of the ATmega. Because the current MP3 shield does not have a microSD socket, you will need to add the microSD
shield to your Arduino stack.

The main gotcha from all of this is that you have to make sure your CS pins for each device on an SPI bus is carefully
declared. For the SS pin (aka CS) on the SD FAT libaray, you need to correctly set it within Sd2PinMap.h. The default
pin in Sd2PinMap.h is 10. If you're using the SparkFun microSD shield with the SparkFun MP3 shield, the SD CS pin
is pin 9.

Four pins are needed to control the VS1503:
DREQ
CS
DCS
Reset (optional but good to have access to)
Plus the SPI bus

Only the SPI bus pins and another CS pin are needed to control the microSD card.

What surprised me is the fact that with a normal MP3 we can do other things for up to 100ms while the MP3 IC crunches
through it's fairly large buffer of 2048 bytes. As long as you keep your sensor checks or serial reporting to under
100ms and leave ~30ms to then replenish the MP3 buffer, you can do quite a lot while the MP3 is playing glitch free.

*/

#include <SPI.h>

//Add the SdFat Libraries
#include <SdFat.h>
#include <SdFatUtil.h>

//Create the variables to be used by SdFat Library
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile track;

//This is the name of the file on the microSD card you would like to play
//Stick with normal 8.3 nomeclature. All lower-case works well.
//Note: you must name the tracks on the SD card with 001, 002, 003, etc.
//For example, the code is expecting to play 'track002.mp3', not track2.mp3.
char trackName[] = "track001.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 6 //Control Chip Select Pin (for accessing SPI Control/Status registers)
#define MP3_XDCS 7 //Data Chip Select / BSYNC Pin
#define MP3_DREQ 2 //Data Request Pin: Player asks for more data
#define MP3_RESET 8 //Reset is active low
//Remember you have to edit the Sd2PinMap.h of the sdfatlib library to correct control the 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(57600); //Use serial for debugging
Serial.println("MP3 Testing");

//Setup SD card interface
pinMode(10, OUTPUT); //Pin 10 must be set as an output for the SD communication to work.
if (!card.init(SPI_FULL_SPEED)) Serial.println("Error: Card init"); //Initialize the SD card and configure the I/O pins.
if (!volume.init(&card)) Serial.println("Error: Volume ini"); //Initialize a volume on the SD card.
if (!root.openRoot(&volume)) Serial.println("Error: Opening root"); //Open the root directory in the volume.

//We have no need to setup SPI for VS1053 because this has already been done by the SDfatlib

//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(){

//Let's play a track of a given number
sprintf(trackName, "track%03d.mp3", trackNumber); //Splice the new file number into this file name
playMP3(trackName); //Go play trackXXX.mp3

//Once we are done playing or have exited the playback for some reason, decide what track to play next
trackNumber++; //When we loop, advance to next track!

if(trackNumber > 100) {
Serial.println("Whoa there cowboy!"); //Soft limit. We shouldn't be trying to open past track 100.
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) {

if (!track.open(&root, fileName, O_READ)) { //Open the file in read mode.
sprintf(errorMsg, "Failed to open %s", fileName);
Serial.println(errorMsg);
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(!track.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(!track.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

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

Selecione a versão da sua placa Arduino (UNO, Duemilanove, etc) e selecione a Porta a qual o Arduino está conectado (COMx, ttyUSBx, ttyACMx, etc) e clique em UPLOAD. Ao terminar, conecte o MP3 Player Shield no Arduino. O áudio sairá pelo conector PS/2, então conecte as caixinhas de som e pronto! Caso tenha dúvidas, poste aqui mesmo neste blog!

Caso tenha sugestões para tutoriais, poste aqui! Para ver outros tutoriais disponíveis, clique aqui, e para projetos abertos disponibilizados por outros garagistas ou pela equipe LdG, clique aqui! Até a próxima!!

Referências:

http://www.sparkfun.com/products/10628

http://www.sparkfun.com/tutorials/295

Exibições: 13436

Comentar

Você precisa ser um membro de Laboratorio de Garagem (arduino, eletrônica, robotica, hacking) para adicionar comentários!

Entrar em Laboratorio de Garagem (arduino, eletrônica, robotica, hacking)

Comentário de ronaldo abadio dos santos em 13 agosto 2015 às 23:26

ola amigo teria como acopla uma shield mp3 com uma easyvr  para aumenta  o numero de comandos

pois eu gostaria de  faze  automaçao de minha casa com comando de voz  mais  a quantidade de comando da easyvr e limitado pois vc fala ela responde e eseculta  o pesamento era o seguinte  deixa  os audio  a quais seria  as fala da easyvr  na shield mp3 para  libera mais espasso e asim  aumenta os numeroas de comando?  o que vcs mim falao  da minha loucura kk

Comentário de Edson Rodrigues do Vale Junior em 10 maio 2014 às 17:05

Este Shield mp3 ocupa todas as portas do Arduino? Ele é compatível com outros Arduinos além do UNO?

Comentário de Alexandre Costa em 3 maio 2014 às 21:50

Tem como ligar esse shield em um MEGA 2560 ???

Comentário de Fabiano Assunção em 2 abril 2014 às 19:29

O SDFat na sua versão atual não tem o arquivo  "Sd2PinMap.h", portanto o código não implementa. Alguém sabe como atualizar o código para usar o Shield na versão atual?

Comentário de Fabrício Peres em 17 outubro 2013 às 17:32

Olá galera, eu tenho um arduino mega 2560 como faço pra rodar esse código. Alguém me ajuda?

Comentário de Andressa Cutrim em 8 junho 2013 às 16:23

Oi, gostaria de saber como faço a conexão do arduíno e do shield MP3

Comentário de Arthur Grandini Rodella em 3 abril 2013 às 18:14

Olá, estou com um mp3 shield em mãos e um fone de ouvido conectado na saída p2, mas quando executo o código acima não toca a musica (track001.mp3) que está no microSD, e no serial monitor fica apenas aparecendo as linhas abaixo.. por favor me ajudem. 

SCI_Mode (0x4800) = 0x4800
SCI_Status (0x48) = 0x48
VS Version (VS1053 is 4) = 4
SCI_ClockF = 0x0
SCI_ClockF = 0x6000
Track open
Start MP3 decoding
Time to replenish buffer: 25ms Idle time: 99ms
Time to replenish buffer: 21ms Idle time: 100ms
Time to replenish buffer: 20ms Idle time: 100ms
Time to replenish buffer: 20ms Idle time: 100ms
Time to replenish buffer: 19ms Idle time: 101ms
Time to replenish buffer: 19ms Idle time: 99ms
Time to replenish buffer: 21ms Idle time: 100ms

Comentário de Laboratório de Garagem em 19 novembro 2012 às 8:40

Pessoal, Na programação acima, a linha destacada em vermelho mantenha o número 10. Mude apenas na biblioteca de 10 para 9. A correção já foi feita.

Abraços!

Equipe LdG

Comentário de Vinícius Fontes de Freitas em 19 novembro 2012 às 0:59

Bruno Lima, o mesmo aconteceu comigo.
Aconteceu isso com mais alguém? Como podemos solucionar?

Comentário de Bia Capelli em 10 novembro 2012 às 10:54

Oi, esse código pode ser adaptado para usar a biblioteca própria de VS1053 para Arduíno? Ao invés de explicitar as funções de inicialização como reset, simplesmente chamar "MP3.begin()"?

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço