Subversion Repositories Code-Repo

Rev

Rev 251 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
248 Kevin 1
/*
2
 
3
    VLSI Solution generic microcontroller example player / recorder for
4
    VS1053.
5
 
6
    v1.03 2012-12-11 HH  Recording command 'p' was VS1063 only -> removed
7
                                             Added chip type recognition
8
    v1.02 2012-12-04 HH  Command '_' incorrectly printed VS1063-specific fields
9
    v1.01 2012-11-28 HH  Untabified
10
    v1.00 2012-11-27 HH  First release
11
 
12
*/
13
 
14
#include "player.h"
15
#include "hal_SPI.h"
16
#include "hal_hardware_board.h"
17
#include "pff.h"
18
 
19
/* Download the latest VS1053a Patches package and its
20
     vs1053b-patches-flac.plg. If you want to use the smaller patch set
21
     which doesn't contain the FLAC decoder, use vs1053b-patches.plg instead.
22
     The patches package is available at
23
     http://www.vlsi.fi/en/support/software/vs10xxpatches.html */
24
//#include "vs1053b-patches.plg"
25
// Extracted plugin contents:
26
#define PLUGIN_SIZE 40
27
const unsigned short plugin[40] = { /* Compressed plugin */
28
        0x0007, 0x0001, 0x8010, 0x0006, 0x001c, 0x3e12, 0xb817, 0x3e14, /*    0 */
29
        0xf812, 0x3e01, 0xb811, 0x0007, 0x9717, 0x0020, 0xffd2, 0x0030, /*    8 */
30
        0x11d1, 0x3111, 0x8024, 0x3704, 0xc024, 0x3b81, 0x8024, 0x3101, /*   10 */
31
        0x8024, 0x3b81, 0x8024, 0x3f04, 0xc024, 0x2808, 0x4800, 0x36f1, /*   18 */
32
        0x9811, 0x0007, 0x0001, 0x8028, 0x0006, 0x0002, 0x2a00, 0x040e,
33
};
34
 
35
 
36
/* We also want to have the VS1053b Ogg Vorbis Encoder plugin. To get more
37
     than one plugin included, we'll have to include it in a slightly more
38
     tricky way. To get the plugin included below, download the latest version
39
     of the VS1053 Ogg Vorbis Encoder Application from
40
     http://www.vlsi.fi/en/support/software/vs10xxapplications.html */
41
// #define SKIP_PLUGIN_VARNAME
42
// const unsigned int encoderPlugin[] = {
43
// #include "venc44k2q05.plg"
44
// };
45
// #undef SKIP_PLUGIN_VARNAME
46
 
47
 
48
/* VS1053b IMA ADPCM Encoder Fix, available at
49
     http://www.vlsi.fi/en/support/software/vs10xxpatches.html */
50
// #define SKIP_PLUGIN_VARNAME
51
// const unsigned int imaFix[] = {
52
// #include "imafix.plg"
53
// };
54
// #undef SKIP_PLUGIN_VARNAME
55
 
56
 
57
#define FILE_BUFFER_SIZE        224  // Minimum 32!
58
#define SDI_MAX_TRANSFER_SIZE   32
59
#define SDI_END_FILL_BYTES_FLAC 12288
60
#define SDI_END_FILL_BYTES      2052
251 Kevin 61
//#define REC_BUFFER_SIZE         224
248 Kevin 62
 
63
#define REPORT_INTERVAL 4096
64
#define REPORT_INTERVAL_MIDI 512
65
 
66
#define min(a,b) (((a)<(b))?(a):(b))
67
 
68
enum AudioFormat {
69
    afUnknown,
70
    afRiff,
71
    afOggVorbis,
72
    afMp1,
73
    afMp2,
74
    afMp3,
75
    afAacMp4,
76
    afAacAdts,
77
    afAacAdif,
78
    afFlac,
79
    afWma,
80
    afMidi
81
} audioFormat = afUnknown;
82
 
83
const char *afName[] = {
84
    "unknown",
85
    "RIFF",
86
    "Ogg",
87
    "MP1",
88
    "MP2",
89
    "MP3",
90
    "AAC MP4",
91
    "AAC ADTS",
92
    "AAC ADIF",
93
    "FLAC",
94
    "WMA",
95
    "MIDI",
96
};
97
 
98
/*
99
 * SCI Write
100
 */
101
void WriteSci(unsigned char addr, unsigned int data) {
102
    unsigned char c;
103
    do {                    // Wait until DREQ is high
104
        c = VS10XX_DREQ_STAT();
105
    } while (c == 0);
106
    VS10XX_CS_LOW();
107
    spiSendByte(0x02);      // Write command code
108
    spiSendByte(addr);      // Write SCI register
109
    spiSendByte((unsigned char)(data >> 8));
110
    spiSendByte((unsigned char)(data & 0xFF));
111
    VS10XX_CS_HIGH();
112
}
113
 
114
/*
115
 * SCI Read
116
 */
117
unsigned int ReadSci(unsigned char addr) {
118
    unsigned char buffer[2];
119
    int ret;
120
 
121
    unsigned char c;
122
    do {                    // Wait until DREQ is high
123
        c = VS10XX_DREQ_STAT();
124
    } while (c == 0);
125
    VS10XX_CS_LOW();
126
    spiSendByte(0x03);      // Write command code
127
    spiSendByte(addr);      // Write SCI register
128
    spiReadFrame(buffer, 2);
129
    ret = buffer[0] << 8;
130
    ret |= buffer[1];
131
    VS10XX_CS_HIGH();
132
 
133
    return ret;
134
}
135
 
136
/*
137
 * SDI Write
138
 */
139
int WriteSdi(unsigned char *data, unsigned char bytes) {
140
    if (bytes > SDI_MAX_TRANSFER_SIZE)
141
        return -1;
142
 
143
    unsigned char c;
144
    do {                    // Wait until DREQ is high
145
        c = VS10XX_DREQ_STAT();
146
    } while (c == 0);
147
    VS10XX_DS_LOW();
148
    spiSendFrame(data, (unsigned int)bytes);
149
    VS10XX_DS_HIGH();
150
 
151
    return 0;
152
}
153
 
154
/*
155
    Read 32-bit increasing counter value from addr.
156
    Because the 32-bit value can change while reading it,
157
    read MSB's twice and decide which is the correct one.
158
*/
159
unsigned long ReadVS10xxMem32Counter(unsigned int addr) {
160
    unsigned int msbV1, lsb, msbV2;
161
    unsigned long res;
162
 
163
    WriteSci(SCI_WRAMADDR, addr+1);
164
    msbV1 = ReadSci(SCI_WRAM);
165
    WriteSci(SCI_WRAMADDR, addr);
166
    lsb = ReadSci(SCI_WRAM);
167
    msbV2 = ReadSci(SCI_WRAM);
168
    if (lsb < 0x8000U) {
169
        msbV1 = msbV2;
170
    }
171
    res = ((unsigned long)msbV1 << 16) | lsb;
172
 
173
    return res;
174
}
175
 
176
/*
177
    Read 32-bit non-changing value from addr.
178
*/
179
unsigned long ReadVS10xxMem32(unsigned int addr) {
180
    unsigned int lsb;
181
    WriteSci(SCI_WRAMADDR, addr);
182
    lsb = ReadSci(SCI_WRAM);
183
    return lsb | ((unsigned long)ReadSci(SCI_WRAM) << 16);
184
}
185
 
186
/*
187
    Read 16-bit value from addr.
188
*/
189
unsigned int ReadVS10xxMem(unsigned int addr) {
190
    WriteSci(SCI_WRAMADDR, addr);
191
    return ReadSci(SCI_WRAM);
192
}
193
 
194
/*
195
    Write 16-bit value to given VS10xx address
196
*/
197
void WriteVS10xxMem(unsigned int addr, unsigned int data) {
198
    WriteSci(SCI_WRAMADDR, addr);
199
    WriteSci(SCI_WRAM, data);
200
}
201
 
202
/*
203
    Write 32-bit value to given VS10xx address
204
*/
205
void WriteVS10xxMem32(unsigned int addr, unsigned long data) {
206
    WriteSci(SCI_WRAMADDR, addr);
207
    WriteSci(SCI_WRAM, (unsigned int)data);
208
    WriteSci(SCI_WRAM, (unsigned int)(data>>16));
209
}
210
 
211
/* Note: code SS_VER=2 is used for both VS1002 and VS1011e */
212
const unsigned int chipNumber[16] = {
213
    1001, 1011, 1011, 1003, 1053, 1033, 1063, 1103,
214
    0, 0, 0, 0, 0, 0, 0, 0
215
};
216
 
217
void Set32(unsigned char *d, unsigned long n) {
218
	unsigned int i;
219
    for (i=0; i<4; i++) {
220
        *d++ = (unsigned char)n;
221
        n >>= 8;
222
    }
223
}
224
 
225
void Set16(unsigned char *d, unsigned int n) {
226
	unsigned int i;
227
    for (i=0; i<2; i++) {
228
        *d++ = (unsigned char)n;
229
        n >>= 8;
230
    }
231
}
232
 
233
/*
234
    Loads a plugin.
235
 
236
    This is a slight modification of the LoadUserCode() example
237
    provided in many of VLSI Solution's program packages.
238
*/
239
void LoadPlugin(const unsigned short *d, unsigned short len) {
240
    unsigned int i = 0;
241
 
242
    while (i<len) {
243
        unsigned short addr, n, val;
244
        addr = d[i++];
245
        n = d[i++];
246
        if (n & 0x8000U) { /* RLE run, replicate n samples */
247
            n &= 0x7FFF;
248
            val = d[i++];
249
            while (n--) {
250
                WriteSci(addr, val);
251
            }
252
        } else {           /* Copy run, copy n samples */
253
            while (n--) {
254
                val = d[i++];
255
                WriteSci(addr, val);
256
            }
257
        }
258
    }
259
}
260
 
261
enum PlayerStates {
262
    psPlayback = 0,
263
    psStopped
264
} playerState;
265
 
266
/*
267
 * Executes a software reset
268
 */
269
void VS1053SoftwareReset(void) {
270
	unsigned char c;
271
	unsigned short oldMode = ReadSci(SCI_MODE);
272
	WriteSci(SCI_MODE, oldMode | SM_RESET);
273
	__delay_cycles(100);
274
	do {	// Wait until DREQ is high
275
		c = VS10XX_DREQ_STAT();
276
	} while (c == 0);
277
}
278
 
279
/*
280
    This function plays back an audio file.
281
 
282
    File playback:
283
        1. Send an audio file to VS1053b
284
        2. Read extra parameter value endFillByte
285
        3. Send at least 2052 bytes of endFillByte
286
        4. Set SCI_MODE bit SM_CANCEL
287
        5. Send at least 32 bytes of endFillByte
288
        6. Read SCI_MODE. If SM_CANCEL is set, goto step 5
289
            If still set after 2048 bytes, do a software reset
290
 
291
    Cancelling playback:
292
        1. Send a portion of an audio file to VS1053b
293
        2. Set SCI_MODE bit SM_CANCEL
294
        3. Continue to send audio file, check SM_CANCEL every 32 bytes
295
            If set, goto step 3
296
            If still set after 2048 bytes, do a software reset
297
        4. Read extra parameter value endFillByte
298
        5. Send 2052 bytes of endFillByte
299
*/
300
void VS1053PlayFile(const char *fileName) {
301
    unsigned char playBuf[FILE_BUFFER_SIZE];
302
    unsigned short bytesRead;			// Number of bytes read by pf_read()
303
    unsigned short bytesInBuffer;       // How many valid bytes in buffer left
304
    unsigned short pos = 0;             // File position
305
    int endFillByte = 0;                // What byte value to send after file
306
    int playMode = ReadVS10xxMem(PAR_PLAY_MODE);
307
    long nextReportPos = 0;             // File pointer where to next collect/report
308
    FRESULT res;
309
    unsigned int i;
310
 
311
    playerState = psPlayback;           // Set state to normal playback
312
 
313
    WriteSci(SCI_DECODE_TIME, 0);       // Reset DECODE_TIME
314
 
315
    res = pf_open(fileName);
316
    if (res != FR_OK)
317
        return;
318
 
319
    /* Main playback loop */
320
 
321
    // Read the entire file FILE_BUFFER_SIZE (32) bytes at a time
322
    do {
323
        unsigned char *bufP = playBuf;
324
 
325
        // Read FILE_BUFFER_SIZE (32) bytes from the file into the buffer
326
        res = pf_read(playBuf, FILE_BUFFER_SIZE, &bytesRead);
327
        if (res != FR_OK)
328
            break;
329
        bytesInBuffer = bytesRead;
330
 
331
        while (bytesInBuffer && playerState != psStopped) {
332
 
333
            if (!(playMode & PAR_PLAY_MODE_PAUSE_ENA)) {
334
                int bytesToWrite = min(SDI_MAX_TRANSFER_SIZE, bytesInBuffer);
335
 
336
                // This is the heart of the algorithm: on the following line
337
                // actual audio data gets sent to VS10xx.
338
                WriteSdi(bufP, bytesToWrite);
339
 
340
                bufP += bytesToWrite;
341
                bytesInBuffer -= bytesToWrite;
342
                pos += bytesToWrite;
343
            }
344
 
345
            /* If playback is going on as normal, see if we need to collect and
346
                 possibly report */
347
            if (playerState == psPlayback && pos >= nextReportPos) {
348
 
349
                nextReportPos += (audioFormat == afMidi || audioFormat == afUnknown) ?
350
                    REPORT_INTERVAL_MIDI : REPORT_INTERVAL;
351
                /* It is important to collect endFillByte while still in normal
352
                     playback. If we need to later cancel playback or run into any
353
                     trouble with e.g. a broken file, we need to be able to repeatedly
354
                     send this byte until the decoder has been able to exit. */
355
                endFillByte = ReadVS10xxMem(PAR_END_FILL_BYTE);
356
            }
357
        }
358
    } while(bytesRead == FILE_BUFFER_SIZE && playerState != psStopped);
359
 
360
    /* Earlier we collected endFillByte. Now, just in case the file was
361
         broken, or if a cancel playback command has been given, write
362
         SDI_END_FILL_BYTES (2052) bytes of endFillByte. */
363
    for (i = 0; i < FILE_BUFFER_SIZE; i++) {
364
        playBuf[i] = endFillByte;
365
    }
366
    for (i = 0; i < SDI_END_FILL_BYTES; i += SDI_MAX_TRANSFER_SIZE) {
367
        WriteSdi(playBuf, SDI_MAX_TRANSFER_SIZE);
368
    }
369
 
370
    /* If the file actually ended, and playback cancellation was not
371
         done earlier, do it now. */
372
    if (playerState == psPlayback) {
373
    	pos = SDI_MAX_TRANSFER_SIZE;
374
        unsigned short oldMode = ReadSci(SCI_MODE);
375
        WriteSci(SCI_MODE, oldMode | SM_CANCEL);
376
        // Write 32 bytes of endFillByte
377
        WriteSdi(playBuf, SDI_MAX_TRANSFER_SIZE);
378
        i = ReadSci(SCI_MODE);
379
        while (i & SM_CANCEL) {
380
        	// Reset after sending 2048 bytes
381
        	if (pos > 2048) {
382
        		VS1053SoftwareReset();
383
        		break;
384
        	}
385
            WriteSdi(playBuf, SDI_MAX_TRANSFER_SIZE);
386
            pos += SDI_MAX_TRANSFER_SIZE;
387
            i = ReadSci(SCI_MODE);
388
        }
389
    }
390
}
391
 
392
/*
393
 * Main initialization function
394
 */
395
int VS1053Init(void) {
396
    if (VSInitHardware() != 0)
397
        return 1;
398
    if (VSInitSoftware() != 0)
399
        return 1;
400
    return 0;
401
}
402
 
403
/*
404
    Hardware Initialization for VS1053.
405
*/
406
int VSInitHardware(void) {
407
    /* Write here your microcontroller code which puts VS10xx in hardware
408
         reset and back (set xRESET to 0 for at least a few clock cycles,
409
         then to 1). */
410
 
411
//    // Chip Command Select (idle high)
412
//    VS10XX_CS_PxOUT |= VS10XX_CS;
413
//    VS10XX_CS_PxDIR |= VS10XX_CS;
414
//
415
//    // Chip Data Select (idle high)
416
//    VS10XX_DC_PxOUT |= VS10XX_DC;
417
//    VS10XX_DC_PxDIR |= VS10XX_DC;
418
//
419
//    // Reset (idle high)
420
//    VS10XX_RESET_PxOUT |= VS10XX_RESET;
421
//    VS10XX_RESET_PxDIR |= VS10XX_RESET;
422
//
423
//    // DREQ Line
424
//    VS10XX_DREQ_PxDIR &= ~VS10XX_DREQ;
425
 
426
	CHIP_RESET_LOW();
427
    __delay_cycles(10000);
428
    CHIP_RESET_HIGH();
429
 
430
    unsigned char c;
431
	do {	// Wait until DREQ is high
432
		c = VS10XX_DREQ_STAT();
433
	} while (c == 0);
434
 
435
    return 0;
436
}
437
 
438
/*
439
    Software Initialization for VS1053.
440
 
441
    Note that you need to check whether SM_SDISHARE should be set in
442
    your application or not.
443
*/
444
int VSInitSoftware(void) {
445
    unsigned int ssVer;
446
 
447
    unsigned char c;
448
	do {	// Wait until DREQ is high
449
		c = VS10XX_DREQ_STAT();
450
	} while (c == 0);
451
 
452
    /* Initial SPI bus speed needs to be < 1.5Mhz */
453
    halSPISetSpeedLow();
454
 
455
    /* Start initialization with a dummy read, which makes sure our
456
         microcontroller chips selects and everything are where they
457
         are supposed to be and that VS10xx's SCI bus is in a known state. */
458
    ReadSci(SCI_MODE);
459
 
460
    /* First real operation is a software reset. After the software
461
         reset we know what the status of the IC is. You need, depending
462
         on your application, either set or not set SM_SDISHARE. See the
463
         datasheet for details. */
464
//    WriteSci(SCI_MODE, SM_SDINEW|SM_SDISHARE|SM_TESTS|SM_RESET);
465
    WriteSci(SCI_MODE, SM_SDINEW|SM_RESET);
466
 
467
    /* A quick sanity check: write to two registers, then test if we
468
         get the same results. Note that if you use a too high SPI
469
         speed, the MSB is the most likely to fail when read again. */
470
    WriteSci(SCI_HDAT0, 0xABAD);
471
    WriteSci(SCI_HDAT1, 0x1DEA);
472
    if (ReadSci(SCI_HDAT0) != 0xABAD || ReadSci(SCI_HDAT1) != 0x1DEA) {
473
    	// There is something wrong with VS10xx
474
        return 1;
475
    }
476
 
477
    /* Set the clock. Until this point we need to run SPI slow so that
478
         we do not exceed the maximum speeds mentioned in
479
         Chapter SPI Timing Diagram in the datasheet. */
480
    WriteSci(SCI_CLOCKF, HZ_TO_SC_FREQ(12288000) | SC_MULT_53_35X | SC_ADD_53_10X);
481
//    WriteSci(SCI_CLOCKF, 0x6000);
482
 
483
    __delay_cycles(10000);
484
 
485
    /* Now when we have upped the VS10xx clock speed, the microcontroller
486
		 SPI bus can run faster. Do that before you start playing or
487
		 recording files. */
488
    halSPISetSpeedHigh();
489
 
490
    /* A quick sanity check: write to two registers, then test if we
491
		 get the same results. Note that if you use a too high SPI
492
		 speed, the MSB is the most likely to fail when read again. */
493
	WriteSci(SCI_HDAT0, 0xABAD);
494
	WriteSci(SCI_HDAT1, 0x1DEA);
495
	if (ReadSci(SCI_HDAT0) != 0xABAD || ReadSci(SCI_HDAT1) != 0x1DEA) {
496
		// There is something wrong with VS10xx
497
		return 1;
498
	}
499
 
500
    /* Check VS10xx type */
501
    ssVer = ((ReadSci(SCI_STATUS) >> 4) & 15);
502
    if (chipNumber[ssVer]) {
503
    	// Chip is VS%d\n", chipNumber[ssVer]);
504
        if (chipNumber[ssVer] != 1053) {
505
        	// Incorrect chip
506
            return 1;
507
        }
508
    } else {
509
    	// Unknown VS10xx SCI_MODE field
510
        return 1;
511
    }
512
 
513
    /* Set up other parameters. */
514
//    WriteVS10xxMem(PAR_CONFIG1, PAR_CONFIG1_AAC_SBR_SELECTIVE_UPSAMPLE);
515
 
516
    /* Set volume level to max */
517
    WriteSci(SCI_VOL, 0x0000);
518
 
519
    /* Now it's time to load the proper patch set. */
520
    LoadPlugin(plugin, sizeof(plugin)/sizeof(plugin[0]));
521
 
522
    /* We're ready to go. */
523
    return 0;
524
}