/*************************************************** This is a library for the Adafruit VS1053 Codec Breakout Designed specifically to work with the Adafruit VS1053 Codec Breakout ----> https://www.adafruit.com/products/1381 Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. BSD license, all text above must be included in any redistribution ****************************************************/ #include #include static Adafruit_VS1053_FilePlayer *myself; #if defined(__AVR__) SIGNAL(TIMER0_COMPA_vect) { myself->feedBuffer(); } #endif static void feeder(void) { myself->feedBuffer(); } #define VS1053_CONTROL_SPI_SETTING SPISettings(250000, MSBFIRST, SPI_MODE0) #define VS1053_DATA_SPI_SETTING SPISettings(8000000, MSBFIRST, SPI_MODE0) static const uint8_t dreqinttable[] = { #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) || defined(__AVR_ATmega8__) 2, 0, 3, 1, #elif defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) 2, 0, 3, 1, 21, 2, 20, 3, 19, 4, 18, 5, #elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY) 5, 0, 6, 1, 7, 2, 8, 3, #elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY) 0, 0, 1, 1, 2, 2, 3, 3, 36, 4, 37, 5, 18, 6, 19, 7, #elif defined(__arm__) && defined(CORE_TEENSY) 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, #elif defined(__AVR_ATmega32U4__) 3, 0, 2, 1, 0, 2, 1, 3, 7, 4, #endif }; boolean Adafruit_VS1053_FilePlayer::useInterrupt(uint8_t type) { myself = this; // oy vey if (type == VS1053_FILEPLAYER_TIMER0_INT) { #if defined(__AVR__) OCR0A = 0xAF; TIMSK0 |= _BV(OCIE0A); return true; #elif defined(__arm__) && defined(CORE_TEENSY) IntervalTimer *t = new IntervalTimer(); return (t && t->begin(feeder, 1024)) ? true : false; #else return false; #endif } if (type == VS1053_FILEPLAYER_PIN_INT) { for (uint8_t i=0; i= 0) { uint16_t offsets[] = {0x8000UL, 0x0, 0x4000UL}; uint16_t addr, len; //Serial.print("type: "); Serial.println(type, HEX); if (type >= 4) { plugin.close(); return 0xFFFF; } len = plugin.read(); len <<= 8; len |= plugin.read() & ~1; addr = plugin.read(); addr <<= 8; addr |= plugin.read(); //Serial.print("len: "); Serial.print(len); //Serial.print(" addr: $"); Serial.println(addr, HEX); if (type == 3) { // execute rec! plugin.close(); return addr; } // set address sciWrite(VS1053_REG_WRAMADDR, addr + offsets[type]); // write data do { uint16_t data; data = plugin.read(); data <<= 8; data |= plugin.read(); sciWrite(VS1053_REG_WRAM, data); } while ((len -=2)); } plugin.close(); return 0xFFFF; } boolean Adafruit_VS1053::readyForData(void) { return digitalRead(_dreq); } void Adafruit_VS1053::playData(uint8_t *buffer, uint8_t buffsiz) { #ifdef SPI_HAS_TRANSACTION if (useHardwareSPI) SPI.beginTransaction(VS1053_DATA_SPI_SETTING); #endif digitalWrite(_dcs, LOW); for (uint8_t i=0; i= 0) { digitalWrite(_reset, LOW); delay(100); digitalWrite(_reset, HIGH); } digitalWrite(_cs, HIGH); digitalWrite(_dcs, HIGH); delay(100); softReset(); delay(100); sciWrite(VS1053_REG_CLOCKF, 0x6000); setVolume(40, 40); } uint8_t Adafruit_VS1053::begin(void) { if (_reset >= 0) { pinMode(_reset, OUTPUT); digitalWrite(_reset, LOW); } pinMode(_cs, OUTPUT); digitalWrite(_cs, HIGH); pinMode(_dcs, OUTPUT); digitalWrite(_dcs, HIGH); pinMode(_dreq, INPUT); if (! useHardwareSPI) { pinMode(_mosi, OUTPUT); pinMode(_clk, OUTPUT); pinMode(_miso, INPUT); } else { SPI.begin(); SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV128); } reset(); return (sciRead(VS1053_REG_STATUS) >> 4) & 0x0F; } void Adafruit_VS1053::dumpRegs(void) { Serial.print("Mode = 0x"); Serial.println(sciRead(VS1053_REG_MODE), HEX); Serial.print("Stat = 0x"); Serial.println(sciRead(VS1053_REG_STATUS), HEX); Serial.print("ClkF = 0x"); Serial.println(sciRead(VS1053_REG_CLOCKF), HEX); Serial.print("Vol. = 0x"); Serial.println(sciRead(VS1053_REG_VOLUME), HEX); } uint16_t Adafruit_VS1053::recordedWordsWaiting(void) { return sciRead(VS1053_REG_HDAT1); } uint16_t Adafruit_VS1053::recordedReadWord(void) { return sciRead(VS1053_REG_HDAT0); } boolean Adafruit_VS1053::prepareRecordOgg(char *plugname) { sciWrite(VS1053_REG_CLOCKF, 0xC000); // set max clock delay(1); while (! readyForData() ); sciWrite(VS1053_REG_BASS, 0); // clear Bass softReset(); delay(1); while (! readyForData() ); sciWrite(VS1053_SCI_AIADDR, 0); // disable all interrupts except SCI sciWrite(VS1053_REG_WRAMADDR, VS1053_INT_ENABLE); sciWrite(VS1053_REG_WRAM, 0x02); int pluginStartAddr = loadPlugin(plugname); if (pluginStartAddr == 0xFFFF) return false; Serial.print("Plugin at $"); Serial.println(pluginStartAddr, HEX); if (pluginStartAddr != 0x34) return false; return true; } void Adafruit_VS1053::stopRecordOgg(void) { sciWrite(VS1053_SCI_AICTRL3, 1); } void Adafruit_VS1053::startRecordOgg(boolean mic) { /* Set VS1053 mode bits as instructed in the VS1053b Ogg Vorbis Encoder manual. Note: for microphone input, leave SMF_LINE1 unset! */ if (mic) { sciWrite(VS1053_REG_MODE, VS1053_MODE_SM_ADPCM | VS1053_MODE_SM_SDINEW); } else { sciWrite(VS1053_REG_MODE, VS1053_MODE_SM_LINE1 | VS1053_MODE_SM_ADPCM | VS1053_MODE_SM_SDINEW); } sciWrite(VS1053_SCI_AICTRL0, 1024); /* Rec level: 1024 = 1. If 0, use AGC */ sciWrite(VS1053_SCI_AICTRL1, 1024); /* Maximum AGC level: 1024 = 1. Only used if SCI_AICTRL1 is set to 0. */ sciWrite(VS1053_SCI_AICTRL2, 0); /* Miscellaneous bits that also must be set before recording. */ sciWrite(VS1053_SCI_AICTRL3, 0); sciWrite(VS1053_SCI_AIADDR, 0x34); delay(1); while (! readyForData() ); } void Adafruit_VS1053::GPIO_pinMode(uint8_t i, uint8_t dir) { if (i > 7) return; sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_DDR); uint16_t ddr = sciRead(VS1053_REG_WRAM); if (dir == INPUT) ddr &= ~_BV(i); if (dir == OUTPUT) ddr |= _BV(i); sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_DDR); sciWrite(VS1053_REG_WRAM, ddr); } void Adafruit_VS1053::GPIO_digitalWrite(uint8_t val) { sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_ODATA); sciWrite(VS1053_REG_WRAM, val); } void Adafruit_VS1053::GPIO_digitalWrite(uint8_t i, uint8_t val) { if (i > 7) return; sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_ODATA); uint16_t pins = sciRead(VS1053_REG_WRAM); if (val == LOW) pins &= ~_BV(i); if (val == HIGH) pins |= _BV(i); sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_ODATA); sciWrite(VS1053_REG_WRAM, pins); } uint16_t Adafruit_VS1053::GPIO_digitalRead(void) { sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_IDATA); return sciRead(VS1053_REG_WRAM) & 0xFF; } boolean Adafruit_VS1053::GPIO_digitalRead(uint8_t i) { if (i > 7) return 0; sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_IDATA); uint16_t val = sciRead(VS1053_REG_WRAM); if (val & _BV(i)) return true; return false; } uint16_t Adafruit_VS1053::sciRead(uint8_t addr) { uint16_t data; #ifdef SPI_HAS_TRANSACTION if (useHardwareSPI) SPI.beginTransaction(VS1053_CONTROL_SPI_SETTING); #endif digitalWrite(_cs, LOW); spiwrite(VS1053_SCI_READ); spiwrite(addr); delayMicroseconds(10); data = spiread(); data <<= 8; data |= spiread(); digitalWrite(_cs, HIGH); #ifdef SPI_HAS_TRANSACTION if (useHardwareSPI) SPI.endTransaction(); #endif return data; } void Adafruit_VS1053::sciWrite(uint8_t addr, uint16_t data) { #ifdef SPI_HAS_TRANSACTION if (useHardwareSPI) SPI.beginTransaction(VS1053_CONTROL_SPI_SETTING); #endif digitalWrite(_cs, LOW); spiwrite(VS1053_SCI_WRITE); spiwrite(addr); spiwrite(data >> 8); spiwrite(data & 0xFF); digitalWrite(_cs, HIGH); #ifdef SPI_HAS_TRANSACTION if (useHardwareSPI) SPI.endTransaction(); #endif } uint8_t Adafruit_VS1053::spiread(void) { int8_t i, x; x = 0; // MSB first, clock low when inactive (CPOL 0), data valid on leading edge (CPHA 0) // Make sure clock starts low if (useHardwareSPI) { x = SPI.transfer(0x00); } else { for (i=7; i>=0; i--) { if ((*misoportreg) & misopin) x |= (1<=0; i--) { *clkportreg &= ~clkpin; if (c & (1<