Skip to content

Commit e069959

Browse files
author
rogerclarkmelbourne
committed
Added VS1003V_STM from Vassillis Serasidis. Note. Had to make a minor change as PC7 used in the example was not availabel on Maple mini. So I changed this for PC14
1 parent 8540c26 commit e069959

4 files changed

Lines changed: 708 additions & 0 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Description
2+
---
3+
4+
That library is for VS1003B / VS10053B WAV/MP3/AAC audio decoder. The library has been ported to work with STM32 micro-controllers.
Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
/*
2+
Copyright (C) 2012 Andy Karpov <andy.karpov@gmail.com>
3+
4+
This program is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU General Public License
6+
version 2 as published by the Free Software Foundation.
7+
8+
Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
9+
Home: http://www.serasidis.gr
10+
email: avrsite@yahoo.gr
11+
12+
*/
13+
14+
// STL headers
15+
// C headers
16+
#include <avr/pgmspace.h>
17+
// Framework headers
18+
// Library headers
19+
#include <avr/pgmspace.h>
20+
#include <limits.h>
21+
#include <libmaple/dma.h>
22+
#include "pins_arduino.h"
23+
#include "wiring_private.h"
24+
#include <SPI.h>
25+
// Project headers
26+
// This component's header
27+
#include <VS1003_STM.h>
28+
29+
const uint8_t vs1003_chunk_size = 32;
30+
31+
#undef PROGMEM
32+
#define PROGMEM __attribute__ ((section (".progmem.data")))
33+
#undef PSTR
34+
#define PSTR(s) (__extension__({static char __c[] PROGMEM = (s); &__c[0];}))
35+
36+
/****************************************************************************/
37+
38+
// VS1003 SCI Write Command byte is 0x02
39+
#define VS_WRITE_COMMAND 0x02
40+
41+
// VS1003 SCI Read COmmand byte is 0x03
42+
#define VS_READ_COMMAND 0x03
43+
44+
// SCI Registers
45+
46+
const uint8_t SCI_MODE = 0x0;
47+
const uint8_t SCI_STATUS = 0x1;
48+
const uint8_t SCI_BASS = 0x2;
49+
const uint8_t SCI_CLOCKF = 0x3;
50+
const uint8_t SCI_DECODE_TIME = 0x4;
51+
const uint8_t SCI_AUDATA = 0x5;
52+
const uint8_t SCI_WRAM = 0x6;
53+
const uint8_t SCI_WRAMADDR = 0x7;
54+
const uint8_t SCI_HDAT0 = 0x8;
55+
const uint8_t SCI_HDAT1 = 0x9;
56+
const uint8_t SCI_AIADDR = 0xa;
57+
const uint8_t SCI_VOL = 0xb;
58+
const uint8_t SCI_AICTRL0 = 0xc;
59+
const uint8_t SCI_AICTRL1 = 0xd;
60+
const uint8_t SCI_AICTRL2 = 0xe;
61+
const uint8_t SCI_AICTRL3 = 0xf;
62+
const uint8_t SCI_num_registers = 0xf;
63+
64+
// SCI_MODE bits
65+
66+
const uint8_t SM_DIFF = 0;
67+
const uint8_t SM_LAYER12 = 1;
68+
const uint8_t SM_RESET = 2;
69+
const uint8_t SM_OUTOFWAV = 3;
70+
const uint8_t SM_EARSPEAKER_LO = 4;
71+
const uint8_t SM_TESTS = 5;
72+
const uint8_t SM_STREAM = 6;
73+
const uint8_t SM_EARSPEAKER_HI = 7;
74+
const uint8_t SM_DACT = 8;
75+
const uint8_t SM_SDIORD = 9;
76+
const uint8_t SM_SDISHARE = 10;
77+
const uint8_t SM_SDINEW = 11;
78+
const uint8_t SM_ADPCM = 12;
79+
const uint8_t SM_ADCPM_HP = 13;
80+
const uint8_t SM_LINE_IN = 14;
81+
82+
// Register names
83+
84+
char reg_name_MODE[] PROGMEM = "MODE";
85+
char reg_name_STATUS[] PROGMEM = "STATUS";
86+
char reg_name_BASS[] PROGMEM = "BASS";
87+
char reg_name_CLOCKF[] PROGMEM = "CLOCKF";
88+
char reg_name_DECODE_TIME[] PROGMEM = "DECODE_TIME";
89+
char reg_name_AUDATA[] PROGMEM = "AUDATA";
90+
char reg_name_WRAM[] PROGMEM = "WRAM";
91+
char reg_name_WRAMADDR[] PROGMEM = "WRAMADDR";
92+
char reg_name_HDAT0[] PROGMEM = "HDAT0";
93+
char reg_name_HDAT1[] PROGMEM = "HDAT1";
94+
char reg_name_AIADDR[] PROGMEM = "AIADDR";
95+
char reg_name_VOL[] PROGMEM = "VOL";
96+
char reg_name_AICTRL0[] PROGMEM = "AICTRL0";
97+
char reg_name_AICTRL1[] PROGMEM = "AICTRL1";
98+
char reg_name_AICTRL2[] PROGMEM = "AICTRL2";
99+
char reg_name_AICTRL3[] PROGMEM = "AICTRL3";
100+
101+
static PGM_P register_names[] PROGMEM =
102+
{
103+
reg_name_MODE,
104+
reg_name_STATUS,
105+
reg_name_BASS,
106+
reg_name_CLOCKF,
107+
reg_name_DECODE_TIME,
108+
reg_name_AUDATA,
109+
reg_name_WRAM,
110+
reg_name_WRAMADDR,
111+
reg_name_HDAT0,
112+
reg_name_HDAT1,
113+
reg_name_AIADDR,
114+
reg_name_VOL,
115+
reg_name_AICTRL0,
116+
reg_name_AICTRL1,
117+
reg_name_AICTRL2,
118+
reg_name_AICTRL3,
119+
};
120+
121+
/****************************************************************************/
122+
123+
inline void DMA1_CH3_Event() {
124+
dma1_ch3_Active = 0;
125+
dma_disable(DMA1, DMA_CH3);
126+
}
127+
128+
/****************************************************************************/
129+
130+
uint16_t VS1003_STM::read_register(uint8_t _reg) const
131+
{
132+
uint16_t result;
133+
control_mode_on();
134+
delayMicroseconds(1); // tXCSS
135+
SPI.transfer(VS_READ_COMMAND); // Read operation
136+
SPI.transfer(_reg); // Which register
137+
result = SPI.transfer(0xff) << 8; // read high byte
138+
result |= SPI.transfer(0xff); // read low byte
139+
delayMicroseconds(1); // tXCSH
140+
await_data_request();
141+
control_mode_off();
142+
return result;
143+
}
144+
145+
/****************************************************************************/
146+
147+
void VS1003_STM::write_register(uint8_t _reg,uint16_t _value) const
148+
{
149+
control_mode_on();
150+
delayMicroseconds(1); // tXCSS
151+
SPI.transfer(VS_WRITE_COMMAND); // Write operation
152+
SPI.transfer(_reg); // Which register
153+
SPI.transfer(_value >> 8); // Send hi byte
154+
SPI.transfer(_value & 0xff); // Send lo byte
155+
delayMicroseconds(1); // tXCSH
156+
await_data_request();
157+
control_mode_off();
158+
}
159+
160+
/****************************************************************************/
161+
162+
void VS1003_STM::sdi_send_buffer(const uint8_t* data, size_t len)
163+
{
164+
data_mode_on();
165+
while ( len )
166+
{
167+
await_data_request();
168+
delayMicroseconds(3);
169+
170+
size_t chunk_length = min(len,vs1003_chunk_size);
171+
len -= chunk_length;
172+
while ( chunk_length-- )
173+
SPI.transfer(*data++);
174+
}
175+
data_mode_off();
176+
}
177+
178+
/****************************************************************************/
179+
180+
void VS1003_STM::sdi_send_zeroes(size_t len)
181+
{
182+
data_mode_on();
183+
while ( len )
184+
{
185+
await_data_request();
186+
187+
size_t chunk_length = min(len,vs1003_chunk_size);
188+
len -= chunk_length;
189+
while ( chunk_length-- )
190+
SPI.transfer(0);
191+
}
192+
data_mode_off();
193+
}
194+
195+
/****************************************************************************/
196+
197+
VS1003_STM::VS1003_STM( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t _reset_pin):
198+
cs_pin(_cs_pin), dcs_pin(_dcs_pin), dreq_pin(_dreq_pin), reset_pin(_reset_pin)
199+
{
200+
}
201+
202+
/****************************************************************************/
203+
204+
void VS1003_STM::begin(void)
205+
{
206+
207+
// Keep the chip in reset until we are ready
208+
pinMode(reset_pin,OUTPUT);
209+
digitalWrite(reset_pin,LOW);
210+
211+
// The SCI and SDI will start deselected
212+
pinMode(cs_pin,OUTPUT);
213+
digitalWrite(cs_pin,HIGH);
214+
pinMode(dcs_pin,OUTPUT);
215+
digitalWrite(dcs_pin,HIGH);
216+
217+
// DREQ is an input
218+
pinMode(dreq_pin,INPUT);
219+
220+
// Boot VS1003
221+
//Serial.println(PSTR("Booting VS1003...\r\n"));
222+
223+
delay(1);
224+
225+
SPI.begin();
226+
SPI.setBitOrder(MSBFIRST);
227+
SPI.setDataMode(SPI_MODE0);
228+
// init SPI slow mode
229+
SPI.setClockDivider(SPI_CLOCK_DIV64); // Slow!
230+
231+
// release from reset
232+
digitalWrite(reset_pin,HIGH);
233+
234+
// Declick: Immediately switch analog off
235+
write_register(SCI_VOL,0xffff); // VOL
236+
237+
/* Declick: Slow sample rate for slow analog part startup */
238+
write_register(SCI_AUDATA,10);
239+
240+
delay(100);
241+
242+
/* Switch on the analog parts */
243+
write_register(SCI_VOL,0xfefe); // VOL
244+
245+
//printf_P(PSTR("VS1003 still booting\r\n"));
246+
247+
write_register(SCI_AUDATA,44101); // 44.1kHz stereo
248+
249+
write_register(SCI_VOL,0x2020); // VOL
250+
251+
// soft reset
252+
write_register(SCI_MODE, (1<<SM_SDINEW) | (1<<SM_RESET));
253+
delay(1);
254+
await_data_request();
255+
//write_register(SCI_CLOCKF,0xB800); // Experimenting with higher clock settings
256+
write_register(SCI_CLOCKF,0x6000);
257+
delay(1);
258+
await_data_request();
259+
260+
// Now you can set high speed SPI clock
261+
// 72 MHz / 16 = 4.5 MHz max is practically allowed by VS1003 SPI interface.
262+
SPI.setClockDivider(SPI_CLOCK_DIV16);
263+
264+
//printf_P(PSTR("VS1003 Set\r\n"));
265+
//printDetails();
266+
//printf_P(PSTR("VS1003 OK\r\n"));
267+
268+
}
269+
270+
/****************************************************************************/
271+
272+
void VS1003_STM::setVolume(uint8_t vol) const
273+
{
274+
uint16_t value = vol;
275+
value <<= 8;
276+
value |= vol;
277+
278+
write_register(SCI_VOL,value); // VOL
279+
}
280+
281+
/****************************************************************************/
282+
283+
void VS1003_STM::startSong(void)
284+
{
285+
sdi_send_zeroes(10);
286+
}
287+
288+
/****************************************************************************/
289+
290+
void VS1003_STM::playChunk(const uint8_t* data, size_t len)
291+
{
292+
sdi_send_buffer(data,len);
293+
}
294+
295+
/****************************************************************************/
296+
297+
void VS1003_STM::stopSong(void)
298+
{
299+
sdi_send_zeroes(2048);
300+
}
301+
302+
/****************************************************************************/
303+
304+
void VS1003_STM::print_byte_register(uint8_t reg) const
305+
{
306+
const char *name = reinterpret_cast<const char*>(pgm_read_word( register_names + reg ));
307+
char extra_tab = strlen_P(name) < 5 ? '\t' : 0;
308+
//printf_P(PSTR("%02x %S\t%c = 0x%02x\r\n"),reg,name,extra_tab,read_register(reg));
309+
}
310+
311+
/****************************************************************************/
312+
313+
void VS1003_STM::printDetails(void) const
314+
{
315+
//printf_P(PSTR("VS1003 Configuration:\r\n"));
316+
int i = 0;
317+
while ( i <= SCI_num_registers )
318+
print_byte_register(i++);
319+
}
320+
321+
/****************************************************************************/
322+
323+
void VS1003_STM::loadUserCode(const uint16_t* buf, size_t len) const
324+
{
325+
while (len)
326+
{
327+
uint16_t addr = pgm_read_word(buf++); len--;
328+
uint16_t n = pgm_read_word(buf++); len--;
329+
if (n & 0x8000U) { /* RLE run, replicate n samples */
330+
n &= 0x7FFF;
331+
uint16_t val = pgm_read_word(buf++); len--;
332+
while (n--) {
333+
//printf_P(PSTR("W %02x: %04x\r\n"),addr,val);
334+
write_register(addr, val);
335+
}
336+
} else { /* Copy run, copy n samples */
337+
while (n--) {
338+
uint16_t val = pgm_read_word(buf++); len--;
339+
//printf_P(PSTR("W %02x: %04x\r\n"),addr,val);
340+
write_register(addr, val);
341+
}
342+
}
343+
}
344+
}
345+
346+
/****************************************************************************/

0 commit comments

Comments
 (0)