Library for VLSI VS1053b - Ogg Vorbis / MP3 / AAC / WMA / FLAC / MIDI Audio Codec Chip for a complete sample see Lib_VS1053b
Dependents: Lab3_1 RTOS-VS1053b-mp3_semaphore RTOS-VS1053b-mp3_v01
VS1053.cpp
- Committer:
- christi_s
- Date:
- 2010-12-25
- Revision:
- 5:ead95c0f7800
- Parent:
- 4:cacb5e663fa9
- Child:
- 6:eed008905159
File content as of revision 5:ead95c0f7800:
/* 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" void test(void) { // DEBUGOUT("Interupt\r\n"); } /* ================================================================== * Constructor * =================================================================*/ VS1053::VS1053( PinName mosi, PinName miso, PinName sck, PinName cs, PinName rst, PinName dreq, PinName dcs) : _spi(mosi, miso, sck), _CS(cs), _RST(rst), _DCS(dcs), _DREQ(dreq), _DREQ_INTERUPT_IN(dreq) { _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; _DREQ_INTERUPT_IN.mode(PullDown); INTERRUPT_HANDLER_DISABLE; bufferReset(); } /*=================================================================== * 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); } 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); //TODO: testing 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; 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 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(unsigned char c) { if (bufferFree() > 0x00) { *_bufferWritePointer++ = c; if (_bufferWritePointer >= _buffer + BUFFER_SIZE) { _bufferWritePointer = _buffer; } return true; } return false; } bool VS1053::bufferPutStream(const unsigned 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; } void VS1053::dataRequestHandler(void) { if (_isIdle && _DREQ) { _isIdle = false; // 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; if (!_DREQ || i > 4) break; i++; } sdi_dis(); _isIdle = true; } } void VS1053::play(void) { INTERRUPT_HANDLER_ENABLE; DEBUGOUT("VS1053b: Play.\r\n"); } void VS1053::pause(void) { INTERRUPT_HANDLER_DISABLE; DEBUGOUT("VS1053b: Pause.\r\n"); } void VS1053::stop(void) { INTERRUPT_HANDLER_DISABLE; __disable_irq(); 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); } 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); //TODO: testing initialize(); } bufferReset(); __enable_irq(); }