Read an wav file from sdcard and play it through I2S on LPC4088 QSB platform

Dependencies:   EALib I2SSlave TLV320 mbed

Fork of playback by Daniel Worrall

works with 16bits / 44,1 khz files.

I'm going to work on 24/32 bits, 48khz 96 khz files...

Committer:
Grag38
Date:
Sat Jul 23 21:29:39 2016 +0000
Revision:
2:ce93bf118649
Parent:
0:3d6892f6384f
This example project works with the LPC4088 QSB.; It reads a wav file from the sdcard (libs are in the EALib from Embedded Artist) and output it to the dac (TLV320 as RS-Audio board).; ; Hope it will helps who works with I2S with LPC4088

Who changed what in which revision?

UserRevisionLine numberNew contents of line
d_worrall 0:3d6892f6384f 1 #include "mbed.h"
d_worrall 0:3d6892f6384f 2 #include "TLV320.h"
Grag38 2:ce93bf118649 3
Grag38 2:ce93bf118649 4 Serial pc(USBTX, USBRX);
d_worrall 0:3d6892f6384f 5
Grag38 2:ce93bf118649 6 /******************************************************************************
Grag38 2:ce93bf118649 7 * Includes
Grag38 2:ce93bf118649 8 *****************************************************************************/
Grag38 2:ce93bf118649 9 #include "MCIFileSystem.h"
Grag38 2:ce93bf118649 10
Grag38 2:ce93bf118649 11 /******************************************************************************
Grag38 2:ce93bf118649 12 * Typedefs and defines
Grag38 2:ce93bf118649 13 *****************************************************************************/
Grag38 2:ce93bf118649 14
Grag38 2:ce93bf118649 15 typedef bool (*syncFunc)(const char* name, bool isDir);
Grag38 2:ce93bf118649 16
Grag38 2:ce93bf118649 17 /******************************************************************************
Grag38 2:ce93bf118649 18 * Local variables
Grag38 2:ce93bf118649 19 *****************************************************************************/
Grag38 2:ce93bf118649 20
Grag38 2:ce93bf118649 21 MCIFileSystem mcifs("mci");
Grag38 2:ce93bf118649 22
Grag38 2:ce93bf118649 23 DigitalOut myled1(LED1);
Grag38 2:ce93bf118649 24 DigitalOut myled2(LED2);
Grag38 2:ce93bf118649 25
Grag38 2:ce93bf118649 26 /******************************************************************************
Grag38 2:ce93bf118649 27 * Local functions
Grag38 2:ce93bf118649 28 *****************************************************************************/
Grag38 2:ce93bf118649 29
Grag38 2:ce93bf118649 30 static void ledShowProgress()
Grag38 2:ce93bf118649 31 {
Grag38 2:ce93bf118649 32 static int state = 0;
Grag38 2:ce93bf118649 33 state = (state + 1) % 2;
Grag38 2:ce93bf118649 34 switch (state)
Grag38 2:ce93bf118649 35 {
Grag38 2:ce93bf118649 36 case 0:
Grag38 2:ce93bf118649 37 myled1 = 1;
Grag38 2:ce93bf118649 38 myled2 = 0;
Grag38 2:ce93bf118649 39 break;
Grag38 2:ce93bf118649 40
Grag38 2:ce93bf118649 41 case 1:
Grag38 2:ce93bf118649 42 default:
Grag38 2:ce93bf118649 43 myled1 = 0;
Grag38 2:ce93bf118649 44 myled2 = 1;
Grag38 2:ce93bf118649 45 }
Grag38 2:ce93bf118649 46 }
Grag38 2:ce93bf118649 47
Grag38 2:ce93bf118649 48 static void handleError(const char* msg)
Grag38 2:ce93bf118649 49 {
Grag38 2:ce93bf118649 50 printf(msg);
Grag38 2:ce93bf118649 51 while(true) {
Grag38 2:ce93bf118649 52 myled1 = 1;
Grag38 2:ce93bf118649 53 myled2 = 1;
Grag38 2:ce93bf118649 54 wait(0.3);
Grag38 2:ce93bf118649 55 myled1 = 0;
Grag38 2:ce93bf118649 56 myled2 = 0;
Grag38 2:ce93bf118649 57 wait(0.3);
Grag38 2:ce93bf118649 58 }
Grag38 2:ce93bf118649 59 }
Grag38 2:ce93bf118649 60
Grag38 2:ce93bf118649 61 static bool recursiveProcessFS(char* buff, const char* name, syncFunc func, bool adding)
Grag38 2:ce93bf118649 62 {
Grag38 2:ce93bf118649 63 uint32_t len = strlen(buff);
Grag38 2:ce93bf118649 64 if (len > 0) {
Grag38 2:ce93bf118649 65 if (buff[len - 1] != '/') {
Grag38 2:ce93bf118649 66 buff[len++] = '/';
Grag38 2:ce93bf118649 67 buff[len] = '\0';
Grag38 2:ce93bf118649 68 }
Grag38 2:ce93bf118649 69 }
Grag38 2:ce93bf118649 70 strcat(buff, name);
Grag38 2:ce93bf118649 71 len += strlen(name);
Grag38 2:ce93bf118649 72
Grag38 2:ce93bf118649 73 if (len > 60) {
Grag38 2:ce93bf118649 74 // ugly fix to avoid crashes that occurs when file name is larger than buffer
Grag38 2:ce93bf118649 75 // in FATFileSystem.
Grag38 2:ce93bf118649 76 printf("skipped: %s\n", buff);
Grag38 2:ce93bf118649 77 return true;
Grag38 2:ce93bf118649 78 }
Grag38 2:ce93bf118649 79
Grag38 2:ce93bf118649 80 DIR *d = opendir(buff);
Grag38 2:ce93bf118649 81 bool result = true; // success
Grag38 2:ce93bf118649 82 if (d != NULL) {
Grag38 2:ce93bf118649 83 if (adding) {
Grag38 2:ce93bf118649 84 // when processing in adding mode folders must be created before it's content
Grag38 2:ce93bf118649 85 result = func(buff, true);
Grag38 2:ce93bf118649 86 }
Grag38 2:ce93bf118649 87 struct dirent *p;
Grag38 2:ce93bf118649 88 while (result && ((p = readdir(d)) != NULL)) {
Grag38 2:ce93bf118649 89 result = recursiveProcessFS(buff, p->d_name, func, adding);
Grag38 2:ce93bf118649 90 buff[len] = '\0';
Grag38 2:ce93bf118649 91 }
Grag38 2:ce93bf118649 92 closedir(d);
Grag38 2:ce93bf118649 93 if (result && !adding) {
Grag38 2:ce93bf118649 94 // when processing in removing mode folders must be deleted after it's content
Grag38 2:ce93bf118649 95 result = func(buff, true);
Grag38 2:ce93bf118649 96 }
Grag38 2:ce93bf118649 97 } else {
Grag38 2:ce93bf118649 98 // a file
Grag38 2:ce93bf118649 99 result = func(buff, false);
Grag38 2:ce93bf118649 100 }
Grag38 2:ce93bf118649 101 return result;
Grag38 2:ce93bf118649 102 }
Grag38 2:ce93bf118649 103
Grag38 2:ce93bf118649 104 static uint32_t fileLen(FILE* f)
Grag38 2:ce93bf118649 105 {
Grag38 2:ce93bf118649 106 uint32_t pos = ftell(f);
Grag38 2:ce93bf118649 107 fseek(f, 0, SEEK_END);
Grag38 2:ce93bf118649 108 uint32_t size = ftell(f);
Grag38 2:ce93bf118649 109 fseek(f, pos, SEEK_SET);
Grag38 2:ce93bf118649 110 return size;
Grag38 2:ce93bf118649 111 }
Grag38 2:ce93bf118649 112
Grag38 2:ce93bf118649 113 static bool copyFH(FILE* fSrc, FILE* fDst)
Grag38 2:ce93bf118649 114 {
Grag38 2:ce93bf118649 115 char buff[512];
Grag38 2:ce93bf118649 116 uint32_t left = fileLen(fSrc);
Grag38 2:ce93bf118649 117 uint32_t num;
Grag38 2:ce93bf118649 118 uint32_t chunk;
Grag38 2:ce93bf118649 119
Grag38 2:ce93bf118649 120 fseek(fSrc, 0, SEEK_SET);
Grag38 2:ce93bf118649 121 do {
Grag38 2:ce93bf118649 122 chunk = (left < 512) ? left : 512;
Grag38 2:ce93bf118649 123 num = fread(buff, 1, chunk, fSrc);
Grag38 2:ce93bf118649 124 if (num > 0) {
Grag38 2:ce93bf118649 125 uint32_t tmp = fwrite(buff, 1, num, fDst);
Grag38 2:ce93bf118649 126 if (tmp != num) {
Grag38 2:ce93bf118649 127 // failed to write
Grag38 2:ce93bf118649 128 return false;
Grag38 2:ce93bf118649 129 }
Grag38 2:ce93bf118649 130 left -= num;
Grag38 2:ce93bf118649 131 ledShowProgress();
Grag38 2:ce93bf118649 132 }
Grag38 2:ce93bf118649 133 } while(num > 0 && left > 0);
Grag38 2:ce93bf118649 134
Grag38 2:ce93bf118649 135 // copied entire file
Grag38 2:ce93bf118649 136 return true;
Grag38 2:ce93bf118649 137 }
Grag38 2:ce93bf118649 138
Grag38 2:ce93bf118649 139 static bool copy(const char* fnameSrc, const char* fnameDest)
Grag38 2:ce93bf118649 140 {
Grag38 2:ce93bf118649 141 FILE* fhSrc = NULL;
Grag38 2:ce93bf118649 142 FILE* fhDest = NULL;
Grag38 2:ce93bf118649 143 bool success = false;
Grag38 2:ce93bf118649 144
Grag38 2:ce93bf118649 145 do {
Grag38 2:ce93bf118649 146 fhSrc = fopen(fnameSrc, "r");
Grag38 2:ce93bf118649 147 if (fhSrc == NULL) {
Grag38 2:ce93bf118649 148 break;
Grag38 2:ce93bf118649 149 }
Grag38 2:ce93bf118649 150
Grag38 2:ce93bf118649 151 fhDest = fopen(fnameDest, "w");
Grag38 2:ce93bf118649 152 if (fhDest == NULL) {
Grag38 2:ce93bf118649 153 break;
Grag38 2:ce93bf118649 154 }
Grag38 2:ce93bf118649 155
Grag38 2:ce93bf118649 156 if (!copyFH(fhSrc, fhDest)) {
Grag38 2:ce93bf118649 157 break;
Grag38 2:ce93bf118649 158 }
Grag38 2:ce93bf118649 159
Grag38 2:ce93bf118649 160 success = true;
Grag38 2:ce93bf118649 161 } while (false);
Grag38 2:ce93bf118649 162
Grag38 2:ce93bf118649 163 if (fhSrc != NULL) {
Grag38 2:ce93bf118649 164 fclose(fhSrc);
Grag38 2:ce93bf118649 165 }
Grag38 2:ce93bf118649 166 if (fhDest != NULL) {
Grag38 2:ce93bf118649 167 fclose(fhDest);
Grag38 2:ce93bf118649 168 }
Grag38 2:ce93bf118649 169
Grag38 2:ce93bf118649 170 return success;
Grag38 2:ce93bf118649 171 }
Grag38 2:ce93bf118649 172
Grag38 2:ce93bf118649 173 static bool list(const char* name, bool isDir)
Grag38 2:ce93bf118649 174 {
Grag38 2:ce93bf118649 175 if (isDir) {
Grag38 2:ce93bf118649 176 printf("d: %s\n", name);
Grag38 2:ce93bf118649 177 } else {
Grag38 2:ce93bf118649 178 FILE* f = fopen(name, "r");
Grag38 2:ce93bf118649 179 if (f != NULL) {
Grag38 2:ce93bf118649 180 uint32_t len = fileLen(f);
Grag38 2:ce93bf118649 181 printf("f: %7u %s\n", len, name);
Grag38 2:ce93bf118649 182 fclose(f);
Grag38 2:ce93bf118649 183 } else {
Grag38 2:ce93bf118649 184 printf("f: ??? %s\n", name);
Grag38 2:ce93bf118649 185 }
Grag38 2:ce93bf118649 186 }
Grag38 2:ce93bf118649 187 return true;
Grag38 2:ce93bf118649 188 }
Grag38 2:ce93bf118649 189
Grag38 2:ce93bf118649 190 static void recursiveList(const char* dirname)
Grag38 2:ce93bf118649 191 {
Grag38 2:ce93bf118649 192 printf("\nRecursive list of file and folders in %s\n", dirname);
Grag38 2:ce93bf118649 193 char* buff = (char*)malloc(512);
Grag38 2:ce93bf118649 194 if (buff != NULL)
Grag38 2:ce93bf118649 195 {
Grag38 2:ce93bf118649 196 buff[0] = '\0';
Grag38 2:ce93bf118649 197 recursiveProcessFS(buff, dirname, list, true);
Grag38 2:ce93bf118649 198 free(buff);
Grag38 2:ce93bf118649 199 }
Grag38 2:ce93bf118649 200 }
Grag38 2:ce93bf118649 201
Grag38 2:ce93bf118649 202 static void testAppend(const char* filename)
Grag38 2:ce93bf118649 203 {
Grag38 2:ce93bf118649 204 FILE *fp = fopen(filename, "a");
Grag38 2:ce93bf118649 205 if (fp != NULL) {
Grag38 2:ce93bf118649 206 fprintf(fp, "Hello World!");
Grag38 2:ce93bf118649 207 fclose(fp);
Grag38 2:ce93bf118649 208 }
Grag38 2:ce93bf118649 209 }
Grag38 2:ce93bf118649 210
Grag38 2:ce93bf118649 211 /******************************************************************************
Grag38 2:ce93bf118649 212 * TestSdCard function
Grag38 2:ce93bf118649 213 *****************************************************************************/
Grag38 2:ce93bf118649 214
Grag38 2:ce93bf118649 215 int TestSdCard()
Grag38 2:ce93bf118649 216 {
Grag38 2:ce93bf118649 217 printf("\n-----------------\n\nWelcome to the MCI file system example...\n");
Grag38 2:ce93bf118649 218
Grag38 2:ce93bf118649 219 if (!mcifs.cardInserted()) {
Grag38 2:ce93bf118649 220 printf("Please insert a SD/MMC card...\n");
Grag38 2:ce93bf118649 221 while (!mcifs.cardInserted()) {
Grag38 2:ce93bf118649 222 wait(0.5);
Grag38 2:ce93bf118649 223 }
Grag38 2:ce93bf118649 224 printf("Card detected!\n");
Grag38 2:ce93bf118649 225 }
Grag38 2:ce93bf118649 226
Grag38 2:ce93bf118649 227 recursiveList("/mci/");
Grag38 2:ce93bf118649 228
Grag38 2:ce93bf118649 229 copy("/mci/expanding.txt", "/mci/expanding.old");
Grag38 2:ce93bf118649 230 testAppend("/mci/expanding.txt");
Grag38 2:ce93bf118649 231
Grag38 2:ce93bf118649 232 //recursiveList("/mci/");
Grag38 2:ce93bf118649 233
Grag38 2:ce93bf118649 234
Grag38 2:ce93bf118649 235
Grag38 2:ce93bf118649 236 printf("Found SD/MMC card, writing to /mci/myfile.txt ...\n");
Grag38 2:ce93bf118649 237
Grag38 2:ce93bf118649 238 Timer t;
Grag38 2:ce93bf118649 239
Grag38 2:ce93bf118649 240 t.start();
Grag38 2:ce93bf118649 241
Grag38 2:ce93bf118649 242 FILE *fp = fopen("/mci/myfile.txt", "w");
Grag38 2:ce93bf118649 243 if (fp != NULL)
Grag38 2:ce93bf118649 244 {
Grag38 2:ce93bf118649 245 for (long i=0; i<100000L; i++)
Grag38 2:ce93bf118649 246 fprintf(fp, "Hello World!\n");
Grag38 2:ce93bf118649 247 fclose(fp);
Grag38 2:ce93bf118649 248 printf("Wrote to /mci/myfile.txt\n");
Grag38 2:ce93bf118649 249 } else {
Grag38 2:ce93bf118649 250 printf("Failed to open /mci/myfile.txt\n");
Grag38 2:ce93bf118649 251 }
Grag38 2:ce93bf118649 252 t.stop();
Grag38 2:ce93bf118649 253
Grag38 2:ce93bf118649 254 printf("The time taken was %f seconds\n", t.read());
Grag38 2:ce93bf118649 255
Grag38 2:ce93bf118649 256
Grag38 2:ce93bf118649 257 handleError("Program completed!\n");
Grag38 2:ce93bf118649 258 return 1;
Grag38 2:ce93bf118649 259 }
Grag38 2:ce93bf118649 260
Grag38 2:ce93bf118649 261
Grag38 2:ce93bf118649 262
Grag38 2:ce93bf118649 263 TLV320 audio(p9, p10, 52, p11, p12, p13, p14, p16); //TLV320 object
Grag38 2:ce93bf118649 264
d_worrall 0:3d6892f6384f 265 InterruptIn volumeSet(p17);
d_worrall 0:3d6892f6384f 266 AnalogIn aIn(p19);
d_worrall 0:3d6892f6384f 267 FILE *infp; //File pointer object
d_worrall 0:3d6892f6384f 268 /* Buffers */
d_worrall 0:3d6892f6384f 269 int circularBuffer[4096];
d_worrall 0:3d6892f6384f 270 volatile int readPointer = 0;
d_worrall 0:3d6892f6384f 271 volatile int theta = 0;
d_worrall 0:3d6892f6384f 272 /* Wav file header data, for setting up the transfer protocol */
d_worrall 0:3d6892f6384f 273 short channels;
d_worrall 0:3d6892f6384f 274 long sampleRate;
d_worrall 0:3d6892f6384f 275 short wordWidth;
d_worrall 0:3d6892f6384f 276 /* Function to set volume*/
d_worrall 0:3d6892f6384f 277 void setVolume(void){
d_worrall 0:3d6892f6384f 278 audio.outputVolume(aIn, aIn);
d_worrall 0:3d6892f6384f 279 }
d_worrall 0:3d6892f6384f 280 /* Function to read from circular buffer and send data to TLV320 */
d_worrall 0:3d6892f6384f 281 void play(void){
d_worrall 0:3d6892f6384f 282 audio.write(circularBuffer, readPointer, 8);
d_worrall 0:3d6892f6384f 283 //Pointer fun :-)
d_worrall 0:3d6892f6384f 284 readPointer += 8;
d_worrall 0:3d6892f6384f 285 readPointer &= 0xfff;
d_worrall 0:3d6892f6384f 286 theta -= 8;
d_worrall 0:3d6892f6384f 287 }
d_worrall 0:3d6892f6384f 288 /* Function to load circular buffer from SD Card */
d_worrall 0:3d6892f6384f 289 void fillBuffer(void){
d_worrall 0:3d6892f6384f 290 while(!feof(infp)){ //fill the circular buffer until the end of the file
d_worrall 0:3d6892f6384f 291 static volatile int writePointer = 0;
d_worrall 0:3d6892f6384f 292 if(theta < 4096){
d_worrall 0:3d6892f6384f 293 fread(&circularBuffer[writePointer], 4, 4, infp); //read 4 integers into the circular buffer at a time
d_worrall 0:3d6892f6384f 294 //More pointer fun :D
d_worrall 0:3d6892f6384f 295 theta+=4;
d_worrall 0:3d6892f6384f 296 writePointer+=4;
d_worrall 0:3d6892f6384f 297 writePointer &= 0xfff;
d_worrall 0:3d6892f6384f 298 }
d_worrall 0:3d6892f6384f 299 }
d_worrall 0:3d6892f6384f 300 }
d_worrall 0:3d6892f6384f 301 /* main */
Grag38 2:ce93bf118649 302 int main()
Grag38 2:ce93bf118649 303 {
Grag38 2:ce93bf118649 304 pc.baud(460800);
Grag38 2:ce93bf118649 305
Grag38 2:ce93bf118649 306 infp = fopen("/mci/agnes.wav","rb");
d_worrall 0:3d6892f6384f 307 if(infp == NULL){ //make sure it's been opened
d_worrall 0:3d6892f6384f 308 perror("Error opening file!");
d_worrall 0:3d6892f6384f 309 exit(1);
d_worrall 0:3d6892f6384f 310 }
d_worrall 0:3d6892f6384f 311 /* Parse wav file header */
d_worrall 0:3d6892f6384f 312 fseek(infp, 22, SEEK_SET);
d_worrall 0:3d6892f6384f 313 fread(&channels, 2, 1, infp);
d_worrall 0:3d6892f6384f 314 fseek(infp, 24, SEEK_SET);
d_worrall 0:3d6892f6384f 315 fread(&sampleRate, 4, 1, infp);
d_worrall 0:3d6892f6384f 316 fseek(infp, 34, SEEK_SET);
d_worrall 0:3d6892f6384f 317 fread(&wordWidth, 2, 1, infp);
d_worrall 0:3d6892f6384f 318
d_worrall 0:3d6892f6384f 319 volumeSet.rise(&setVolume); //attach set volume function to digital input
d_worrall 0:3d6892f6384f 320 audio.power(0x07); //power up TLV apart from analogue input
d_worrall 0:3d6892f6384f 321 audio.frequency(sampleRate); //set sample frequency
d_worrall 0:3d6892f6384f 322 audio.format(wordWidth, (2-channels)); //set transfer protocol
d_worrall 0:3d6892f6384f 323 audio.attach(&play); //attach interrupt handler to send data to TLV320
d_worrall 0:3d6892f6384f 324 for(int j = 0; j < 4096; ++j){ //upon interrupt generation
d_worrall 0:3d6892f6384f 325 circularBuffer[j] = 0; //clear circular buffer
d_worrall 0:3d6892f6384f 326 }
d_worrall 0:3d6892f6384f 327 audio.start(TRANSMIT); //interrupt come from the I2STXFIFO only
d_worrall 0:3d6892f6384f 328 fillBuffer(); //continually fill circular buffer
d_worrall 0:3d6892f6384f 329 }