Converted VS1003 lib to new lib style including keywords
This commit is contained in:
parent
2797907221
commit
1af98fed89
|
@ -1,7 +1,8 @@
|
|||
Description
|
||||
---
|
||||
|
||||
That library is for VS1003B / VS10053B WAV/MP3/AAC audio decoder. The library has been ported to work with STM32 micro-controllers.
|
||||
That library is for VS1003B / VS10053B WAV/MP3/AAC audio decoder.
|
||||
The library has been ported to work with STM32 micro-controllers.
|
||||
|
||||
A short Youtube video demonstration of the library can be found [here][A].
|
||||
In that video I used an **STM32F103C8T** development board and a **VS1053B** mp3 decoder module.
|
||||
|
|
|
@ -1,345 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2012 Andy Karpov <andy.karpov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
|
||||
Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
|
||||
Home: http://www.serasidis.gr
|
||||
email: avrsite@yahoo.gr
|
||||
29 May 2015 - Added a fix for booting the VS1053B boards into
|
||||
mp3 decoding instead of booting into MID (modeSwitch function).
|
||||
*/
|
||||
|
||||
//#include <my_SPI.h>
|
||||
#include <VS1003_STM.h>
|
||||
|
||||
#define vs1003_chunk_size 32
|
||||
/****************************************************************************/
|
||||
|
||||
// VS1003 SCI Write Command byte is 0x02
|
||||
#define VS_WRITE_COMMAND 0x02
|
||||
|
||||
// VS1003 SCI Read COmmand byte is 0x03
|
||||
#define VS_READ_COMMAND 0x03
|
||||
|
||||
// SCI Registers
|
||||
|
||||
const uint8_t SCI_MODE = 0x0;
|
||||
const uint8_t SCI_STATUS = 0x1;
|
||||
const uint8_t SCI_BASS = 0x2;
|
||||
const uint8_t SCI_CLOCKF = 0x3;
|
||||
const uint8_t SCI_DECODE_TIME = 0x4;
|
||||
const uint8_t SCI_AUDATA = 0x5;
|
||||
const uint8_t SCI_WRAM = 0x6;
|
||||
const uint8_t SCI_WRAMADDR = 0x7;
|
||||
const uint8_t SCI_HDAT0 = 0x8;
|
||||
const uint8_t SCI_HDAT1 = 0x9;
|
||||
const uint8_t SCI_AIADDR = 0xa;
|
||||
const uint8_t SCI_VOL = 0xb;
|
||||
const uint8_t SCI_AICTRL0 = 0xc;
|
||||
const uint8_t SCI_AICTRL1 = 0xd;
|
||||
const uint8_t SCI_AICTRL2 = 0xe;
|
||||
const uint8_t SCI_AICTRL3 = 0xf;
|
||||
const uint8_t SCI_num_registers = 0xf;
|
||||
|
||||
// SCI_MODE bits
|
||||
|
||||
const uint8_t SM_DIFF = 0;
|
||||
const uint8_t SM_LAYER12 = 1;
|
||||
const uint8_t SM_RESET = 2;
|
||||
const uint8_t SM_OUTOFWAV = 3;
|
||||
const uint8_t SM_EARSPEAKER_LO = 4;
|
||||
const uint8_t SM_TESTS = 5;
|
||||
const uint8_t SM_STREAM = 6;
|
||||
const uint8_t SM_EARSPEAKER_HI = 7;
|
||||
const uint8_t SM_DACT = 8;
|
||||
const uint8_t SM_SDIORD = 9;
|
||||
const uint8_t SM_SDISHARE = 10;
|
||||
const uint8_t SM_SDINEW = 11;
|
||||
const uint8_t SM_ADPCM = 12;
|
||||
const uint8_t SM_ADCPM_HP = 13;
|
||||
const uint8_t SM_LINE_IN = 14;
|
||||
|
||||
// Register names
|
||||
|
||||
const char reg_name_MODE[] = "MODE";
|
||||
const char reg_name_STATUS[] = "STATUS";
|
||||
const char reg_name_BASS[] = "BASS";
|
||||
const char reg_name_CLOCKF[] = "CLOCKF";
|
||||
const char reg_name_DECODE_TIME[] = "DECODE_TIME";
|
||||
const char reg_name_AUDATA[] = "AUDATA";
|
||||
const char reg_name_WRAM[] = "WRAM";
|
||||
const char reg_name_WRAMADDR[] = "WRAMADDR";
|
||||
const char reg_name_HDAT0[] = "HDAT0";
|
||||
const char reg_name_HDAT1[] = "HDAT1";
|
||||
const char reg_name_AIADDR[] = "AIADDR";
|
||||
const char reg_name_VOL[] = "VOL";
|
||||
const char reg_name_AICTRL0[] = "AICTRL0";
|
||||
const char reg_name_AICTRL1[] = "AICTRL1";
|
||||
const char reg_name_AICTRL2[] = "AICTRL2";
|
||||
const char reg_name_AICTRL3[] = "AICTRL3";
|
||||
|
||||
static PGM_P const register_names[] =
|
||||
{
|
||||
reg_name_MODE,
|
||||
reg_name_STATUS,
|
||||
reg_name_BASS,
|
||||
reg_name_CLOCKF,
|
||||
reg_name_DECODE_TIME,
|
||||
reg_name_AUDATA,
|
||||
reg_name_WRAM,
|
||||
reg_name_WRAMADDR,
|
||||
reg_name_HDAT0,
|
||||
reg_name_HDAT1,
|
||||
reg_name_AIADDR,
|
||||
reg_name_VOL,
|
||||
reg_name_AICTRL0,
|
||||
reg_name_AICTRL1,
|
||||
reg_name_AICTRL2,
|
||||
reg_name_AICTRL3,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
inline void DMA1_CH3_Event() {
|
||||
dma1_ch3_Active = 0;
|
||||
dma_disable(DMA1, DMA_CH3);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
uint16_t VS1003::read_register(uint8_t _reg) const
|
||||
{
|
||||
uint16_t result;
|
||||
control_mode_on();
|
||||
delayMicroseconds(1); // tXCSS
|
||||
my_SPI.transfer(VS_READ_COMMAND); // Read operation
|
||||
my_SPI.transfer(_reg); // Which register
|
||||
result = my_SPI.transfer(0xff) << 8; // read high byte
|
||||
result |= my_SPI.transfer(0xff); // read low byte
|
||||
delayMicroseconds(1); // tXCSH
|
||||
await_data_request();
|
||||
control_mode_off();
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::write_register(uint8_t _reg,uint16_t _value) const
|
||||
{
|
||||
control_mode_on();
|
||||
delayMicroseconds(1); // tXCSS
|
||||
my_SPI.transfer(VS_WRITE_COMMAND); // Write operation
|
||||
my_SPI.transfer(_reg); // Which register
|
||||
my_SPI.transfer(_value >> 8); // Send hi byte
|
||||
my_SPI.transfer(_value & 0xff); // Send lo byte
|
||||
delayMicroseconds(1); // tXCSH
|
||||
await_data_request();
|
||||
control_mode_off();
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::sdi_send_buffer(const uint8_t* data, size_t len)
|
||||
{
|
||||
data_mode_on();
|
||||
while ( len )
|
||||
{
|
||||
await_data_request();
|
||||
delayMicroseconds(3);
|
||||
|
||||
size_t chunk_length = min(len,vs1003_chunk_size);
|
||||
len -= chunk_length;
|
||||
while ( chunk_length-- )
|
||||
my_SPI.transfer(*data++);
|
||||
}
|
||||
data_mode_off();
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::sdi_send_zeroes(size_t len)
|
||||
{
|
||||
data_mode_on();
|
||||
while ( len )
|
||||
{
|
||||
await_data_request();
|
||||
|
||||
size_t chunk_length = min(len,vs1003_chunk_size);
|
||||
len -= chunk_length;
|
||||
while ( chunk_length-- )
|
||||
my_SPI.transfer(0);
|
||||
}
|
||||
data_mode_off();
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
VS1003::VS1003( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t _reset_pin, SPIClass _spiChan):
|
||||
cs_pin(_cs_pin), dcs_pin(_dcs_pin), dreq_pin(_dreq_pin), reset_pin(_reset_pin), my_SPI(_spiChan)
|
||||
{
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::begin(void)
|
||||
{
|
||||
|
||||
// Keep the chip in reset until we are ready
|
||||
pinMode(reset_pin,OUTPUT);
|
||||
digitalWrite(reset_pin,LOW);
|
||||
|
||||
// The SCI and SDI will start deselected
|
||||
pinMode(cs_pin,OUTPUT);
|
||||
digitalWrite(cs_pin,HIGH);
|
||||
pinMode(dcs_pin,OUTPUT);
|
||||
digitalWrite(dcs_pin,HIGH);
|
||||
|
||||
// DREQ is an input
|
||||
pinMode(dreq_pin,INPUT);
|
||||
|
||||
|
||||
// Boot VS1003
|
||||
//printf(("Booting VS1003...\r\n"));
|
||||
|
||||
delay(1);
|
||||
|
||||
my_SPI.begin();
|
||||
my_SPI.setBitOrder(MSBFIRST);
|
||||
my_SPI.setDataMode(SPI_MODE0);
|
||||
// init SPI slow mode
|
||||
|
||||
my_SPI.setClockDivider(SPI_CLOCK_DIV64); // Slow!
|
||||
|
||||
// release from reset
|
||||
digitalWrite(reset_pin,HIGH);
|
||||
|
||||
// Declick: Immediately switch analog off
|
||||
write_register(SCI_VOL,0xffff); // VOL
|
||||
|
||||
/* Declick: Slow sample rate for slow analog part startup */
|
||||
write_register(SCI_AUDATA,10);
|
||||
|
||||
delay(100);
|
||||
|
||||
/* Switch on the analog parts */
|
||||
write_register(SCI_VOL,0xfefe); // VOL
|
||||
|
||||
//printf(("VS1003 still booting\r\n"));
|
||||
|
||||
write_register(SCI_AUDATA,44101); // 44.1kHz stereo
|
||||
|
||||
write_register(SCI_VOL,0x2020); // VOL
|
||||
|
||||
// soft reset
|
||||
write_register(SCI_MODE, (1<<SM_SDINEW) | (1<<SM_RESET));
|
||||
delay(1);
|
||||
await_data_request();
|
||||
//write_register(SCI_CLOCKF,0xB800); // Experimenting with higher clock settings
|
||||
write_register(SCI_CLOCKF,0x6000);
|
||||
delay(1);
|
||||
await_data_request();
|
||||
|
||||
// Now you can set high speed SPI clock
|
||||
// 72 MHz / 16 = 4.5 MHz max is practically allowed by VS1003 SPI interface.
|
||||
my_SPI.setClockDivider(SPI_CLOCK_DIV16);
|
||||
|
||||
//printf(("VS1003 Set\r\n"));
|
||||
//printDetails();
|
||||
//printf(("VS1003 OK\r\n"));
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::setVolume(uint8_t vol) const
|
||||
{
|
||||
uint16_t value = vol;
|
||||
value <<= 8;
|
||||
value |= vol;
|
||||
|
||||
write_register(SCI_VOL,value); // VOL
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::startSong(void)
|
||||
{
|
||||
sdi_send_zeroes(10);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::playChunk(const uint8_t* data, size_t len)
|
||||
{
|
||||
sdi_send_buffer(data,len);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::stopSong(void)
|
||||
{
|
||||
sdi_send_zeroes(2048);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::print_byte_register(uint8_t reg) const
|
||||
{
|
||||
const char *name = reinterpret_cast<const char*>(pgm_read_word( register_names + reg ));
|
||||
char extra_tab = strlen_P(name) < 5 ? '\t' : 0;
|
||||
//printf(("%02x %S\t%c = 0x%02x\r\n"),reg,name,extra_tab,read_register(reg));
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::printDetails(void) const
|
||||
{
|
||||
//printf(("VS1003 Configuration:\r\n"));
|
||||
int i = 0;
|
||||
while ( i <= SCI_num_registers )
|
||||
print_byte_register(i++);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
void VS1003::modeSwitch(void)
|
||||
{
|
||||
//GPIO_DDR
|
||||
write_register(SCI_WRAMADDR, 0xc017);
|
||||
write_register(SCI_WRAM, 0x0003);
|
||||
//GPIO_ODATA
|
||||
write_register(SCI_WRAMADDR, 0xc019);
|
||||
write_register(SCI_WRAM, 0x0000);
|
||||
|
||||
delay(100);
|
||||
write_register(SCI_MODE, (1<<SM_SDINEW) | (1<<SM_RESET));
|
||||
delay(100);
|
||||
}
|
||||
/****************************************************************************/
|
||||
|
||||
void VS1003::loadUserCode(const uint16_t* buf, size_t len) const
|
||||
{
|
||||
while (len)
|
||||
{
|
||||
uint16_t addr = pgm_read_word(buf++); len--;
|
||||
uint16_t n = pgm_read_word(buf++); len--;
|
||||
if (n & 0x8000U) { /* RLE run, replicate n samples */
|
||||
n &= 0x7FFF;
|
||||
uint16_t val = pgm_read_word(buf++); len--;
|
||||
while (n--) {
|
||||
//printf(("W %02x: %04x\r\n"),addr,val);
|
||||
write_register(addr, val);
|
||||
}
|
||||
} else { /* Copy run, copy n samples */
|
||||
while (n--) {
|
||||
uint16_t val = pgm_read_word(buf++); len--;
|
||||
//printf(("W %02x: %04x\r\n"),addr,val);
|
||||
write_register(addr, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2012 Andy Karpov <andy.karpov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
|
||||
Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
|
||||
Home: http://www.serasidis.gr
|
||||
email: avrsite@yahoo.gr
|
||||
|
||||
29 May 2015 - Added a fix for booting the VS1053B boards into mp3 decoding instead of booting into MIDI.
|
||||
*/
|
||||
|
||||
//This is an additional test line
|
||||
#ifndef __VS1003_STM_H__
|
||||
#define __VS1003_STM_H__
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
/**
|
||||
* Driver for VS1003 - MP3 / WMA / MIDI Audio Codec Chip
|
||||
*
|
||||
* See http://www.vlsi.fi/en/products/vs1003.html
|
||||
*/
|
||||
|
||||
class VS1003
|
||||
{
|
||||
private:
|
||||
uint8_t cs_pin; /**< Pin where CS line is connected */
|
||||
uint8_t dcs_pin; /**< Pin where DCS line is connected */
|
||||
uint8_t dreq_pin; /**< Pin where DREQ line is connected */
|
||||
uint8_t reset_pin; /**< Pin where RESET line is connected */
|
||||
uint8_t my_SPCR; /**< Value of the SPCR register how we like it. */
|
||||
uint8_t my_SPSR; /**< Value of the SPSR register how we like it. */
|
||||
SPIClass my_SPI;
|
||||
public:
|
||||
inline void await_data_request(void) const
|
||||
{
|
||||
while ( !digitalRead(dreq_pin) );
|
||||
}
|
||||
|
||||
inline void control_mode_on(void) const
|
||||
{
|
||||
digitalWrite(dcs_pin,HIGH);
|
||||
digitalWrite(cs_pin,LOW);
|
||||
}
|
||||
|
||||
inline void control_mode_off(void) const
|
||||
{
|
||||
digitalWrite(cs_pin,HIGH);
|
||||
}
|
||||
|
||||
inline void data_mode_on(void) const
|
||||
{
|
||||
digitalWrite(cs_pin,HIGH);
|
||||
digitalWrite(dcs_pin,LOW);
|
||||
}
|
||||
|
||||
inline void data_mode_off(void) const
|
||||
{
|
||||
digitalWrite(dcs_pin,HIGH);
|
||||
}
|
||||
|
||||
uint16_t read_register(uint8_t _reg) const;
|
||||
void write_register(uint8_t _reg,uint16_t _value) const;
|
||||
void sdi_send_buffer(const uint8_t* data,size_t len);
|
||||
void sdi_send_zeroes(size_t length);
|
||||
void print_byte_register(uint8_t reg) const;
|
||||
|
||||
/**
|
||||
* Load a user code plugin
|
||||
*
|
||||
* @param buf Location of memory (in PROGMEM) where the code is
|
||||
* @param len Number of words to load
|
||||
*/
|
||||
void loadUserCode(const uint16_t* buf, size_t len) const;
|
||||
|
||||
//public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Only sets pin values. Doesn't do touch the chip. Be sure to call begin()!
|
||||
*/
|
||||
VS1003( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t _reset_pin, SPIClass _spi = SPIClass(1));
|
||||
|
||||
/**
|
||||
* Begin operation
|
||||
*
|
||||
* Sets pins correctly, and prepares SPI bus.
|
||||
*/
|
||||
void begin(void);
|
||||
|
||||
/**
|
||||
* Prepare to start playing
|
||||
*
|
||||
* Call this each time a new song starts.
|
||||
*/
|
||||
void startSong(void);
|
||||
|
||||
/**
|
||||
* Play a chunk of data. Copies the data to the chip. Blocks until complete.
|
||||
*
|
||||
* @param data Pointer to where the data lives
|
||||
* @param len How many bytes of data to play
|
||||
*/
|
||||
void playChunk(const uint8_t* data, size_t len);
|
||||
|
||||
/**
|
||||
* Finish playing a song.
|
||||
*
|
||||
* Call this after the last playChunk call.
|
||||
*/
|
||||
void stopSong(void);
|
||||
|
||||
/**
|
||||
* Print configuration details
|
||||
*
|
||||
* Dumps all registers to stdout. Be sure to have stdout configured first
|
||||
* (see fdevopen() in avr/io.h).
|
||||
*/
|
||||
void printDetails(void) const;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
void modeSwitch(void);
|
||||
|
||||
/**
|
||||
* Set the player volume
|
||||
*
|
||||
* @param vol Volume level from 0-255, lower is louder.
|
||||
*/
|
||||
void setVolume(uint8_t vol) const;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue