Add the RTOS processing. for the Network radio streaming receiver.
Fork of VS1053b by
VS1053.cpp
- Committer:
- ban4jp
- Date:
- 2015-02-22
- Revision:
- 10:114ac02a3875
- Parent:
- 8:5e4a21202223
File content as of revision 10:114ac02a3875:
/* mbed VLSI VS1053b library
* Copyright (c) 2010 Christian Schmiljun
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* This code based on:
* mbeduino_MP3_Shield_MP3Player
* http://mbed.org/users/xshige/programs/mbeduino_MP3_Shield_MP3Player/lgcx63
* 2010-10-16
*/
#include "VS1053.h"
#include "mbed.h"
// patch binarys
#include "Patches/VS1053b_patch_1_5.c"
#include "Patches/VS1053b_patch_1_5_flac.c"
#include "Patches/VS1053b_patch_1_4_flac.c"
#include "Patches/VS1053b_specana_0_9.c"
#include "Patches/VS1053b_pcm_recorder_0_9.c"
const char VS1053::_sampleRateTable[4][4] = {
11, 12, 8, 0,
11, 12, 8, 0,
22, 24, 16, 0,
44, 48, 32, 0
};
/* ==================================================================
* Constructor
* =================================================================*/
VS1053::VS1053(
PinName mosi, PinName miso, PinName sck, PinName cs, PinName rst,
PinName dreq, PinName dcs, char* buffer, int buffer_size)
:
_spi(mosi, miso, sck),
_CS(cs),
_RST(rst),
_DCS(dcs),
_DREQ(dreq),
#ifdef DEBUG
_led(D8),
#endif
#ifdef VS1053_RTOS
_thread(VS1053::dataRequestHandler_start, this, osPriorityNormal, 1024)
#else
_DREQ_INTERUPT_IN(dreq)
#endif
{
cs_high();
dcs_high();
_volume = DEFAULT_VOLUME;
_balance = DEFAULT_BALANCE_DIFERENCE_LEFT_RIGHT;
_sb_amplitude = DEFAULT_BASS_AMPLITUDE;
_sb_freqlimit = DEFAULT_BASS_FREQUENCY;
_st_amplitude = DEFAULT_TREBLE_AMPLITUDE;
_st_freqlimit = DEFAULT_TREBLE_FREQUENCY;
_buffer = buffer;
BUFFER_SIZE = buffer_size;
#ifndef VS1053_RTOS
_DREQ_INTERUPT_IN.mode(PullDown);
#endif
INTERRUPT_HANDLER_DISABLE;
bufferReset();
#ifdef VS1053_RTOS
_thread.signal_set(START_THREAD);
#endif
}
/*===================================================================
* Functions
*==================================================================*/
void VS1053::cs_low(void) {
_CS = 0;
}
void VS1053::cs_high(void) {
_CS = 1;
}
void VS1053::dcs_low(void) {
_DCS = 0;
}
void VS1053::dcs_high(void) {
_DCS = 1;
}
void VS1053::sci_en(void) { //SCI enable
cs_high();
dcs_high();
cs_low();
}
void VS1053::sci_dis(void) { //SCI disable
cs_high();
}
void VS1053::sdi_en(void) { //SDI enable
dcs_high();
cs_high();
dcs_low();
}
void VS1053::sdi_dis(void) { //SDI disable
dcs_high();
}
void VS1053::reset(void) { //hardware reset
INTERRUPT_HANDLER_DISABLE;
wait_ms(10);
_RST = 0;
wait_ms(5);
_RST = 1;
wait_ms(10);
}
void VS1053::power_down(void) { //hardware and software reset
cs_low();
reset();
// sci_write(0x00, SM_PDOWN);
sci_write(0x00, 0x10); // tempo
wait(0.01);
reset();
}
void VS1053::spi_initialise(void) {
_RST = 1; //no reset
_spi.format(8,0); //spi 8bit interface, steady state low
// _spi.frequency(1000000); //rising edge data record, freq. 1Mhz
_spi.frequency(2000000); //rising edge data record, freq. 2Mhz
cs_low();
for (int i=0; i<4; i++) {
_spi.write(0xFF); //clock the chip a bit
}
cs_high();
dcs_high();
wait_us(5);
}
void VS1053::sdi_initialise(void) {
_spi.frequency(8000000); //set to 8 MHz to make fast transfer
cs_high();
dcs_high();
}
void VS1053::sci_write(unsigned char address, unsigned short int data) {
// TODO disable all interrupts
__disable_irq();
sci_en(); //enables SCI/disables SDI
while (!_DREQ); //wait unitl data request is high
_spi.write(0x02); //SCI write
_spi.write(address); //register address
_spi.write((data >> 8) & 0xFF); //write out first half of data word
_spi.write(data & 0xFF); //write out second half of data word
sci_dis(); //enables SDI/disables SCI
wait_us(5);
// TODO enable all interrupts
__enable_irq();
}
void VS1053::sdi_write(unsigned char datum) {
sdi_en();
while (!_DREQ);
_spi.write(datum);
sdi_dis();
}
unsigned short VS1053::sci_read(unsigned short int address) {
// TODO disable all interrupts
__disable_irq();
cs_low(); //enables SCI/disables SDI
while (!_DREQ); //wait unitl data request is high
_spi.write(0x03); //SCI write
_spi.write(address); //register address
unsigned short int received = _spi.write(0x00); //write out dummy byte
received <<= 8;
received |= _spi.write(0x00); //write out dummy byte
cs_high(); //enables SDI/disables SCI
// TODO enable all interrupts
__enable_irq();
return received; //return received word
}
void VS1053::sine_test_activate(unsigned char wave) {
cs_high(); //enables SDI/disables SCI
while (!_DREQ); //wait unitl data request is high
_spi.write(0x53); //SDI write
_spi.write(0xEF); //SDI write
_spi.write(0x6E); //SDI write
_spi.write(wave); //SDI write
_spi.write(0x00); //filler byte
_spi.write(0x00); //filler byte
_spi.write(0x00); //filler byte
_spi.write(0x00); //filler byte
cs_low(); //enables SCI/disables SDI
}
void VS1053::sine_test_deactivate(void) {
cs_high();
while (!_DREQ);
_spi.write(0x45); //SDI write
_spi.write(0x78); //SDI write
_spi.write(0x69); //SDI write
_spi.write(0x74); //SDI write
_spi.write(0x00); //filler byte
_spi.write(0x00); //filler byte
_spi.write(0x00); //filler byte
_spi.write(0x00); //filler byte
}
unsigned short int VS1053::wram_read(unsigned short int address) {
unsigned short int tmp1,tmp2;
sci_write(SCI_WRAMADDR,address);
tmp1=sci_read(SCI_WRAM);
sci_write(SCI_WRAMADDR,address);
tmp2=sci_read(SCI_WRAM);
if (tmp1==tmp2) return tmp1;
sci_write(SCI_WRAMADDR,address);
tmp1=sci_read(SCI_WRAM);
if (tmp1==tmp2) return tmp1;
sci_write(SCI_WRAMADDR,address);
tmp1=sci_read(SCI_WRAM);
if (tmp1==tmp2) return tmp1;
return tmp1;
}
void VS1053::wram_write(unsigned short int address, unsigned short int data) {
sci_write(SCI_WRAMADDR,address);
sci_write(SCI_WRAM,data);
return;
}
void VS1053::setPlaySpeed(unsigned short speed)
{
wram_write(para_playSpeed, speed);
DEBUGOUT("VS1053b: Change speed. New speed: %d\r\n", speed);
}
void VS1053::terminateStream(void) {
while(bufferCount() > 0)
;
DEBUGOUT("VS1053b: Song terminating..\r\n");
// send at least 2052 bytes of endFillByte[7:0].
// read endFillByte (0 .. 15) from wram
unsigned short endFillByte=wram_read(para_endFillByte);
// clear endFillByte (8 .. 15)
endFillByte = endFillByte ^0x00FF;
for (int n = 0; n < 2052; n++)
sdi_write(endFillByte);
// set SCI MODE bit SM CANCEL
unsigned short sciModeByte = sci_read(SCI_MODE);
sciModeByte |= SM_CANCEL;
sci_write(SCI_MODE, sciModeByte);
// send up 2048 bytes of endFillByte[7:0].
for (int i = 0; i < 64; i++)
{
// send at least 32 bytes of endFillByte[7:0]
for (int n = 0; n < 32; n++)
sdi_write(endFillByte);
// read SCI MODE; if SM CANCEL is still set, repeat
sciModeByte = sci_read(SCI_MODE);
if ((sciModeByte & SM_CANCEL) == 0x0000)
{
break;
}
}
if ((sciModeByte & SM_CANCEL) == 0x0000)
{
DEBUGOUT("VS1053b: Song sucessfully sent. Terminating OK\r\n");
DEBUGOUT("VS1053b: SCI MODE = %#x, SM_CANCEL = %#x\r\n", sciModeByte, sciModeByte & SM_CANCEL);
sci_write(SCI_DECODE_TIME, 0x0000);
}
else
{
DEBUGOUT("VS1053b: SM CANCEL hasn't cleared after sending 2048 bytes, do software reset\r\n");
DEBUGOUT("VS1053b: SCI MODE = %#x, SM_CANCEL = %#x\r\n", sciModeByte, sciModeByte & SM_CANCEL);
initialize();
}
}
void VS1053::write_plugin(const unsigned short *plugin, unsigned int len) {
unsigned int i;
unsigned short addr, n, val;
for (i=0; i<len;) {
addr = plugin[i++];
n = plugin[i++];
if (n & 0x8000U) { //RLE run, replicate n samples
n &= 0x7FFF;
val = plugin[i++];
while (n--) {
sci_write(addr,val);
}
} else { //copy run, copy n sample
while (n--) {
val = plugin[i++];
sci_write(addr,val);
}
}
}
return;
}
bool VS1053::initialize(void) {
_RST = 1;
cs_high(); //chip disabled
spi_initialise(); //initialise MBED
sci_write(SCI_MODE, (SM_SDINEW+SM_RESET)); // set mode reg.
wait_ms(10);
#ifdef DEBUG
unsigned int info = wram_read(para_chipID_0);
DEBUGOUT("VS1053b: ChipID_0:%04X\r\n", info);
info = wram_read(para_chipID_1);
DEBUGOUT("VS1053b: ChipID_1:%04X\r\n", info);
info = wram_read(para_version);
DEBUGOUT("VS1053b: Structure version:%04X\r\n", info);
#endif
//get chip version, set clock multiplier and load patch
int i = (sci_read(SCI_STATUS) & 0xF0) >> 4;
if (i == 4) {
DEBUGOUT("VS1053b: Installed Chip is: VS1053\r\n");
sci_write(SCI_CLOCKF, (SC_MULT_XTALIx50));
wait_ms(10);
#ifdef VS_PATCH
// loading patch
write_plugin(vs1053b_patch, sizeof(vs1053b_patch)/2);
DEBUGOUT("VS1053b: Patch is loaded.\r\n");
DEBUGOUT("VS1053b: Patch size:%d bytes\r\n",sizeof(vs1053b_patch));
#endif // VS_PATCH
}
else
{
DEBUGOUT("VS1053b: Not Supported Chip\r\n");
return false;
}
// change spi to higher speed
sdi_initialise();
changeVolume();
changeBass();
_isIdle = true;
_isPlay = false;
return true;
}
void VS1053::setVolume(float vol)
{
if (vol > -0.5)
_volume = -0.5;
else
_volume = vol;
changeVolume();
}
float VS1053::getVolume(void)
{
return _volume;
}
void VS1053::setBalance(float balance)
{
_balance = balance;
changeVolume();
}
float VS1053::getBalance(void)
{
return _balance;
}
void VS1053::changeVolume(void)
{
// volume calculation
unsigned short volCalced = (((char)(_volume / -0.5f)) << 8) + (char)((_volume - _balance) / -0.5f);
sci_write(SCI_VOL, volCalced);
DEBUGOUT("VS1053b: Change volume to %#x (%f, Balance = %f)\r\n", volCalced, _volume, _balance);
}
int VS1053::getTrebleFrequency(void)
{
return _st_freqlimit * 1000;
}
void VS1053::setTrebleFrequency(int frequency)
{
frequency /= 1000;
if(frequency < 1)
{
frequency = 1;
}
else if(frequency > 15)
{
frequency = 15;
}
_st_freqlimit = frequency;
changeBass();
}
int VS1053::getTrebleAmplitude(void)
{
return _st_amplitude;
}
void VS1053::setTrebleAmplitude(int amplitude)
{
if(amplitude < -8)
{
amplitude = -8;
}
else if(amplitude > 7)
{
amplitude = 7;
}
_st_amplitude = amplitude;
changeBass();
}
int VS1053::getBassFrequency(void)
{
return _sb_freqlimit * 10;
}
void VS1053::setBassFrequency(int frequency)
{
frequency /= 10;
if(frequency < 2)
{
frequency = 2;
}
else if(frequency > 15)
{
frequency = 15;
}
_sb_freqlimit = frequency;
changeBass();
}
int VS1053::getBassAmplitude(void)
{
return _sb_amplitude;
}
void VS1053::setBassAmplitude(int amplitude)
{
if(amplitude < -15)
{
amplitude = -15;
}
else if(amplitude > 0)
{
amplitude = 0;
}
_sb_amplitude = amplitude;
changeBass();
}
void VS1053::changeBass(void)
{
unsigned short bassCalced = ((_st_amplitude & 0x0f) << 12)
| ((_st_freqlimit & 0x0f) << 8)
| ((_sb_amplitude & 0x0f) << 4)
| ((_sb_freqlimit & 0x0f) << 0);
sci_write(SCI_BASS, bassCalced);
DEBUGOUT("VS1053b: Change bass settings to:\r\n")
DEBUGOUT("VS1053b: --Treble: Amplitude=%i, Frequency=%i\r\n", getTrebleAmplitude(), getTrebleFrequency());
DEBUGOUT("VS1053b: --Bass: Amplitude=%i, Frequency=%i\r\n", getBassAmplitude(), getBassFrequency());
}
/*===================================================================
* Buffer handling
*==================================================================*/
unsigned int VS1053::bufferLength(void)
{
return BUFFER_SIZE;
}
unsigned char VS1053::bufferGetByte(void)
{
unsigned char retVal = 0x00;
if (bufferCount() > 0x00)
{
retVal = *_bufferReadPointer++;
if (_bufferReadPointer >= _buffer + BUFFER_SIZE)
{
_bufferReadPointer = _buffer;
}
}
return retVal;
}
bool VS1053::bufferSetByte(char c)
{
if (bufferFree() > 0x00)
{
*_bufferWritePointer++ = c;
if (_bufferWritePointer >= _buffer + BUFFER_SIZE)
{
_bufferWritePointer = _buffer;
}
return true;
}
return false;
}
bool VS1053::bufferPutStream(const char *s, unsigned int length)
{
if (bufferFree() >= length)
{
while (length--)
{
*_bufferWritePointer++ = *s++;
if (_bufferWritePointer >= _buffer + BUFFER_SIZE)
{
_bufferWritePointer = _buffer;
}
}
return true;
}
return false;
}
unsigned int VS1053::bufferFree(void)
{
if(_bufferReadPointer > _bufferWritePointer)
{
return _bufferReadPointer - _bufferWritePointer - 1;
}
else if(_bufferReadPointer < _bufferWritePointer)
{
return BUFFER_SIZE - (_bufferWritePointer - _bufferReadPointer) - 1;
}
return BUFFER_SIZE - 1;
}
unsigned int VS1053::bufferCount(void)
{
return BUFFER_SIZE - bufferFree() - 1;
}
void VS1053::bufferReset(void)
{
_bufferReadPointer = _buffer;
_bufferWritePointer = _buffer;
}
#ifdef VS1053_RTOS
void VS1053::dataRequestHandler_start(const void *args)
{
VS1053 *instance = (VS1053*)args;
instance->dataRequestHandler();
}
#endif
void VS1053::dataRequestHandler(void)
{
#ifdef VS1053_RTOS
_thread.signal_wait(START_THREAD);
while(1)
{
if (!_DREQ || !_isPlay) {
Thread::wait(10);
continue;
}
#else
if (_isIdle && _DREQ)
{
#endif
_isIdle = false;
#ifdef DEBUG
_led = 0;
#endif
// write buffer to vs1053b
unsigned length = bufferCount();
int i = 0;
sdi_en();
while (length > 0)
{
int l2 = (length > 32) ? 32 : length;
//DEBUGOUT("L2: %i\r\n", l2);
for( ; l2 != 0; l2--)
{
_spi.write(bufferGetByte());
}
length -= l2;
//wait_us(50);
if (!_DREQ || i > 4)
break;
i++;
}
sdi_dis();
#ifdef DEBUG
_led = 1;
#endif
_isIdle = true;
#ifdef VS1053_RTOS
//Thread::wait(10);
Thread::yield();
#endif
}
}
void VS1053::play(void)
{
INTERRUPT_HANDLER_ENABLE;
DEBUGOUT("VS1053b: Play.\r\n");
}
void VS1053::pause(void)
{
INTERRUPT_HANDLER_DISABLE;
DEBUGOUT("VS1053b: Pause.\r\n");
#ifdef DEBUG
_led = 1;
#endif
}
void VS1053::stop(void)
{
INTERRUPT_HANDLER_DISABLE;
#ifndef VS1053_RTOS
__disable_irq();
#endif
DEBUGOUT("VS1053b: Song stoping..\r\n");
while(!_isIdle)
;
// set SCI MODE bit SM CANCEL
unsigned short sciModeByte = sci_read(SCI_MODE);
sciModeByte |= SM_CANCEL;
sci_write(SCI_MODE, sciModeByte);
// send up 2048 bytes of audio data.
for (int i = 0; i < 64; i++)
{
// send at least 32 bytes of audio data
int z = bufferCount();
if (z > 32)
z = 32;
for (int n = 0; n < z; n++)
{
_spi.write(bufferGetByte());
}
// read SCI MODE; if SM CANCEL is still set, repeat
sciModeByte = sci_read(SCI_MODE);
if ((sciModeByte & SM_CANCEL) == 0x0000)
{
break;
}
}
if ((sciModeByte & SM_CANCEL) == 0x0000)
{
// send at least 2052 bytes of endFillByte[7:0].
// read endFillByte (0 .. 15) from wram
unsigned short endFillByte=wram_read(para_endFillByte);
// clear endFillByte (8 .. 15)
endFillByte = endFillByte ^0x00FF;
for (int n = 0; n < 2052; n++)
sdi_write(endFillByte);
DEBUGOUT("VS1053b: Song sucessfully stopped.\r\n");
DEBUGOUT("VS1053b: SCI MODE = %#x, SM_CANCEL = %#x\r\n", sciModeByte, sciModeByte & SM_CANCEL);
sci_write(SCI_DECODE_TIME, 0x0000);
}
else
{
DEBUGOUT("VS1053b: SM CANCEL hasn't cleared after sending 2048 bytes, do software reset\r\n");
DEBUGOUT("VS1053b: SCI MODE = %#x, SM_CANCEL = %#x\r\n", sciModeByte, sciModeByte & SM_CANCEL);
initialize();
}
bufferReset();
#ifndef VS1053_RTOS
__enable_irq();
#endif
}
void VS1053::getAudioInfo(AudioInfo* aInfo)
{
// volume calculation
unsigned short hdat0 = sci_read(SCI_HDAT0);
unsigned short hdat1 = sci_read(SCI_HDAT1);
DEBUGOUT("VS1053b: Audio info\r\n");
AudioInfo* retVal = aInfo;
retVal->type = UNKNOWN;
if (hdat1 == 0x7665)
{
// audio is WAV
retVal->type = WAV;
}
else if (hdat1 == 0x4154 || hdat1 == 0x4144 || hdat1 == 0x4D34 )
{
// audio is AAC
retVal->type = AAC;
}
else if (hdat1 == 0x574D )
{
// audio is WMA
retVal->type = WMA;
}
else if (hdat1 == 0x4D54 )
{
// audio is MIDI
retVal->type = MIDI;
}
else if (hdat1 == 0x4F76 )
{
// audio is OGG VORBIS
retVal->type = OGG_VORBIS;
}
else if (hdat1 >= 0xFFE0 && hdat1 <= 0xFFFF)
{
// audio is mp3
retVal->type = MP3;
DEBUGOUT("VS1053b: Audio is mp3\r\n");
retVal->ext.mp3.id = (MP3_ID)((hdat1 >> 3) & 0x0003);
switch((hdat1 >> 1) & 0x0003)
{
case 3:
retVal->ext.mp3.layer = 1;
break;
case 2:
retVal->ext.mp3.layer = 2;
break;
case 1:
retVal->ext.mp3.layer = 3;
break;
default:
retVal->ext.mp3.layer = 0;
break;
}
retVal->ext.mp3.protrectBit = (hdat1 >> 0) & 0x0001;
char srate = (hdat0 >> 10) & 0x0003;
retVal->ext.mp3.kSampleRate = _sampleRateTable[retVal->ext.mp3.id][srate];
retVal->ext.mp3.padBit = (hdat0 >> 9) & 0x0001;
retVal->ext.mp3.mode =(MP3_MODE)((hdat0 >> 6) & 0x0003);
retVal->ext.mp3.extension = (hdat0 >> 4) & 0x0003;
retVal->ext.mp3.copyright = (hdat0 >> 3) & 0x0001;
retVal->ext.mp3.original = (hdat0 >> 2) & 0x0001;
retVal->ext.mp3.emphasis = (hdat0 >> 0) & 0x0003;
DEBUGOUT("VS1053b: ID: %i, Layer: %i, Samplerate: %i, Mode: %i\r\n", retVal->ext.mp3.id, retVal->ext.mp3.layer, retVal->ext.mp3.kSampleRate, retVal->ext.mp3.mode);
}
// read byteRate
unsigned short byteRate = wram_read(para_byteRate);
retVal->kBitRate = (byteRate * 8) / 1000;
DEBUGOUT("VS1053b: BitRate: %i kBit/s\r\n", retVal->kBitRate);
// decode time
retVal->decodeTime = sci_read(SCI_DECODE_TIME);
DEBUGOUT("VS1053b: Decodetime: %i s\r\n", retVal->decodeTime);
}
ban4jp -
