#410007091 kayuli (mel) software code

45
All of my software code (Included code to test mp3 player shield, force sensitive resistor – square, WiFly Shield, basic 16x2 character LCD and codes that combined all code) Step 1: Code to test the mp3 player shield /* 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

Upload: melmel7159

Post on 24-Apr-2015

105 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: #410007091 KaYuLI (MeL) Software Code

All of my software code

(Included code to test mp3 player shield, force sensitive resistor – square, WiFly Shield, basic

16x2 character LCD and codes that combined all code)

Step 1:

Code to test the mp3

player shield

/*

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

Page 2: #410007091 KaYuLI (MeL) Software Code

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;

Page 3: #410007091 KaYuLI (MeL) Software Code

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

Page 4: #410007091 KaYuLI (MeL) Software Code

#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.

Page 5: #410007091 KaYuLI (MeL) Software Code

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

Page 6: #410007091 KaYuLI (MeL) Software Code

//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.

Page 7: #410007091 KaYuLI (MeL) Software Code

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;

}

Page 8: #410007091 KaYuLI (MeL) Software Code

//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;

Page 9: #410007091 KaYuLI (MeL) Software Code

}

//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

Page 10: #410007091 KaYuLI (MeL) Software Code

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);

}

Page 11: #410007091 KaYuLI (MeL) Software Code

Step 2:

Code to test the force

sensitive resistor - square

/*

AnalogReadSerial

Reads an analog input on pin 0, prints the result to the serial

monitor

This example code is in the public domain.

*/

void setup() {

Serial.begin(9600);

pinMode(13,OUTPUT);

}

void loop() {

Serial.println(analogRead(0), DEC);

if(analogRead(0) > 800)

{

Serial.println("LED on");

digitalWrite(13,255);

}

if(analogRead(0) < 800)

{

Serial.println("LED off");

digitalWrite(13,0);

}

}

Other:

Code to test the WiFly

Shield

/*

* WiFly Tutorial Example

* Copyright (c) 2010 SparkFun Electronics. All right reserved.

* Written by Chris Taylor

*

* This code was written to demonstrate the WiFly Tutorial from

SparkFun Electronics

*

* This code will associate with the SparkFun WiFi network,

serve a simple page, and

* "say" typed words using the Voice Box Shield

*

* http://www.sparkfun.com

Page 12: #410007091 KaYuLI (MeL) Software Code

*/

#include <string.h>

#include <SoftwareSerial.h>

#include <avr/pgmspace.h>

// SC16IS750 Register Definitions

#define THR 0x00 << 3

#define RHR 0x00 << 3

#define IER 0x01 << 3

#define FCR 0x02 << 3

#define IIR 0x02 << 3

#define LCR 0x03 << 3

#define MCR 0x04 << 3

#define LSR 0x05 << 3

#define MSR 0x06 << 3

#define SPR 0x07 << 3

#define TXFIFO 0x08 << 3

#define RXFIFO 0x09 << 3

#define DLAB 0x80 << 3

#define IODIR 0x0A << 3

#define IOSTATE 0x0B << 3

#define IOINTMSK 0x0C << 3

#define IOCTRL 0x0E << 3

#define EFCR 0x0F << 3

#define DLL 0x00 << 3

#define DLM 0x01 << 3

#define EFR 0x02 << 3

#define XON1 0x04 << 3

#define XON2 0x05 << 3

#define XOFF1 0x06 << 3

#define XOFF2 0x07 << 3

// SPI port definitions

#define CS 10

#define MOSI 11

#define MISO 12

#define SCK 13

Page 13: #410007091 KaYuLI (MeL) Software Code

// Voice Box Shield definitions

#define RES 3

#define SPK 4

#define txPin 2

SoftwareSerial speakjet = SoftwareSerial(0, txPin);

#define WORD_LIST_LENGTH 100

#define ASSOCIATE_TIMEOUT 5000

char is_get = 1;

// "Associated"

char message[] = {

132,187,187,137,8,189,8,128,154,191,129,176,0,255};

// SpeakJet numbers

char zero[] = {

167,7,128,7,149,164,0,255};

char one[] = {

147,14,135,8,141,0,255};

char two[] = {

8,191,162,31,0,255};

char three[] = {

8,190,148,8,128,0,255};

char four[] = {

186,7,137,153,0,0,255};

char five[] = {

186,157,166,0,255};

char six[] = {

8,187,129,14,194,7,187,0,255};

char seven[] = {

8,187,7,131,166,131,141,0,255};

char eight[] = {

154,4,191,0,255};

char nine[] = {

141,14,157,141,0,255};

char *numbers[] = {

zero, one, two, three, four, five, six, seven, eight, nine };

Page 14: #410007091 KaYuLI (MeL) Software Code

char ping[] = {

220,0,255};

char dot[] = {

175,8,135,191,0,255};

// WORD LIST

// Phoneme strings for SpeakJet

// Placed in program memory to save RAM

prog_char sj_the[] PROGMEM = {

8,169,8,128,0,0,255};

prog_char sj_of[] PROGMEM = {

8,134,166,0,0,255};

prog_char sj_and1[] PROGMEM = {

8,132,8,141,177,0,0,255};

prog_char sj_a1[] PROGMEM = {

154,128,0,0,255};

prog_char sj_to[] PROGMEM = {

8,191,162,0,0,255};

prog_char sj_in[] PROGMEM = {

8,129,8,141,0,0,255};

prog_char sj_is[] PROGMEM = {

8,129,167,0,0,255};

prog_char sj_you[] PROGMEM = {

8,160,0,0,255};

prog_char sj_that[] PROGMEM = {

169,8,132,8,191,0,0,255};

prog_char sj_it[] PROGMEM = {

8,129,8,191,0,0,255};

prog_char sj_he[] PROGMEM = {

183,128,0,0,255};

prog_char sj_for1[] PROGMEM = {

186,153,0,0,255};

prog_char sj_was[] PROGMEM = {

147,134,167,0,0,255};

prog_char sj_on[] PROGMEM = {

135,135,142,0,0,255};

prog_char sj_are[] PROGMEM = {

152,0,0,255};

Page 15: #410007091 KaYuLI (MeL) Software Code

prog_char sj_as[] PROGMEM = {

132,8,167,0,0,255};

prog_char sj_with[] PROGMEM = {

147,129,8,8,190,0,0,255};

prog_char sj_his[] PROGMEM = {

183,129,167,0,0,255};

prog_char sj_they[] PROGMEM = {

8,169,154,0,0,255};

prog_char sj_at[] PROGMEM = {

132,8,191,0,0,255};

prog_char sj_be[] PROGMEM = {

170,128,128,0,0,255};

prog_char sj_this1[] PROGMEM = {

8,169,8,129,187,0,0,255};

prog_char sj_from[] PROGMEM = {

186,148,134,8,140,0,0,255};

prog_char sj_i1[] PROGMEM = {

157,0,0,255};

prog_char sj_have[] PROGMEM = {

183,8,132,166,0,0,255};

prog_char sj_or1[] PROGMEM = {

153,0,0,255};

prog_char sj_by[] PROGMEM = {

171,157,0,0,255};

prog_char sj_one[] PROGMEM = {

147,14,135,8,141,0,0,255};

prog_char sj_not1[] PROGMEM = {

141,135,191,0,0,255};

prog_char sj_what[] PROGMEM = {

185,8,135,191,0,0,255};

prog_char sj_all[] PROGMEM = {

8,136,8,146,0,0,255};

prog_char sj_when[] PROGMEM = {

185,8,131,8,141,0,0,255};

prog_char sj_we[] PROGMEM = {

147,8,128,0,0,255};

prog_char sj_there[] PROGMEM = {

8,169,150,0,0,255};

prog_char sj_can[] PROGMEM = {

194,8,132,141,0,0,255};

Page 16: #410007091 KaYuLI (MeL) Software Code

prog_char sj_an[] PROGMEM = {

132,132,141,0,0,255};

prog_char sj_your[] PROGMEM = {

128,153,0,0,255};

prog_char sj_which[] PROGMEM = {

185,129,8,182,0,0,255};

prog_char sj_their[] PROGMEM = {

8,169,150,0,0,255};

prog_char sj_if1[] PROGMEM = {

129,186,186,0,0,255};

prog_char sj_do1[] PROGMEM = {

174,162,0,0,255};

prog_char sj_will[] PROGMEM = {

147,129,8,145,0,0,255};

prog_char sj_each[] PROGMEM = {

128,128,4,182,0,0,255};

prog_char sj_about[] PROGMEM = {

134,173,163,191,0,0,255};

prog_char sj_how[] PROGMEM = {

184,8,163,0,0,255};

prog_char sj_up[] PROGMEM = {

8,134,199,0,0,255};

prog_char sj_out[] PROGMEM = {

163,191,0,0,255};

prog_char sj_them[] PROGMEM = {

8,169,131,8,140,0,0,255};

prog_char sj_then[] PROGMEM = {

8,169,131,8,142,0,0,255};

prog_char sj_she[] PROGMEM = {

8,189,8,128,0,0,255};

prog_char sj_many[] PROGMEM = {

140,131,141,128,0,0,255};

prog_char sj_some[] PROGMEM = {

8,187,134,140,0,0,255};

prog_char sj_so[] PROGMEM = {

8,188,7,164,7,147,0,0,255};

prog_char sj_these[] PROGMEM = {

8,169,8,128,7,167,0,0,255};

prog_char sj_would[] PROGMEM = {

147,8,138,177,0,0,255};

Page 17: #410007091 KaYuLI (MeL) Software Code

prog_char sj_other[] PROGMEM = {

134,190,151,0,0,255};

prog_char sj_into[] PROGMEM = {

129,141,191,162,0,0,255};

prog_char sj_more[] PROGMEM = {

140,7,137,153,0,0,255};

prog_char sj_her[] PROGMEM = {

183,151,0,0,255};

prog_char sj_two[] PROGMEM = {

8,191,162,0,0,255};

prog_char sj_like[] PROGMEM = {

145,7,135,7,155,196,0,0,255};

prog_char sj_him[] PROGMEM = {

183,8,129,140,0,0,255};

prog_char sj_see[] PROGMEM = {

187,187,128,128,0,0,255};

prog_char sj_time[] PROGMEM = {

8,191,157,8,140,0,0,255};

prog_char sj_could[] PROGMEM = {

195,138,138,177,0,0,255};

prog_char sj_no[] PROGMEM = {

142,164,0,0,255};

prog_char sj_make[] PROGMEM = {

140,154,196,0,0,255};

prog_char sj_than[] PROGMEM = {

169,8,132,8,142,0,0,255};

prog_char sj_first[] PROGMEM = {

186,151,187,191,0,0,255};

prog_char sj_now[] PROGMEM = {

142,163,0,0,255};

prog_char sj_people[] PROGMEM = {

198,7,128,198,8,145,0,0,255};

prog_char sj_my[] PROGMEM = {

140,155,0,0,255};

prog_char sj_over[] PROGMEM = {

8,137,7,166,151,0,0,255};

prog_char sj_down[] PROGMEM = {

175,163,141,0,0,255};

prog_char sj_only[] PROGMEM = {

137,142,145,128,0,0,255};

Page 18: #410007091 KaYuLI (MeL) Software Code

prog_char sj_find[] PROGMEM = {

186,155,141,177,0,0,255};

prog_char sj_use[] PROGMEM = {

160,167,0,0,255};

prog_char sj_may[] PROGMEM = {

140,154,0,0,255};

prog_char sj_water[] PROGMEM = {

147,135,191,7,151,0,0,255};

prog_char sj_long1[] PROGMEM = {

146,135,8,144,0,0,255};

prog_char sj_little[] PROGMEM = {

145,129,191,131,145,0,0,255};

prog_char sj_feed[] PROGMEM = {

186,128,128,176,0,0,255};

prog_char sj_very[] PROGMEM = {

166,150,7,128,0,0,255};

prog_char sj_after[] PROGMEM = {

132,186,191,7,151,0,0,255};

prog_char sj_me[] PROGMEM = {

140,128,128,0,0,255};

prog_char sj_words[] PROGMEM = {

147,151,176,7,167,0,0,255};

prog_char sj_just[] PROGMEM = {

165,133,187,191,0,0,255};

prog_char sj_cat[] PROGMEM = {

194,132,191,0,0,255};

prog_char sj_where[] PROGMEM = {

147,150,0,0,255};

prog_char sj_most[] PROGMEM = {

140,8,137,187,191,0,0,255};

prog_char sj_know[] PROGMEM = {

142,137,164,0,0,255};

prog_char sj_dead[] PROGMEM = {

174,131,174,0,0,255};

prog_char sj_get[] PROGMEM = {

8,178,8,131,191,0,0,255};

prog_char sj_through[] PROGMEM = {

8,190,148,8,139,0,0,255};

prog_char sj_back[] PROGMEM = {

170,8,132,4,196,0,0,255};

Page 19: #410007091 KaYuLI (MeL) Software Code

prog_char sj_much[] PROGMEM = {

140,134,182,0,0,255};

prog_char sj_go[] PROGMEM = {

8,179,8,164,0,0,255};

prog_char sj_good[] PROGMEM = {

8,179,138,138,177,0,0,255};

prog_char sj_new1[] PROGMEM = {

141,160,0,0,255};

prog_char sj_write[] PROGMEM = {

148,155,191,0,0,255};

PROGMEM const char *SpeakJetDictionary[] = {

sj_the,sj_of,sj_and1,sj_a1,sj_to,sj_in,sj_is,sj_you,sj_that,sj_it,sj

_he,sj_for1,sj_was,sj_on,sj_are,sj_as,

sj_with,sj_his,sj_they,sj_at,sj_be,sj_this1,sj_from,sj_i1,sj_have,

sj_or1,sj_by,sj_one,sj_not1,sj_what,sj_all,

sj_when,sj_we,sj_there,sj_can,sj_an,sj_your,sj_which,sj_their,s

j_if1,sj_do1,sj_will,sj_each,sj_about,sj_how,

sj_up,sj_out,sj_them,sj_then,sj_she,sj_many,sj_some,sj_so,sj_

these,sj_would,sj_other,sj_into,sj_more,sj_her,

sj_two,sj_like,sj_him,sj_see,sj_time,sj_could,sj_no,sj_make,sj_t

han,sj_first,sj_now,sj_people,sj_my,sj_over,

sj_down,sj_only,sj_find,sj_use,sj_may,sj_water,sj_long1,sj_little

,sj_feed,sj_very,sj_after,sj_me,sj_words,

sj_just,sj_cat,sj_where,sj_most,sj_know,sj_dead,sj_get,sj_throu

gh,sj_back,sj_much,sj_go,sj_good,sj_new1,sj_write

};

// SpeakJet lookup table

// Local searchable table to find indices for phoneme strings

char *SpeakJetLookup[] = {

Page 20: #410007091 KaYuLI (MeL) Software Code

"the","of","and","a","to","in","is","you","that","it","he","for","was","

on","are","as","with","his","they","at","be","this",

"from","i","have","or","by","one","not","what","all","when","we","t

here","can","an","your","which","their","if","do","will",

"each","about","how","up","out","them","then","she","many","so

me","so","these","would","other","into","more","her","two","like",

"him","see","time","could","no","make","than","first","now","peopl

e","my","over","down","only","find","use","may","water","long",

"little","feed","very","after","me","words","just","cat","where","mo

st","know","dead","get","through","back","much","go","good",

"new","write"

};

// Flags

char incoming_data;

char SPI_init_flag = 0;

char polling = 0;

char TX_Fifo_Address = THR;

int i = 0;

int j = 0;

int k = 0;

char clr = 0;

struct SPI_UART_cfg

// Defines register values for SC16IS750

{

char DivL,DivM,DataFormat,Flow;

};

struct SPI_UART_cfg SPI_Uart_config = {

0x60,0x00,0x03,0x10};

char auth_level[] = "3";

Page 21: #410007091 KaYuLI (MeL) Software Code

char auth_phrase[] = "56925100";

char port_listen[] = "80";

char ssid[] = "ChocoMocha";

char ip_address[30]; // Stores IP address for SpeakJet

void setup()

{

// SPI Init

pinMode(MOSI, OUTPUT);

pinMode(MISO, INPUT);

pinMode(SCK,OUTPUT);

pinMode(CS,OUTPUT);

digitalWrite(CS,HIGH); //disable device

// SpeakJet Init

pinMode(txPin, OUTPUT);

pinMode(SPK, INPUT);

pinMode(RES, OUTPUT);

// SPI Start

SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);

clr=SPSR;

clr=SPDR;

delay(10);

Serial.begin(9600);

speakjet.begin(9600);

// Reset the SpeakJet

digitalWrite(RES, LOW);

delay(100);

digitalWrite(RES, HIGH);

Serial.println("\n\r\n\rWiFly Shield Terminal Routine");

// Initialize and test the SPI-Uart bridge

if(SPI_Uart_Init()){

Serial.println("Bridge initialized successfully!");

}

else{

Page 22: #410007091 KaYuLI (MeL) Software Code

Serial.println("Could not initialize bridge, locking up.\n\r");

while(1);

}

// Autoconnect to local WiFi using parameters from the global

vars

autoconnect();

}

void loop()

{

// Exit command mode if we haven't already

SPI_Uart_println("exit");

delay(500);

Flush_RX();

while(1)

{

while(!Have_Client()); // Wait on client

Serial.println("\n\rConnection opened.");

// Send HTML

HTML_print("<html>");

HTML_print("<title>SparkFun SpeakJet Server</title>");

HTML_print("<h1><center>");

HTML_print("<img

src=\"http://static.sparkfun.com/images/framework/logo.gif\">");

HTML_print("</center></h1>");

HTML_print("Type some shizz up:");

HTML_print("<form name=\"input\" action=\"\"

method=\"post\">");

HTML_print("<input type=\"text\" name=\"%\" size=\"100\">");

HTML_print("<input type=\"submit\" value=\"Submit\">");

HTML_print("</form>");

// Send word list

HTML_print("<h1>Word List:</h1><p>");

for(int wordn = 0; wordn < WORD_LIST_LENGTH; wordn++)

{

HTML_print(SpeakJetLookup[wordn]);

HTML_print(" ");

}

Page 23: #410007091 KaYuLI (MeL) Software Code

HTML_print("</html>");

delay(500);

// Enter command mode and close connection

SPI_Uart_print("$$$");

delay(500);

SPI_Uart_println("close");

delay(1000);

SPI_Uart_println("exit");

delay(500);

Serial.println("Connection closed.\n\r");

Flush_RX();

}

}

void select(void) // Select SC16IS750

{

digitalWrite(CS,LOW);

}

void deselect(void) // Deselect SC16IS750

{

digitalWrite(CS,HIGH);

}

char Have_Client(void)

{

if(SPI_Uart_ReadByte(LSR) & 0x01){ // Wait for characters

from a connection

Serial.println("Client request...");

is_get = 1;

Parse_Request(); // Check if request is a POST

Flush_RX();

return 1;

}

else{

return 0;

}

}

Page 24: #410007091 KaYuLI (MeL) Software Code

char SPI_Uart_Init(void)

// Initialize SC16IS750

{

char data = 0;

SPI_Uart_WriteByte(LCR,0x80); // 0x80 to program baudrate

SPI_Uart_WriteByte(DLL,SPI_Uart_config.DivL); //0x50 =

9600 with Xtal = 12.288MHz

SPI_Uart_WriteByte(DLM,SPI_Uart_config.DivM);

SPI_Uart_WriteByte(LCR, 0xBF); // access EFR register

SPI_Uart_WriteByte(EFR, SPI_Uart_config.Flow); // enable

enhanced registers

SPI_Uart_WriteByte(LCR, SPI_Uart_config.DataFormat); // 8

data bit, 1 stop bit, no parity

SPI_Uart_WriteByte(FCR, 0x06); // reset TXFIFO, reset

RXFIFO, non FIFO mode

SPI_Uart_WriteByte(FCR, 0x01); // enable FIFO mode

// Perform read/write test to check if UART is working

SPI_Uart_WriteByte(SPR,'H');

data = SPI_Uart_ReadByte(SPR);

if(data == 'H'){

return 1;

}

else{

return 0;

}

}

void SPI_Uart_WriteByte(char address, char data)

// Write single byte to register at <address>

{

long int length;

char senddata[2];

senddata[0] = address;

senddata[1] = data;

Page 25: #410007091 KaYuLI (MeL) Software Code

select();

length = SPI_Write(senddata, 2);

deselect();

}

long int SPI_Write(char* srcptr, long int length)

// Write string to SC16IS750

{

for(long int i = 0; i < length; i++)

{

spi_transfer(srcptr[i]);

}

return length;

}

void SPI_Uart_WriteArray(char *data, long int NumBytes)

// Write string to THR of SC16IS750

{

long int length;

select();

length = SPI_Write(&TX_Fifo_Address,1);

while(NumBytes > 16)

{

length = SPI_Write(data,16);

NumBytes -= 16;

data += 16;

}

length = SPI_Write(data,NumBytes);

deselect();

}

char SPI_Uart_ReadByte(char address)

// Read SC16IS750 register at <address>

{

char data;

address = (address | 0x80);

Page 26: #410007091 KaYuLI (MeL) Software Code

select();

spi_transfer(address);

data = spi_transfer(0xFF);

deselect();

return data;

}

char autoconnect(void)

// Automatically connect to WiFi network using parameters in

global variables

{

// Exit command mode if we haven't already

SPI_Uart_println("");

SPI_Uart_println("exit");

delay(500);

// Enter command mode

SPI_Uart_print("$$$");

delay(500);

// Reboot to get device into known state

Serial.println("Rebooting");

SPI_Uart_println("reboot");

delay(3000);

// Enter command mode

Serial.println("Entering command mode.");

SPI_Uart_print("$$$");

delay(500);

// Set the security authorization level of the WiFly using

<auth_level>

SPI_Uart_print("set w a ");

SPI_Uart_println(auth_level);

delay(500);

Serial.print("Set wlan to authorization level ");

Serial.println(auth_level);

// Set the WiFly authorization phrase using <auth_phrase>

SPI_Uart_print("set w p ");

Page 27: #410007091 KaYuLI (MeL) Software Code

SPI_Uart_println(auth_phrase);

delay(500);

Serial.print("Set security phrase to ");

Serial.println(auth_phrase);

// Set the WiFly localport using <port_listen>

SPI_Uart_print("set i l ");

SPI_Uart_println(port_listen);

delay(500);

Serial.print("Set IP localport to ");

Serial.println(port_listen);

// Turn off WiFly UART connection indicators

SPI_Uart_println("set comm remote 0");

delay(500);

SPI_Uart_println("set comm open 0");

delay(500);

SPI_Uart_println("set comm close 0");

delay(500);

// Join WiFi network <ssid>

Serial.print("Joining '");

Serial.print(ssid);

Serial.println("'");

delay(100);

Flush_RX();

delay(100);

SPI_Uart_print("join ");

SPI_Uart_println(ssid);

for(int p = 0; p < 5; p++) // Give WiFly time to associate

{

Serial.print(".");

speakjet.print(ping);

delay(ASSOCIATE_TIMEOUT/5);

}

Serial.println("");

// Flush characters from SC16IS750

Flush_RX();

Page 28: #410007091 KaYuLI (MeL) Software Code

// Check for association

SPI_Uart_println("show c");

if(Wait_On_Response_Char(13) != '0')

// Failed, try again

{

Serial.print("Failed to associate with '");

Serial.print(ssid);

Serial.println("'\n\rRetrying...");

Flush_RX();

autoconnect();

}

else

// Success, SpeakJet says "Associated" and IP address

{

Serial.println("Associated!");

speakjet.print(message);

delay(1000);

SPI_Uart_println("get ip");

get_ip();

}

}

void Flush_RX(void)

// Flush characters from the SC16IS750 so we only see what

we want to see on the terminal

{

int j = 0;

while(j < 4000)

{

if((SPI_Uart_ReadByte(LSR) & 0x01))

{

incoming_data = SPI_Uart_ReadByte(RHR);

}

else

{

j++;

}

}

}

Page 29: #410007091 KaYuLI (MeL) Software Code

void Parse_Request(void)

// Parse POST data into separate words, look up, and "say"

words using SpeakJet

{

int j = 0, i = 0, k = 0;

char a = 0;

char printflag = 0;

char message[128];

char poem_word[16] = {

0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

char buffer[16] = {

0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

char sentinel = 0;

while(j < 4000) // Read in full message

{

if((SPI_Uart_ReadByte(LSR) & 0x01))

{

incoming_data = SPI_Uart_ReadByte(RHR);

if(printflag){

message[i-3] = incoming_data;

i++;

}

else if(incoming_data == '%'){

printflag = 1;

}

}

else

{

j++;

}

}

i -= 3;

j = 0;

while(k<i) // Split <message> into words and say

{

while(message[k] != '+' && k < i)

{

poem_word[j] = message[k];

k++;

j++;

Page 30: #410007091 KaYuLI (MeL) Software Code

}

k++;

for(int index = 0; index < WORD_LIST_LENGTH; index++)

{

if(strcmp(poem_word,SpeakJetLookup[index]) == 0) // Look

up word in SpeakJetLookup

{

// Serial.print(index,DEC); // Print index of word for

debugging

strcpy_P(buffer,

(char*)pgm_read_word(&(SpeakJetDictionary[index]))); // Copy

word from program memory using lookup index

speakjet.print(buffer); // Send string to the VoiceBox

is_get = 0; // Flag as POST request

delay(600); // Wait in between words

}

}

j = 0;

for(char c = 0; c < 16; c++){ // Clear buffers

poem_word[c] = 0;

buffer[c] = 0;

}

}

}

char Wait_On_Response_Char(char num)

// Check for character number <num> from a response string

{

i = 1;

while(1)

{

if((SPI_Uart_ReadByte(LSR) & 0x01))

{

incoming_data = SPI_Uart_ReadByte(RHR);

//Serial.print(incoming_data, BYTE); // Print data for

debugging

if(i == num){

return incoming_data;

}

else{

Page 31: #410007091 KaYuLI (MeL) Software Code

i++;

}

}

}

}

void SPI_Uart_println(char *data)

// Write <data> to THR of SC16IS750 followed by a carriage

return

{

SPI_Uart_WriteArray(data,strlen(data));

SPI_Uart_WriteByte(THR, 0x0d);

}

void HTML_print(char *data)

// Write <data> to THR of SC16IS750 followed by a delay

{

SPI_Uart_WriteArray(data,strlen(data));

delay(30);

}

void SPI_Uart_print(char *data)

// Obfuscation of SPI_Uart_WriteArray that uses strlen instead

of hardcoded length

{

SPI_Uart_WriteArray(data,strlen(data));

}

char spi_transfer(volatile char data)

{

SPDR = data; // Start the transmission

while (!(SPSR & (1<<SPIF))) // Wait for the end of the

transmission

{

};

return SPDR; // return the received byte

}

void get_ip(void)

// Parse out IP address of WiFly and "say" it with the speakjet

Page 32: #410007091 KaYuLI (MeL) Software Code

{

char returns = 0;

char ip_index = 0;

char a = 0;

// Parse

while(returns < 6)

{

if((SPI_Uart_ReadByte(LSR) & 0x01))

{

incoming_data = SPI_Uart_ReadByte(RHR);

if(incoming_data == 0x0d)

{

returns++;

}

if(returns > 4)

{

//Serial.print(incoming_data,BYTE);

ip_address[ip_index] = incoming_data;

ip_index++;

}

}

}

delay(1000);

// Say IP address

while(ip_address[a] != ':')

{

if(a < 5){

}

else if(ip_address[a] == '.'){

Serial.print(ip_address[a]);

speakjet.print(dot);

delay(500);

}

else{

Serial.print(ip_address[a]);

speakjet.print(numbers[(ip_address[a] - 48)]);

delay(500);

}

a++;

Page 33: #410007091 KaYuLI (MeL) Software Code

}

Serial.println("");

Flush_RX(); // Do not print characters

}

Step 3:

Code to test the basic 16x2

character LCD

/*

LiquidCrystal Library - Hello World

Demonstrates the use a 16x2 LCD display. The LiquidCrystal

library works with all LCD displays that are compatible with the

Hitachi HD44780 driver. There are many of them out there,

and you

can usually tell them by the 16-pin interface.

This sketch prints "Hello World!" to the LCD

and shows the time.

The circuit:

* LCD RS pin to digital pin 12

* LCD Enable pin to digital pin 11

* LCD D4 pin to digital pin 5

* LCD D5 pin to digital pin 4

* LCD D6 pin to digital pin 3

* LCD D7 pin to digital pin 2

* LCD R/W pin to ground

* 10K resistor:

* ends to +5V and ground

* wiper to LCD VO pin (pin 3)

Library originally added 18 Apr 2008

by David A. Mellis

library modified 5 Jul 2009

by Limor Fried (http://www.ladyada.net)

example added 9 Jul 2009

by Tom Igoe

modified 22 Nov 2010

by Tom Igoe

This example code is in the public domain.

Page 34: #410007091 KaYuLI (MeL) Software Code

http://www.arduino.cc/en/Tutorial/LiquidCrystal

*/

// include the library code:

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {

// set up the LCD's number of columns and rows:

lcd.begin(16, 2);

// Print a message to the LCD.

lcd.print("hello, world!");

}

void loop() {

// set the cursor to column 0, line 1

// (note: line 1 is the second row, since counting begins with

0):

//lcd.setCursor(0, 1);

// print the number of seconds since reset:

//lcd.print(millis()/1000);

}

Last step:

Code that combined all

code

/*

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.

Page 35: #410007091 KaYuLI (MeL) Software Code

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

Page 36: #410007091 KaYuLI (MeL) Software Code

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 the library code:

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins

//LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

LiquidCrystal lcd(5, 4, 13, 3, 11, 12);

#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.

Page 37: #410007091 KaYuLI (MeL) Software Code

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

Page 38: #410007091 KaYuLI (MeL) Software Code

// set up the LCD's number of columns and rows:

lcd.begin(16, 1);

// Print a message to the LCD.

lcd.print("mushion");

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

Page 39: #410007091 KaYuLI (MeL) Software Code

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(0, 0); //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

Page 40: #410007091 KaYuLI (MeL) Software Code

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

/*lcd.setCursor(0, 1);

// print the number of seconds since reset:

lcd.print(millis()/1000);*/

Serial.println (analogRead (0), DEC);

if (analogRead (0) > 800)

{

Serial.println ("LED on");

digitalWrite (13, 255);

}

if (analogRead (0) < 800)

{

Serial.println ("LED off");

digitalWrite (13, 0);

}

Page 41: #410007091 KaYuLI (MeL) Software Code

if(analogRead(0) > 800)

{

Serial.println("pushed!!!!!! HEARTBEATS ON");

//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

/*Serial.println ("LED on");

digitalWrite (13, 255);*/

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

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");

Page 42: #410007091 KaYuLI (MeL) Software Code

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

Page 43: #410007091 KaYuLI (MeL) Software Code

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

Page 44: #410007091 KaYuLI (MeL) Software Code

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

Page 45: #410007091 KaYuLI (MeL) Software Code

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);

}