1

Dependents:   internet_radio_leo

Fork of VS1053 by Vassilis Serasidis

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers VS1053.cpp Source File

VS1053.cpp

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