Tomas Kucera / VS1053

Dependents:   HagridOS5

Fork of VS1053 by Vassilis Serasidis

Revision:
9:e5337a55871a
Parent:
8:5ad25d480d5f
diff -r 5ad25d480d5f -r e5337a55871a VS1053.cpp
--- a/VS1053.cpp	Thu Nov 26 14:21:36 2015 +0000
+++ b/VS1053.cpp	Wed Feb 21 14:57:39 2018 +0000
@@ -1,200 +1,326 @@
-/**
- *  ==================================================== Dec 21 2013, kayeks ==
- *  VS1053.cpp
- *  ===========================================================================
- *  Just a simple library for VLSI's mp3/midi codec chip
- *       - Minimal and simple implementation (and dirty too)
- *
- *  Modified on 05 September 2015 by Vassilis Serasidis.
- *       -   Added a patch for playing MP3 files on some "LC Technology" VS1053 boards.
- *
- *
- */
-
+#include "VS1053.h"
 #include "mbed.h"
-#include "VS1053.h"
-
-/** Constructor of class VS1053. */
-VS1053::VS1053(PinName mosiPin, PinName misoPin, PinName sckPin,
-               PinName csPin, PinName bsyncPin, PinName dreqPin,
-               PinName rstPin, uint32_t spiFrequency)
-:
-    spi(mosiPin, misoPin, sckPin),
-    cs(csPin),
-    bsync(bsyncPin), //dcs pin
-    dreq(dreqPin),
-    rst(rstPin)
+ 
+// patch binary
+#include "VS1053b_patch.c"
+// spectrum analyzer binary
+#include "VS1053b_specana.c"
+ 
+//Serial pc(USBTX, USBRX);
+ 
+/* ==================================================================
+ * Constructor
+ * =================================================================*/
+VS1053::VS1053(
+         PinName mosi, PinName miso, PinName sck, PinName cs, PinName rst,
+         PinName dreq, PinName dcs, PinName vol)
+    :
+     _spi(mosi, miso, sck), 
+     _CS(cs), 
+     _RST(rst), 
+     _DREQ(dreq),
+     _DCS(dcs), 
+     _VOL(vol) {
+        firstTime=-1;    
+    }    
+ 
+/*===================================================================
+ * Functions
+ *==================================================================*/
+ 
+void VS1053::cs_low(void)
+{
+    _CS = 0;                                
+}
+void VS1053::cs_high(void)
+{
+    _CS = 1;                                
+}
+void VS1053::dcs_low(void)
 {
-    //spi.format(8, 0);
-    //spi.frequency(spiFrequency);
-
-    // Initialize outputs
-    cs = 1;
-    bsync = 1;
-    rst = 1;
+    _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();
 }
-
-/** Destructor of class VS1053. */
-VS1053::~VS1053() {
+void VS1053::sdi_dis(void)                    //SDI disable
+{
+    dcs_high();
 }
-
-/** Make a hardware reset by hitting VS1053's RESET pin. */
-void VS1053::hardwareReset() {
-    rst = 0;
-    wait(.05);
-    rst = 1;
-    wait(.05);
+void VS1053::reset(void)                    //hardware reset
+{
+//    wait(0.01);
+    wait_ms(10);
+    _RST = 0;
+//    wait(0.01);
+    wait_ms(5);
+    _RST = 1;
+//    wait(0.10);
+    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();
 }
-
-/** Patch for some LC Technology VS1053 board with "no sound" problem. 
- *  5 September 2015 bby Vassilis Serasidis 
- */
-void VS1053::modeSwitch(void)
+void VS1053::sci_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)
 {
-    //GPIO_DDR
-    writeReg(SCI_WRAMADDR, 0xc017);
-    writeReg(SCI_WRAM, 0x0003);
-  
-    wait(.05);
-    writeReg(SCI_MODE, (1<<SM_SDINEW) | (1<<SM_RESET));
-    wait(.05);
+    _spi.format(8,0);
+//    _spi.frequency(7000000);                //set to 7MHz
+//    _spi.frequency(12000000);                //set to 12MHz to make fast transfer
+    _spi.frequency(18000000);                //set to 18MHz to make fast transfer
+//NG does not work//    _spi.frequency(24000000);                //set to 24MHz to make fast transfer
+    
+    cs_high();
+    dcs_high();
 }
-
-/** Send a data byte to VS1053. */
-void VS1053::sendDataByte(uint8_t data) {
-    while (!dreq);
-    bsync = 0;
-    spi.write(data);
-    bsync = 1;
+void VS1053::sci_write(unsigned char address, unsigned short int data)
+{
+    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);
 }
-
-/** Send a data block specified as a pointer to VS1053.
- *  @return Data length successfully sent.
- */
-size_t VS1053::sendDataBlock(char* data, size_t length) {
-    size_t n, sizeSent = 0;
+void VS1053::sdi_write(unsigned char datum)
+{
+    sdi_en();
+    
+    while(!_DREQ);
+    _spi.write(datum);
+    
+//?    sci_dis();
+      sdi_dis();
+}
+unsigned short int VS1053::sci_read(unsigned short int address)
+{
+    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
+    
+    return received;                        //return received word
+}
+void VS1053::sine_test_activate(unsigned char wave)
+{
+    cs_high();                                //enables SDI/disables SCI
     
-    if (!data || !length) return 0;
-    while (length) {
-        n = length < 32 ? length : 32;
-        while (!dreq);
-        bsync = 0;
-        for (uint32_t i = 0; i < n; i++) {
-            spi.write(*data++);
-            sizeSent++; length--;
-        }
-        bsync = 1;
-    }
-    return sizeSent;
+    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
 }
-
-/** Change VS1053's PLL setting for speedup. */
-void VS1053::clockUp() {
-    // Set CLKI to 43.0-55.3 MHz
-    writeReg(SCI_CLOCKF, 0x8800);  // SC_MULT=4 (3.5x), SC_ADD=1 (+1.0x)
-    wait(0.01);
+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
 }
+void VS1053::volume(uint8_t left, uint8_t right)
+{
 
-/** Send cancel request to VS1053.
- *  @return Zero at failure, non-zero at success.
- */
-bool VS1053::sendCancel() {
-    uint16_t reg;
-    
-    // Set SM_CANCEL bit
-    reg = readReg(SCI_MODE);
-    if (reg & 0x0008) {
-        // Abort if SM_CANCEL is still set
-        return false;
-    }
-    writeReg(SCI_MODE, reg | 0x0008);
-    return true;
-}
 
-/** Attempt a termination of playing.
- *  Please call this repeatedly during data stream tramsission until it successes.
- *  @return Zero at failure, non-zero at success.
- */
-bool VS1053::stop() {
-    uint16_t reg;
-    uint8_t  endFillByte;
-    size_t   n, length;
-    
-    // If SM_CANCEL is still set, do nothing
-    reg = readReg(SCI_MODE);
-    if (reg & 0x0008) {
-        return false;
-    }
-    
-    // Read endFillByte from XRAM <1E06h>
-    writeReg(SCI_WRAMADDR, 0x1e06);
-    reg = readReg(SCI_WRAM);
-    
-    // Send lower 8 bits of endFillByte 2,052 times
-    endFillByte = reg & 0xff;
-    length = 2052;
-    while (length) {
-        n = length < 32 ? length : 32;
-        while (!dreq);
-        bsync = 0;
-        for (uint32_t i = 0; i < n; i++) {
-            spi.write(endFillByte);
-            length--;
-        }
-        bsync = 1;
-    }
-    // Check if both HDAT0 and HDAT1 are cleared
-    return readReg(SCI_HDAT0) == 0x0000 && readReg(SCI_HDAT1) == 0x0000;
-}
+  uint16_t v;
+  v = left;
+  v <<= 8;
+  v |= right;
 
-/**
- * Set the VS1053 volume.
- *
- */
-void VS1053::setVolume(uint8_t vol)
+    while(!_DREQ);
+    
+    sci_write(0x0B, v);
+}
+ 
+void VS1053::writeStream(unsigned char *array, int size)
+{
+   for(int i=0; i<size; i++)
+   {
+       sdi_write(array[i]);
+   }
+   volume(50,50);
+}
+ 
+#if 0
+// this function does not work
+// because of function call overhead
+void VS1053::putcStream(unsigned char datum)
+{
+    sdi_write(datum);
+}
+#endif
+ 
+unsigned short int VS1053::wram_read(unsigned short int address)
 {
-  uint16_t value = vol;
-  value <<= 8;
-  value |= vol;
-
-  writeReg(SCI_VOL,value); // VOL
+    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;
 }
-
-/** Write to an SCI (Serial Control Interface) register entry. */
-void VS1053::writeReg(uint8_t addr, uint16_t word) {
-    // If addr is out-of-range, do nothing
-    if (addr > 0x0f) {
-        return;
+ 
+ 
+void VS1053::terminateStream(void)
+{
+#if 1
+    unsigned int endFillByte=wram_read(para_endFillByte);
+//    printf("endFillByte:%04X\r\n",endFillByte); // debug
+    for(int n=0; n<2052; n++) sdi_write(0xFF&endFillByte);
+    sci_write(SCI_MODE,(SM_SDINEW+SM_CANCEL));
+    for(int n=0; n<2048; n++) sdi_write(0xFF&endFillByte);
+    // don't reset if you don't want to lose the patch 
+    //    sci_write(SCI_MODE,(SM_SDINEW+SM_RESET)); //  set mode reg.
+    //    wait_ms(10); 
+#endif 
+}
+ 
+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);
+      }
     }
-
-    while (!dreq);
-    cs = 0;
-    spi.write(0x02);         // Send a "Write SCI" instruction (02h),
-    spi.write(addr);         // target address,
-    spi.write(word >> 8);    // high byte,
-    spi.write(word & 0xff);  // then low byte
-    while (!dreq);
-    cs = 1;
+    else //copy run, copy n sample
+    {
+      while(n--)
+      {
+        val = plugin[i++];
+        sci_write(addr,val);
+      }
+    }
+  }
+ 
+  return;
 }
-
-/** Read an SCI (Serial Control Interface) register entry.
- *  @return Register value or 0000h when invalid address was specified.
- */
-uint16_t VS1053::readReg(uint8_t addr) {
-    uint16_t word;
-    
-    // If addr is out-of-range, return 0000h
-    if (addr > 0x0f) {
-        return 0x0000;
+ 
+ 
+void VS1053::initialize(void)
+{
+    _RST = 1;
+    cs_high();                           //chip disabled
+    sci_initialise();                    //initialise MBED
+    sci_write(SCI_MODE,(SM_SDINEW+SM_RESET)); //  set mode reg.
+    wait_ms(10); 
+#if 1
+       // debug
+        unsigned int chipID_0=wram_read(para_chipID_0);
+        if (firstTime) printf("chipID_0:%04X\r\n",chipID_0); // debug
+        unsigned int chipID_1=wram_read(para_chipID_1);
+        if (firstTime) printf("chipID_1:%04X\r\n",chipID_1); // debug      
+        unsigned int struct_version=wram_read(para_version);
+        if (firstTime) printf("structure version:%04X\r\n",struct_version); // debug      
+ #endif
+    //get chip version, set clock multiplier and load patch
+    int i = (sci_read(SCI_STATUS)&0xF0)>>4;
+    if(i == 4) 
+    {
+        if (firstTime) printf("Installed Chip is: VS1053\r\n");
+        sci_write(SCI_CLOCKF, (SC_MULT_XTALIx50+SC_ADD_20x)); 
+#ifdef VS_PATCH
+        // loading patch
+        write_plugin(vs1053b_patch, sizeof(vs1053b_patch)/2);
+        if (firstTime) {
+            printf("VS1053b patch loaded.\r\n");
+            printf("patch size:%d bytes\r\n",sizeof(vs1053b_patch));
+        }
+#endif
+#ifdef VS_SPECANA
+        // loading plugin(spectrum analyzer)
+        write_plugin(vs1053b_specana, sizeof(vs1053b_specana)/2);
+        if (firstTime) printf("VS1053b specana loaded.\r\n");
+#endif
     }
-
-    while (!dreq);
-    cs = 0;
-    spi.write(0x03);              // Send a "Read SCI" instruction (03h)
-    spi.write(addr);              // and target address
-    word = spi.write(0xff) << 8;  // Receive high byte with dummy data FFh
-    word |= spi.write(0xff);      // Receive low byte
-    while (!dreq);
-    cs = 1;
-    return word;
-}
+    else printf("??? Not Supported Chip???\r\n");
+    sdi_initialise(); 
+    firstTime=0; // disable message when init after 1st time
+}
\ No newline at end of file