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