Just a simple library for VLSI's mp3/midi codec chip

Dependents:   IsuProject_LPC1768

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers VS1053.cpp Source File

VS1053.cpp

00001 // ==================================================== Dec 21 2013, kayeks ==
00002 // VS1053.cpp
00003 // ===========================================================================
00004 // Just a simple library for VLSI's mp3/midi codec chip
00005 //   - Minimal and simple implementation (and dirty too)
00006 
00007 #include "mbed.h"
00008 #include "VS1053.h"
00009 
00010 /** Constructor of class VS1053. */
00011 VS1053::VS1053(PinName mosiPin, PinName misoPin, PinName sckPin,
00012                PinName csPin, PinName bsyncPin, PinName dreqPin,
00013                PinName rstPin, uint32_t spiFrequency)
00014 :
00015     spi(mosiPin, misoPin, sckPin),
00016     cs(csPin),
00017     bsync(bsyncPin),
00018     dreq(dreqPin),
00019     rst(rstPin)
00020 {
00021     spi.format(8, 0);
00022     spi.frequency(spiFrequency);
00023 
00024     // Initialize outputs
00025     cs = 1;
00026     bsync = 1;
00027     rst = 1;
00028 }
00029 
00030 /** Destructor of class VS1053. */
00031 VS1053::~VS1053() {
00032 }
00033 
00034 /** Make a hardware reset by hitting VS1053's RESET pin. */
00035 void VS1053::hardwareReset() {
00036     rst = 0;
00037     wait(.05);
00038     rst = 1;
00039     wait(.05);
00040 }
00041 
00042 /** Send a data byte to VS1053. */
00043 void VS1053::sendDataByte(uint8_t data) {
00044     while (!dreq);
00045     bsync = 0;
00046     spi.write(data);
00047     bsync = 1;
00048 }
00049 
00050 /** Send a data block specified as a pointer to VS1053.
00051  *  @return Data length successfully sent.
00052  */
00053 size_t VS1053::sendDataBlock(uint8_t* data, size_t length) {
00054     size_t n, sizeSent = 0;
00055     
00056     if (!data || !length) return 0;
00057     while (length) {
00058         n = length < 32 ? length : 32;
00059         while (!dreq);
00060         bsync = 0;
00061         for (uint32_t i = 0; i < n; i++) {
00062             spi.write(*data++);
00063             sizeSent++; length--;
00064         }
00065         bsync = 1;
00066     }
00067     return sizeSent;
00068 }
00069 
00070 /** Change VS1053's PLL setting for speedup. */
00071 void VS1053::clockUp() {
00072     // Set CLKI to 43.0-55.3 MHz
00073     writeReg(SCI_CLOCKF, 0x8800);  // SC_MULT=4 (3.5x), SC_ADD=1 (+1.0x)
00074     wait(0.01);
00075 }
00076 
00077 /** Send cancel request to VS1053.
00078  *  @return Zero at failure, non-zero at success.
00079  */
00080 bool VS1053::sendCancel() {
00081     uint16_t reg;
00082     
00083     // Set SM_CANCEL bit
00084     reg = readReg(SCI_MODE);
00085     if (reg & 0x0008) {
00086         // Abort if SM_CANCEL is still set
00087         return false;
00088     }
00089     writeReg(SCI_MODE, reg | 0x0008);
00090     return true;
00091 }
00092 
00093 /** Attempt a termination of playing.
00094  *  Please call this repeatedly during data stream tramsission until it successes.
00095  *  @return Zero at failure, non-zero at success.
00096  */
00097 bool VS1053::stop() {
00098     uint16_t reg;
00099     uint8_t  endFillByte;
00100     size_t   n, length;
00101     
00102     // If SM_CANCEL is still set, do nothing
00103     reg = readReg(SCI_MODE);
00104     if (reg & 0x0008) {
00105         return false;
00106     }
00107     
00108     // Read endFillByte from XRAM <1E06h>
00109     writeReg(SCI_WRAMADDR, 0x1e06);
00110     reg = readReg(SCI_WRAM);
00111     
00112     // Send lower 8 bits of endFillByte 2,052 times
00113     endFillByte = reg & 0xff;
00114     length = 2052;
00115     while (length) {
00116         n = length < 32 ? length : 32;
00117         while (!dreq);
00118         bsync = 0;
00119         for (uint32_t i = 0; i < n; i++) {
00120             spi.write(endFillByte);
00121             length--;
00122         }
00123         bsync = 1;
00124     }
00125     // Check if both HDAT0 and HDAT1 are cleared
00126     return readReg(SCI_HDAT0) == 0x0000 && readReg(SCI_HDAT1) == 0x0000;
00127 }
00128 
00129 /** Write to an SCI (Serial Control Interface) register entry. */
00130 void VS1053::writeReg(uint8_t addr, uint16_t word) {
00131     // If addr is out-of-range, do nothing
00132     if (addr > 0x0f) {
00133         return;
00134     }
00135 
00136     while (!dreq);
00137     cs = 0;
00138     spi.write(0x02);         // Send a "Write SCI" instruction (02h),
00139     spi.write(addr);         // target address,
00140     spi.write(word >> 8);    // high byte,
00141     spi.write(word & 0xff);  // then low byte
00142     while (!dreq);
00143     cs = 1;
00144 }
00145 
00146 /** Read an SCI (Serial Control Interface) register entry.
00147  *  @return Register value or 0000h when invalid address was specified.
00148  */
00149 uint16_t VS1053::readReg(uint8_t addr) {
00150     uint16_t word;
00151     
00152     // If addr is out-of-range, return 0000h
00153     if (addr > 0x0f) {
00154         return 0x0000;
00155     }
00156 
00157     while (!dreq);
00158     cs = 0;
00159     spi.write(0x03);              // Send a "Read SCI" instruction (03h)
00160     spi.write(addr);              // and target address
00161     word = spi.write(0xff) << 8;  // Receive high byte with dummy data FFh
00162     word |= spi.write(0xff);      // Receive low byte
00163     while (!dreq);
00164     cs = 1;
00165     return word;
00166 }