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