1

Dependents:   internet_radio_leo

Fork of VS1053 by Vassilis Serasidis

Committer:
silis
Date:
Sat Sep 05 12:16:06 2015 +0000
Revision:
7:97a8edd44fe9
Parent:
6:1f57fbd3aeb5
Child:
8:e23900b0f1ca
Library for using the VS1053 MP3 decoder board with the WIZwiki-W7500 ARM Cortex-M0 SoC

Who changed what in which revision?

UserRevisionLine numberNew contents of line
silis 7:97a8edd44fe9 1 /**
silis 7:97a8edd44fe9 2 * ==================================================== Dec 21 2013, kayeks ==
silis 7:97a8edd44fe9 3 * VS1053.cpp
silis 7:97a8edd44fe9 4 * ===========================================================================
silis 7:97a8edd44fe9 5 * Just a simple library for VLSI's mp3/midi codec chip
silis 7:97a8edd44fe9 6 * - Minimal and simple implementation (and dirty too)
silis 7:97a8edd44fe9 7 *
silis 7:97a8edd44fe9 8 * Modified on 05 September 2015 by Vassilis Serasidis.
silis 7:97a8edd44fe9 9 * - Added a patch for playing MP3 files on some "LC Technology" VS1053 boards.
silis 7:97a8edd44fe9 10 *
silis 7:97a8edd44fe9 11 *
silis 7:97a8edd44fe9 12 */
kayekss 0:708868399033 13
kayekss 0:708868399033 14 #include "mbed.h"
kayekss 0:708868399033 15 #include "VS1053.h"
kayekss 0:708868399033 16
kayekss 2:47ba7e2259cd 17 /** Constructor of class VS1053. */
kayekss 0:708868399033 18 VS1053::VS1053(PinName mosiPin, PinName misoPin, PinName sckPin,
kayekss 0:708868399033 19 PinName csPin, PinName bsyncPin, PinName dreqPin,
kayekss 0:708868399033 20 PinName rstPin, uint32_t spiFrequency)
kayekss 0:708868399033 21 :
kayekss 0:708868399033 22 spi(mosiPin, misoPin, sckPin),
kayekss 0:708868399033 23 cs(csPin),
kayekss 0:708868399033 24 bsync(bsyncPin),
kayekss 0:708868399033 25 dreq(dreqPin),
kayekss 0:708868399033 26 rst(rstPin)
kayekss 0:708868399033 27 {
kayekss 0:708868399033 28 spi.format(8, 0);
kayekss 0:708868399033 29 spi.frequency(spiFrequency);
kayekss 0:708868399033 30
kayekss 0:708868399033 31 // Initialize outputs
kayekss 0:708868399033 32 cs = 1;
kayekss 0:708868399033 33 bsync = 1;
kayekss 0:708868399033 34 rst = 1;
kayekss 0:708868399033 35 }
kayekss 0:708868399033 36
kayekss 2:47ba7e2259cd 37 /** Destructor of class VS1053. */
kayekss 0:708868399033 38 VS1053::~VS1053() {
kayekss 0:708868399033 39 }
kayekss 0:708868399033 40
kayekss 2:47ba7e2259cd 41 /** Make a hardware reset by hitting VS1053's RESET pin. */
kayekss 0:708868399033 42 void VS1053::hardwareReset() {
kayekss 0:708868399033 43 rst = 0;
kayekss 0:708868399033 44 wait(.05);
kayekss 0:708868399033 45 rst = 1;
kayekss 0:708868399033 46 wait(.05);
kayekss 0:708868399033 47 }
kayekss 0:708868399033 48
silis 7:97a8edd44fe9 49 /** Patch for some LC Technology VS1053 board with "no sound" problem.
silis 7:97a8edd44fe9 50 * 5 September 2015 bby Vassilis Serasidis
silis 7:97a8edd44fe9 51 */
silis 7:97a8edd44fe9 52 void VS1053::modeSwitch(void)
silis 7:97a8edd44fe9 53 {
silis 7:97a8edd44fe9 54 //GPIO_DDR
silis 7:97a8edd44fe9 55 writeReg(SCI_WRAMADDR, 0xc017);
silis 7:97a8edd44fe9 56 writeReg(SCI_WRAM, 0x0003);
silis 7:97a8edd44fe9 57
silis 7:97a8edd44fe9 58 wait(.05);
silis 7:97a8edd44fe9 59 writeReg(SCI_MODE, (1<<SM_SDINEW) | (1<<SM_RESET));
silis 7:97a8edd44fe9 60 wait(.05);
silis 7:97a8edd44fe9 61 }
silis 7:97a8edd44fe9 62
kayekss 2:47ba7e2259cd 63 /** Send a data byte to VS1053. */
kayekss 2:47ba7e2259cd 64 void VS1053::sendDataByte(uint8_t data) {
kayekss 0:708868399033 65 while (!dreq);
kayekss 0:708868399033 66 bsync = 0;
kayekss 2:47ba7e2259cd 67 spi.write(data);
kayekss 0:708868399033 68 bsync = 1;
kayekss 0:708868399033 69 }
kayekss 0:708868399033 70
kayekss 2:47ba7e2259cd 71 /** Send a data block specified as a pointer to VS1053.
kayekss 2:47ba7e2259cd 72 * @return Data length successfully sent.
kayekss 2:47ba7e2259cd 73 */
kayekss 4:6e0fb5342efa 74 size_t VS1053::sendDataBlock(uint8_t* data, size_t length) {
kayekss 5:cbf43dc9c947 75 size_t n, sizeSent = 0;
kayekss 0:708868399033 76
kayekss 4:6e0fb5342efa 77 if (!data || !length) return 0;
kayekss 5:cbf43dc9c947 78 while (length) {
kayekss 5:cbf43dc9c947 79 n = length < 32 ? length : 32;
kayekss 0:708868399033 80 while (!dreq);
kayekss 1:00c19f771676 81 bsync = 0;
kayekss 4:6e0fb5342efa 82 for (uint32_t i = 0; i < n; i++) {
kayekss 4:6e0fb5342efa 83 spi.write(*data++);
kayekss 5:cbf43dc9c947 84 sizeSent++; length--;
kayekss 0:708868399033 85 }
kayekss 1:00c19f771676 86 bsync = 1;
kayekss 0:708868399033 87 }
kayekss 0:708868399033 88 return sizeSent;
kayekss 0:708868399033 89 }
kayekss 0:708868399033 90
kayekss 2:47ba7e2259cd 91 /** Change VS1053's PLL setting for speedup. */
kayekss 0:708868399033 92 void VS1053::clockUp() {
kayekss 0:708868399033 93 // Set CLKI to 43.0-55.3 MHz
kayekss 0:708868399033 94 writeReg(SCI_CLOCKF, 0x8800); // SC_MULT=4 (3.5x), SC_ADD=1 (+1.0x)
kayekss 4:6e0fb5342efa 95 wait(0.01);
kayekss 0:708868399033 96 }
kayekss 0:708868399033 97
kayekss 2:47ba7e2259cd 98 /** Send cancel request to VS1053.
kayekss 3:696c8e6744b2 99 * @return Zero at failure, non-zero at success.
kayekss 2:47ba7e2259cd 100 */
kayekss 0:708868399033 101 bool VS1053::sendCancel() {
kayekss 0:708868399033 102 uint16_t reg;
kayekss 0:708868399033 103
kayekss 0:708868399033 104 // Set SM_CANCEL bit
kayekss 0:708868399033 105 reg = readReg(SCI_MODE);
kayekss 0:708868399033 106 if (reg & 0x0008) {
kayekss 0:708868399033 107 // Abort if SM_CANCEL is still set
kayekss 3:696c8e6744b2 108 return false;
kayekss 0:708868399033 109 }
kayekss 0:708868399033 110 writeReg(SCI_MODE, reg | 0x0008);
kayekss 3:696c8e6744b2 111 return true;
kayekss 0:708868399033 112 }
kayekss 0:708868399033 113
kayekss 4:6e0fb5342efa 114 /** Attempt a termination of playing.
kayekss 4:6e0fb5342efa 115 * Please call this repeatedly during data stream tramsission until it successes.
kayekss 3:696c8e6744b2 116 * @return Zero at failure, non-zero at success.
kayekss 2:47ba7e2259cd 117 */
kayekss 0:708868399033 118 bool VS1053::stop() {
kayekss 0:708868399033 119 uint16_t reg;
kayekss 5:cbf43dc9c947 120 uint8_t endFillByte;
kayekss 5:cbf43dc9c947 121 size_t n, length;
kayekss 0:708868399033 122
kayekss 0:708868399033 123 // If SM_CANCEL is still set, do nothing
kayekss 0:708868399033 124 reg = readReg(SCI_MODE);
kayekss 0:708868399033 125 if (reg & 0x0008) {
kayekss 3:696c8e6744b2 126 return false;
kayekss 0:708868399033 127 }
kayekss 0:708868399033 128
kayekss 0:708868399033 129 // Read endFillByte from XRAM <1E06h>
kayekss 0:708868399033 130 writeReg(SCI_WRAMADDR, 0x1e06);
kayekss 0:708868399033 131 reg = readReg(SCI_WRAM);
kayekss 0:708868399033 132
kayekss 0:708868399033 133 // Send lower 8 bits of endFillByte 2,052 times
kayekss 0:708868399033 134 endFillByte = reg & 0xff;
kayekss 0:708868399033 135 length = 2052;
kayekss 0:708868399033 136 while (length) {
kayekss 5:cbf43dc9c947 137 n = length < 32 ? length : 32;
kayekss 0:708868399033 138 while (!dreq);
kayekss 1:00c19f771676 139 bsync = 0;
kayekss 5:cbf43dc9c947 140 for (uint32_t i = 0; i < n; i++) {
kayekss 0:708868399033 141 spi.write(endFillByte);
kayekss 5:cbf43dc9c947 142 length--;
kayekss 0:708868399033 143 }
kayekss 1:00c19f771676 144 bsync = 1;
kayekss 0:708868399033 145 }
kayekss 0:708868399033 146 // Check if both HDAT0 and HDAT1 are cleared
kayekss 0:708868399033 147 return readReg(SCI_HDAT0) == 0x0000 && readReg(SCI_HDAT1) == 0x0000;
kayekss 0:708868399033 148 }
kayekss 0:708868399033 149
kayekss 2:47ba7e2259cd 150 /** Write to an SCI (Serial Control Interface) register entry. */
kayekss 0:708868399033 151 void VS1053::writeReg(uint8_t addr, uint16_t word) {
kayekss 0:708868399033 152 // If addr is out-of-range, do nothing
kayekss 0:708868399033 153 if (addr > 0x0f) {
kayekss 0:708868399033 154 return;
kayekss 0:708868399033 155 }
kayekss 0:708868399033 156
kayekss 0:708868399033 157 while (!dreq);
kayekss 0:708868399033 158 cs = 0;
kayekss 0:708868399033 159 spi.write(0x02); // Send a "Write SCI" instruction (02h),
kayekss 0:708868399033 160 spi.write(addr); // target address,
kayekss 0:708868399033 161 spi.write(word >> 8); // high byte,
kayekss 0:708868399033 162 spi.write(word & 0xff); // then low byte
kayekss 0:708868399033 163 while (!dreq);
kayekss 0:708868399033 164 cs = 1;
kayekss 0:708868399033 165 }
kayekss 0:708868399033 166
kayekss 3:696c8e6744b2 167 /** Read an SCI (Serial Control Interface) register entry.
kayekss 3:696c8e6744b2 168 * @return Register value or 0000h when invalid address was specified.
kayekss 3:696c8e6744b2 169 */
kayekss 0:708868399033 170 uint16_t VS1053::readReg(uint8_t addr) {
kayekss 0:708868399033 171 uint16_t word;
kayekss 0:708868399033 172
kayekss 3:696c8e6744b2 173 // If addr is out-of-range, return 0000h
kayekss 0:708868399033 174 if (addr > 0x0f) {
kayekss 3:696c8e6744b2 175 return 0x0000;
kayekss 0:708868399033 176 }
kayekss 0:708868399033 177
kayekss 0:708868399033 178 while (!dreq);
kayekss 0:708868399033 179 cs = 0;
kayekss 0:708868399033 180 spi.write(0x03); // Send a "Read SCI" instruction (03h)
kayekss 0:708868399033 181 spi.write(addr); // and target address
kayekss 0:708868399033 182 word = spi.write(0xff) << 8; // Receive high byte with dummy data FFh
kayekss 0:708868399033 183 word |= spi.write(0xff); // Receive low byte
kayekss 0:708868399033 184 while (!dreq);
kayekss 0:708868399033 185 cs = 1;
kayekss 0:708868399033 186 return word;
kayekss 0:708868399033 187 }