okay so im trying to make an mp3 player through an sd card and a vs1003 breakout board... i've been at it for about a week now... i got each one to work individualy. i.e. the sine wave and reading and writing block, but trying to put them together creates havoc for me.
i was wondering if anyone could help me try to figure it out.
heres the code:
/*
SPI:
MOSI pin 11
MISO pin 12
CLK pin 13
MP3:
XRESET pin 6
DREQ pin 7
XDCS pin 8
CS pin 9
SD:
CS pin 10
*/
/**MP3 Variables**/
#include <avr/io.h>
#define MP3_XRST 6
#define MP3_DREQ 7
#define MP3_XDCS 8
#define MP3_CS 9
#define SD_CS 10
#define SPI_MOSI 11
#define SPI_MISO 12
#define SPI_CLK 13
//SCI_MODE register defines
#define SM_DIFF 0
#define SM_SETTOZERO 1
#define SM_RESET 2
#define SM_OUTOFWAV 3
#define SM_PDOWN 4
#define SM_TESTS 5
#define SM_STREAM 6
#define SM_PLUSV 7
#define SM_DACT 8
#define SM_SDIORD 9
#define SM_SDISHARE 10
#define SM_SDINEW 11
#define SM_ADPCM 12
#define SM_ADPCM_HP 13
/*SD Card Vairables*/
byte clr;
byte spi_err;
// SD Card variables
#define blockSize 512
byte vBlock[blockSize];
byte vBuffer[16];
#define GO_IDLE_STATE 0x00 // resets the SD card
#define SEND_CSD 0x09 // sends card-specific data
#define SEND_CID 0x0A // sends card identification
#define READ_SINGLE_BLOCK 0x11 // reads a block at byte address
#define WRITE_BLOCK 0x18 // writes a block at byte address
#define SEND_OP_COND 0x29 // starts card initialization
#define APP_CMD 0x37 // prefix for application command
//Send SPI Command, includes timeout managment
byte spi_cmd(volatile char data){
spi_err = 0;
SPDR = data; //start the transmission by loading the output byte into the spi data register
int i = 0;
while(!(SPSR &(1<<SPIF))){
i++;
if(i >= 0xFF){
spi_err = 1;
return 0x00;
}
}
return SPDR;
}
//initialized SPI PORT
void spi_init()
{
pinMode(MP3_XDCS, OUTPUT);
pinMode(MP3_CS, OUTPUT);
pinMode(MP3_DREQ, INPUT);
pinMode(SD_CS, OUTPUT);
pinMode(SPI_MOSI, OUTPUT);
pinMode(SPI_MISO, INPUT);
pinMode(SPI_CLK, OUTPUT);
SPCR = (1<<SPE) | (1<<MSTR); // spi enabled, master mode
clr = SPSR;
clr = SPDR;
}
byte spi_SD(){
// set slow clock: 1/128 base frequency (125Khz in this case)
SPCR |= (1<<SPR1) | (1<<SPR0); // set slow clock: 1/128 base frequency (125Khz in this case)
SPSR &= ~(1<<SPI2X); // No doubled clock frequency
// wake up SD card
PORTB |= (1<<SD_CS); // deasserts card for warmup
PORTB |= (1<<SPI_MOSI); // set MOSI high
for(byte i=0; i<10; i++) {
spi_cmd(0xFF); // send 10 times 8 pulses for a warmup (74 minimum)
}
// set idle mode
byte retries=0;
PORTB &= ~(1<<SD_CS); // assert chip select for the card
while(sdc_cmd(GO_IDLE_STATE, 0) != 0x01) { // while SD card is not in iddle state
retries++;
if (retries >= 0xFF) {
return(NULL); // timed out!
}
delay(5);
}
// at this stage, the card is in idle mode and ready for start up
retries = 0;
sdc_cmd(APP_CMD, 0); // startup sequence for SD cards 55/41
while (sdc_cmd(SEND_OP_COND, 0) != 0x00) {
retries++;
if (retries >= 0xFF) {
return(NULL); // timed out!
}
sdc_cmd(APP_CMD, 0);
}
// set fast clock, 1/4 CPU clock frequency (4Mhz in this case)
SPCR &= ~((1<<SPR1) | (1<<SPR0)); // Clock Frequency: f_OSC / 4
SPSR |= (1<<SPI2X); // Doubled Clock Frequency: f_OSC / 2
return (0x01); // returned value (success)
}
void spi_MP3_Clock(){
SPCR &= ~((1<<SPR1) | (1<<SPR0)); // Clock Frequency: f_OSC / 4
}
/************SD Card************/
byte sdc_cmd(byte commandIndex, long arg) {
digitalWrite(SD_CS, LOW);// assert chip select for the card
spi_cmd(0xFF); // dummy byte
commandIndex |= 0x40; // command token OR'ed with 0x40
spi_cmd(commandIndex); // send command
for (int i=3; i>=0; i--) {
spi_cmd(arg>>(i*8)); // send argument in little endian form (MSB first)
}
spi_cmd(0x95); // checksum valid for GO_IDLE_STATE, not needed thereafter, so we can hardcode this value
spi_cmd(0xFF); // dummy byte gives card time to process
byte res = spi_cmd(0xFF);
return (res); // query return value from card
}
//clear sd card Block Content
void sdc_clearVector(void) {
for (int i=0; i<blockSize; i++) {
vBlock[i] = 0;
}
}
// get # of blocks on SD memory card from
long sdc_totalNbrBlocks(void) {
sdc_readRegister(SEND_CSD);
// compute size
long C_Size = ((vBuffer[0x08] & 0xC0) >> 6) | ((vBuffer[0x07] & 0xFF) << 2) | ((vBuffer[0x06] & 0x03) << 10);
long C_Mult = ((vBuffer[0x08] & 0x80) >> 7) | ((vBuffer[0x08] & 0x03) << 2);
return ((C_Size+1) << (C_Mult+2));
}
// read SD card register content and store it in vBuffer
void sdc_readRegister(byte sentCommand) {
byte retries=0x00;
byte res=sdc_cmd(sentCommand, 0);
while(res != 0x00) {
delay(1);
retries++;
if (retries >= 0xFF) return; // timed out!
res=spi_cmd(0xFF); // retry
}
// wait for data token
while (spi_cmd(0xFF) != 0xFE);
// read data
for (int i=0; i<16; i++) {
vBuffer[i] = spi_cmd(0xFF);
}
// read CRC (lost results in blue sky)
spi_cmd(0xFF); // LSB
spi_cmd(0xFF); // MSB
}
void sdc_readBlock(long blockIndex){
byte retries = 0x00;
byte res = sdc_cmd(READ_SINGLE_BLOCK, (blockIndex * blockSize));
while(res != 0x00) {
delay(1);
retries++;
if (retries >= 0xFF) return; // timed out!
res=spi_cmd(0xFF); // retry
}
// read data packet (includes data token, data block and CRC)
// read data token
while (spi_cmd(0xFF) != 0xFE);
// read data block
for (int i=0; i<blockSize; i++) {
vBlock[i] = spi_cmd(0xFF); // read data
Serial.println(vBlock[i]);
}
// read CRC (lost results in blue sky)
spi_cmd(0xFF); // LSB
spi_cmd(0xFF); // MSB
}
void sdc_writeBlock(long blockIndex) {
byte retries=0;
while(sdc_cmd(WRITE_BLOCK, blockIndex * blockSize) != 0x00) {
delay(1);
retries++;
if (retries >= 0xFF) return; // timed out!
}
spi_cmd(0xFF); // dummy byte (at least one)
// send data packet (includes data token, data block and CRC)
// data token
spi_cmd(0xFE);
// copy block data
for (int i=0; i<blockSize; i++) {
spi_cmd(vBlock[i]);
}
// write CRC (lost results in blue sky)
spi_cmd(0xFF); // LSB
spi_cmd(0xFF); // MSB
// wait until write is finished
while (spi_cmd(0xFF) != 0xFF) delay(1); // kind of NOP
}
/****************MP3 Section*****************/
void dcs_low()
{
digitalWrite(MP3_XDCS, LOW);
delay(1); //this delay is important to give vs1002 enough time to react
}
void dcs_high()
{
digitalWrite(MP3_XDCS, HIGH);
delay(1); //this delay is important to give vs1002 enough time to react
}
void cs_low()
{
digitalWrite(MP3_CS, LOW);
delay(1); //this delay is important to give vs1002 enough time to react
}
void cs_high()
{
digitalWrite(MP3_CS, HIGH);
delay(1); //this delay is important to give vs1002 enough time to react
}
char spi_send(volatile char byte)
{
SPDR = byte; //send byte
while(!(SPSR & (1 << SPIF))); //wait until its done
return SPDR; //return the rx byte
}
int sci_read(char address)
{
unsigned int temp;
cs_low();
spi_send(0x03); //send read command, don't worry about return byte
spi_send(address); //now send the address to read
temp = spi_send(0x00); //dummy byte to get out data MSBs
temp <<= 8; //shift it along so we can fit more data in
temp += spi_send(0x00); // get the LSB
cs_high();
return temp;
}
void sci_write(char address, int data)
{
cs_low();
spi_send(0x02); //send write command
spi_send(address); //send address we are going to write to
spi_send((data >> 8) & 0xFF); //send the first 8 MSBs of the data
spi_send(data & 0xFF); //send the LSBs
cs_high();
}
void send_sinewave(char pitch)
{
cs_high(); //this is different to SCI, it is data over SDI (see p.21 datasheet)
dcs_low();
/* we need to send the following bytes (see p.35)
0x53 0xEF 0x6E <pitch>
0 0 0 0
*/
spi_send(0x53);
spi_send(0xEF);
spi_send(0x6E);
spi_send(pitch);
for (int i=0; i < 4; i++) spi_send(0x00); // send the filler bytes
dcs_high();
cs_low();
}
void sdc_printVectorContent(void) {
for (int i=0; i<blockSize; i++) {
Serial.print("0x");
if (vBlock[i] <= 0x0F) Serial.print("0");
Serial.print(vBlock[i], HEX);
Serial.print(" ");
// append crlf to each line of 16 bytes
if (((i+1) % 16) == 0) Serial.println();
}
Serial.println();
}
void send_song(){
cs_high();
dcs_low();
for (int i=0; i<blockSize; i++) {
spi_send(vBlock[i]);
}
dcs_high();
cs_low();
}
void setup(){
digitalWrite(MP3_XRST, LOW);
delay(100);
Serial.begin(9600);//115200);
// Initialize SPI and SDC
DDRB &= ~(1<<SPI_MISO);
// Data out
DDRB |= (1<<SPI_CLK);
DDRB |= (1<<SD_CS);
DDRB |= (1<<SPI_MOSI);
// Initialize serial communication
Serial.begin(9600);
// Initialize SPI and SDC
spi_err=0; // reset SPI error
spi_initialize(); // initialize SPI port
spi_err=0; // reset SPI error
spi_init(); //set up SPI registers
dcs_high();
cs_high();
spi_SD();
Serial.print(sdc_totalNbrBlocks(), DEC);
Serial.println(" blocks");
Serial.println("Reading blocks...");
// for (int b=0; b<255; b++) {
sdc_readBlock(1); // copy SD card block of data in vector of data
// }
Serial.println("Done...");
sdc_printVectorContent();
Serial.println("Done...");
digitalWrite(SD_CS, HIGH);
dcs_high();
cs_high(); // probably a good idea
digitalWrite(MP3_XRST, HIGH);
delay(100);
spi_MP3_Clock();
sci_write(0x00, (1<<SM_TESTS)|(1<<SM_STREAM)|(1<<SM_SDINEW));
while(digitalRead(MP3_DREQ) == 0x00);
cs_low(); // for data interface
send_sinewave(170);
// send_song();
Serial.println("Done...");
delay(10000);
}
void loop(){
}
}
it's peiced together... alot of it might be redundant... i understand pretty much all of what it's doing... but i dont see where the problem is... can someone please help. thanks
uh oh! i posted the wrong code up! >.< and the problem (for now) is that when i try to read blocks from the sd card it just gives me blank, 0x00 through the whole block.
heres the actual code: (sorry)
/*
SPI:
MOSI pin 11
MISO pin 12
CLK pin 13
MP3:
XRESET pin 6
DREQ pin 7
XDCS pin 8
CS pin 9
SD:
CS pin 10
Initialize SPI
Initialize SD Card
START
-Blank vector of data (vBlock)
-Record data in vector of data
-Copy data from vector to CSD card
GOTO START
*/
/******MP3 Variables*******/
#include <avr/io.h>
#define MP3_XRST 6
#define MP3_DREQ 7
#define MP3_XDCS 8
#define MP3_CS 9
#define SD_CS 10
#define SPI_MOSI 11
#define SPI_MISO 12
#define SPI_CLK 13
//SCI_MODE register defines (p. 26 datasheet)
#define SM_DIFF 0
#define SM_SETTOZERO 1
#define SM_RESET 2
#define SM_OUTOFWAV 3
#define SM_PDOWN 4
#define SM_TESTS 5
#define SM_STREAM 6
#define SM_PLUSV 7
#define SM_DACT 8
#define SM_SDIORD 9
#define SM_SDISHARE 10
#define SM_SDINEW 11
#define SM_ADPCM 12
#define SM_ADPCM_HP 13
/*********SD Card Vairables**********/
byte clr;
byte spi_err;
// SD Card variables
#define blockSize 512 // block size (default 512 bytes)
byte vBlock[blockSize]; // set vector containing data that will be recorded on SD Card
byte vBuffer[16];
#define GO_IDLE_STATE 0x00 // resets the SD card
#define SEND_CSD 0x09 // sends card-specific data
#define SEND_CID 0x0A // sends card identification
#define READ_SINGLE_BLOCK 0x11 // reads a block at byte address
#define WRITE_BLOCK 0x18 // writes a block at byte address
#define SEND_OP_COND 0x29 // starts card initialization
#define APP_CMD 0x37 // prefix for application command
//Send SPI Command, includes timeout managment
byte spi_cmd(volatile char data){
spi_err = 0;
SPDR = data; //start the transmission by loading the output byte into the spi data register
int i = 0;
while(!(SPSR &(1<<SPIF))){
i++;
if(i >= 0xFF){
spi_err = 1;
return 0x00;
}
}
return SPDR;
}
//initialized SPI PORT
void spi_init()
{
pinMode(MP3_XDCS, OUTPUT);
pinMode(MP3_CS, OUTPUT);
pinMode(MP3_DREQ, INPUT);
pinMode(SD_CS, OUTPUT);
pinMode(SPI_MOSI, OUTPUT);
pinMode(SPI_MISO, INPUT);
pinMode(SPI_CLK, OUTPUT);
SPCR = (1<<SPE) | (1<<MSTR); // spi enabled, master mode
clr = SPSR;
clr = SPDR;
}
byte spi_SD(){
// set slow clock: 1/128 base frequency (125Khz in this case)
SPCR |= (1<<SPR1) | (1<<SPR0); // set slow clock: 1/128 base frequency (125Khz in this case)
SPSR &= ~(1<<SPI2X); // No doubled clock frequency
// wake up SD card
PORTB |= (1<<SD_CS); // deasserts card for warmup
PORTB |= (1<<SPI_MOSI); // set MOSI high
for(byte i=0; i<10; i++) {
spi_cmd(0xFF); // send 10 times 8 pulses for a warmup (74 minimum)
}
// set idle mode
byte retries=0;
PORTB &= ~(1<<SD_CS); // assert chip select for the card
while(sdc_cmd(GO_IDLE_STATE, 0) != 0x01) { // while SD card is not in iddle state
retries++;
if (retries >= 0xFF) {
return(NULL); // timed out!
}
delay(5);
}
// at this stage, the card is in idle mode and ready for start up
retries = 0;
sdc_cmd(APP_CMD, 0); // startup sequence for SD cards 55/41
while (sdc_cmd(SEND_OP_COND, 0) != 0x00) {
retries++;
if (retries >= 0xFF) {
return(NULL); // timed out!
}
sdc_cmd(APP_CMD, 0);
}
// set fast clock, 1/4 CPU clock frequency (4Mhz in this case)
SPCR &= ~((1<<SPR1) | (1<<SPR0)); // Clock Frequency: f_OSC / 4
SPSR |= (1<<SPI2X); // Doubled Clock Frequency: f_OSC / 2
return (0x01); // returned value (success)
}
void spi_MP3_Clock(){
SPCR &= ~((1<<SPR1) | (1<<SPR0)); // Clock Frequency: f_OSC / 4
}
/************SD Card************/
byte sdc_cmd(byte commandIndex, long arg) {
digitalWrite(SD_CS, LOW);// assert chip select for the card
spi_cmd(0xFF); // dummy byte
commandIndex |= 0x40; // command token OR'ed with 0x40
spi_cmd(commandIndex); // send command
for (int i=3; i>=0; i--) {
spi_cmd(arg>>(i*8)); // send argument in little endian form (MSB first)
}
spi_cmd(0x95); // checksum valid for GO_IDLE_STATE, not needed thereafter, so we can hardcode this value
spi_cmd(0xFF); // dummy byte gives card time to process
byte res = spi_cmd(0xFF);
return (res); // query return value from card
}
//clear sd card Block Content
void sdc_clearVector(void) {
for (int i=0; i<blockSize; i++) {
vBlock[i] = 0;
}
}
// get # of blocks on SD memory card from
long sdc_totalNbrBlocks(void) {
sdc_readRegister(SEND_CSD);
// compute size
long C_Size = ((vBuffer[0x08] & 0xC0) >> 6) | ((vBuffer[0x07] & 0xFF) << 2) | ((vBuffer[0x06] & 0x03) << 10);
long C_Mult = ((vBuffer[0x08] & 0x80) >> 7) | ((vBuffer[0x08] & 0x03) << 2);
return ((C_Size+1) << (C_Mult+2));
}
// read SD card register content and store it in vBuffer
void sdc_readRegister(byte sentCommand) {
byte retries=0x00;
byte res=sdc_cmd(sentCommand, 0);
while(res != 0x00) {
delay(1);
retries++;
if (retries >= 0xFF) return; // timed out!
res=spi_cmd(0xFF); // retry
}
// wait for data token
while (spi_cmd(0xFF) != 0xFE);
// read data
for (int i=0; i<16; i++) {
vBuffer[i] = spi_cmd(0xFF);
}
// read CRC (lost results in blue sky)
spi_cmd(0xFF); // LSB
spi_cmd(0xFF); // MSB
}
void sdc_readBlock(long blockIndex){
byte retries = 0x00;
byte res = sdc_cmd(READ_SINGLE_BLOCK, (blockIndex * blockSize));
while(res != 0x00) {
delay(1);
retries++;
if (retries >= 0xFF) return; // timed out!
res=spi_cmd(0xFF); // retry
}
// read data packet (includes data token, data block and CRC)
// read data token
while (spi_cmd(0xFF) != 0xFE);
// read data block
for (int i=0; i<blockSize; i++) {
vBlock[i] = spi_cmd(0xFF); // read data
Serial.println(vBlock[i]);
}
// read CRC (lost results in blue sky)
spi_cmd(0xFF); // LSB
spi_cmd(0xFF); // MSB
}
void sdc_writeBlock(long blockIndex) {
byte retries=0;
while(sdc_cmd(WRITE_BLOCK, blockIndex * blockSize) != 0x00) {
delay(1);
retries++;
if (retries >= 0xFF) return; // timed out!
}
spi_cmd(0xFF); // dummy byte (at least one)
// send data packet (includes data token, data block and CRC)
// data token
spi_cmd(0xFE);
// copy block data
for (int i=0; i<blockSize; i++) {
spi_cmd(vBlock[i]);
}
// write CRC (lost results in blue sky)
spi_cmd(0xFF); // LSB
spi_cmd(0xFF); // MSB
// wait until write is finished
while (spi_cmd(0xFF) != 0xFF) delay(1); // kind of NOP
}
/****************MP3 Section*****************/
void dcs_low()
{
digitalWrite(MP3_XDCS, LOW);
delay(1); //this delay is important to give vs1002 enough time to react
}
void dcs_high()
{
digitalWrite(MP3_XDCS, HIGH);
delay(1); //this delay is important to give vs1002 enough time to react
}
void cs_low()
{
digitalWrite(MP3_CS, LOW);
delay(1); //this delay is important to give vs1002 enough time to react
}
void cs_high()
{
digitalWrite(MP3_CS, HIGH);
delay(1); //this delay is important to give vs1002 enough time to react
}
char spi_send(volatile char byte)
{
SPDR = byte; //send byte
while(!(SPSR & (1 << SPIF))); //wait until its done
return SPDR; //return the rx byte
}
int sci_read(char address)
{
unsigned int temp;
cs_low();
spi_send(0x03); //send read command, don't worry about return byte
spi_send(address); //now send the address to read
temp = spi_send(0x00); //dummy byte to get out data MSBs
temp <<= 8; //shift it along so we can fit more data in
temp += spi_send(0x00); // get the LSB
cs_high();
return temp;
}
void sci_write(char address, int data)
{
cs_low();
spi_send(0x02); //send write command
spi_send(address); //send address we are going to write to
spi_send((data >> 8) & 0xFF); //send the first 8 MSBs of the data
spi_send(data & 0xFF); //send the LSBs
cs_high();
}
void send_sinewave(char pitch)
{
cs_high(); //this is different to SCI, it is data over SDI (see p.21 datasheet)
dcs_low();
spi_send(0x53);
spi_send(0xEF);
spi_send(0x6E);
spi_send(pitch);
for (int i=0; i < 4; i++) spi_send(0x00); // send the filler bytes
dcs_high();
cs_low();
}
void sdc_printVectorContent(void) {
for (int i=0; i<blockSize; i++) {
Serial.print("0x");
if (vBlock[i] <= 0x0F) Serial.print("0");
Serial.print(vBlock[i], HEX);
Serial.print(" ");
// append crlf to each line of 16 bytes
if (((i+1) % 16) == 0) Serial.println();
}
Serial.println();
}
void send_song(){
cs_high();
dcs_low();
for (int i=0; i<blockSize; i++) {
spi_send(vBlock[i]);
}
dcs_high();
cs_low();
}
void setup() {
// Set ports
// Data in
DDRB &= ~(1<<SPI_MISO);
// Data out
DDRB |= (1<<SPI_CLK);
DDRB |= (1<<SD_CS);
DDRB |= (1<<SPI_MOSI);
// Initialize serial communication
Serial.begin(9600);
// Initialize SPI and SDC
spi_err=0; // reset SPI error
spi_init(); // initialize SPI port
spi_SD(); // Initialize SD Card
Serial.print(sdc_totalNbrBlocks(), DEC);
Serial.println(" blocks");
}
void loop() {
Serial.println("Reading blocks...");
for (int b=0; b<255; b++) {
Serial.print("Reading block ");
Serial.println(b, HEX);
sdc_readBlock(b); // copy SD card block of data in vector of data
sdc_printVectorContent(); // print vector of data content
}
}
and as for the the spi_err being set at 255, thats just the timeout. if it takes longer than that then it just stops what it's doing. and yeah it's pretty good it has worked for me...
see the code works when it reads and writes the blocks... but not when it just reads them...
and inside the sd cards i have 2 files song1.mp3 and song2.mp3 but when it reads and writes the files it just simply seems to ignore them.
void loop() {
// This is just an example
/* Serial.println("Writing blocks...");
for (int b=0; b<255; b++) {
Serial.print("Writing block ");
Serial.println(b, HEX);
for (int i=0; i<blockSize; i++){
vBlock[i] = b; // write incremental data
}
sdc_writeBlock(b); // copy vector of data on SD card
}*/
Serial.println("Reading blocks...");
for (int b=0; b<255; b++) {
Serial.print("Reading block ");
Serial.println(b, HEX);
sdc_readBlock(b); // copy SD card block of data in vector of data
sdc_printVectorContent(); // print vector of data content
}
}
this one does work. but it just writes 0xFE all through the block then prints that.
and the reason why i am not using libraries is that i need to use a sanguino because i have an lcd screen and quite a bit of buttons on my project, so the pins dont all fit an my regular arduino. And apparantly my libraries don't work on the sanguino. ive tried and tried and tried to change them but i can't seem to fix it.
Leonidas:
... see the code works when it reads and writes the blocks... but not when it just reads them...
and inside the sd cards i have 2 files song1.mp3 and song2.mp3 but when it reads and writes the files it just simply seems to ignore them.
I'm a bit confused looking at your code because I don't see any references to song1.mp3 or any attempts to read directory structures or anything like that. How are these SD cards connected?
well see i just started with spi. i understand how it works and the protocols for different things... in here i was just trying to see if i could get anything out of the sd card using code that i found and modified a bit. but i guess it's intention wasn't to read anything from the sd card. I guess i though that it would start reading and it would begin on song1.mp3. any suggestions then?