Dependents: Adafruit_Si4173_Demo Radio_Transmitter_Working
Diff: Adafruit_Si4713.cpp
- Revision:
- 0:6643c5542090
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adafruit_Si4713.cpp Tue Jan 24 06:55:43 2017 +0000 @@ -0,0 +1,404 @@ +/*************************************************** + This is a library for the Si4713 FM Radio Transmitter with RDS + + Designed specifically to work with the Si4713 breakout in the + adafruit shop + ----> https://www.adafruit.com/products/1958 + + These transmitters use I2C to communicate, plus reset pin. + 3 pins are required to interface + 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 + ****************************************************/ +/*************************************************** + Modified to work with ARM mbed by John M. Larkin + January 2017 +******************************************************/ + +#include "Adafruit_Si4713.h" + +float dt = 0.1; // An extra delay between I2C commands is essential + +int min(int a, int b) { + return a > b ? a:b; +} + +Adafruit_Si4713::Adafruit_Si4713(I2C i2c, PinName resetpin, uint8_t addr):_i2c(i2c),_rst(resetpin) { + _i2caddr = addr; +} + + +bool Adafruit_Si4713::begin() { + reset(); + powerUp(); + + // check for Si4713 + if (getRev() != 13) return false; + + return true; +} + +void Adafruit_Si4713::reset() { + _rst = 1; + wait(dt); + _rst = 0; + wait(dt); + _rst = 1; +} + + +////////////////////////////////////////////////////// + +void Adafruit_Si4713::setProperty(uint16_t property, uint16_t value) { + _i2ccommand[0] = SI4710_CMD_SET_PROPERTY; + _i2ccommand[1] = 0; + _i2ccommand[2] = property >> 8; + _i2ccommand[3] = property & 0xFF; + _i2ccommand[4] = value >> 8; + _i2ccommand[5] = value & 0xFF; + sendCommand(6); + +#ifdef SI4713_CMD_DEBUG + printf("Set Prop 0x%x = %d\r\n", property,value); +#endif +} + +void Adafruit_Si4713::sendCommand(uint8_t len) { +#ifdef SI4713_CMD_DEBUG + printf("\r\n*** Command:"); + for (uint8_t i = 0; i<len; i++) + printf(" 0x%x",_i2ccommand[i]); + printf("\r\n"); +#endif + _i2c.write(_i2caddr, _i2ccommand, len,true); + wait(dt); + + // Wait for status CTS bit + char status = 0; + while (! (status & SI4710_STATUS_CTS)) { + status = _i2c.read(0); +#ifdef SI4713_CMD_DEBUG + printf("status: %x\r\n", status); +#endif + } + _i2c.stop(); + wait(dt); +} + +void Adafruit_Si4713::tuneFM(uint16_t freqKHz) { + _i2ccommand[0] = SI4710_CMD_TX_TUNE_FREQ; + _i2ccommand[1] = 0; + _i2ccommand[2] = freqKHz >> 8; + _i2ccommand[3] = freqKHz; + sendCommand(4); + while ((getStatus() & 0x81) != 0x81) { + wait(0.01); + } +} + +void Adafruit_Si4713::setTXpower(uint8_t pwr, uint8_t antcap) { + _i2ccommand[0] = SI4710_CMD_TX_TUNE_POWER; + _i2ccommand[1] = 0; + _i2ccommand[2] = 0; + _i2ccommand[3] = pwr; + _i2ccommand[4] = antcap; + sendCommand(5); +} + +void Adafruit_Si4713::readASQ(void) { + _i2ccommand[0] = SI4710_CMD_TX_ASQ_STATUS; + _i2ccommand[1] = 0x1; + sendCommand(2); + + char rawBytes[5]; + _i2c.read(_i2caddr, rawBytes, 5); + currASQ = rawBytes[1]; + currInLevel = rawBytes[4]; +} + + +void Adafruit_Si4713::readTuneStatus(void) { + _i2ccommand[0] = SI4710_CMD_TX_TUNE_STATUS; + _i2ccommand[1] = 0x1; // INTACK + sendCommand(2); + + + char rawBytes[8]; + _i2c.read(_i2caddr, rawBytes, 8); + currFreq = ((uint16_t)rawBytes[2] << 8) | (uint16_t)rawBytes[3]; + currdBuV = rawBytes[5]; + currAntCap = rawBytes[6]; + currNoiseLevel = rawBytes[7]; +} + + +void Adafruit_Si4713::readTuneMeasure(uint16_t freq) { + // check freq is multiple of 50khz + if (freq % 5 != 0) { + freq -= (freq % 5); + } + _i2ccommand[0] = SI4710_CMD_TX_TUNE_MEASURE; + _i2ccommand[1] = 0; + _i2ccommand[2] = freq >> 8; + _i2ccommand[3] = freq; + _i2ccommand[4] = 0; + + sendCommand(5); + while (getStatus() != 0x81) wait(0.01); +} + +void Adafruit_Si4713::beginRDS(uint16_t programID) { + // 66.25KHz (default is 68.25) + setProperty(SI4713_PROP_TX_AUDIO_DEVIATION, 6625); + + // 2KHz (default) + setProperty(SI4713_PROP_TX_RDS_DEVIATION, 200); + + // RDS IRQ + setProperty(SI4713_PROP_TX_RDS_INTERRUPT_SOURCE, 0x0001); + // program identifier + setProperty(SI4713_PROP_TX_RDS_PI, programID); + // 50% mix (default) + setProperty(SI4713_PROP_TX_RDS_PS_MIX, 0x03); + // RDSD0 & RDSMS (default) + setProperty(SI4713_PROP_TX_RDS_PS_MISC, 0x1808); + // 3 repeats (default) + setProperty(SI4713_PROP_TX_RDS_PS_REPEAT_COUNT, 3); + + setProperty(SI4713_PROP_TX_RDS_MESSAGE_COUNT, 1); + setProperty(SI4713_PROP_TX_RDS_PS_AF, 0xE0E0); // no AF + setProperty(SI4713_PROP_TX_RDS_FIFO_SIZE, 0); + + setProperty(SI4713_PROP_TX_COMPONENT_ENABLE, 0x0007); +} + +void Adafruit_Si4713::setRDSstation(char *s) { + uint8_t i, len = strlen(s); + uint8_t slots = (len+3) / 4; + + for (uint8_t i=0; i<slots; i++) { + memset(_i2ccommand, ' ', 6); // clear it with ' ' + memcpy(_i2ccommand+2, s, min(4, strlen(s))); + s+=4; + _i2ccommand[6] = 0; + //Serial.print("Set slot #"); Serial.print(i); + //char *slot = (char *)( _i2ccommand+2); + //Serial.print(" to '"); Serial.print(slot); Serial.println("'"); + _i2ccommand[0] = SI4710_CMD_TX_RDS_PS; + _i2ccommand[1] = i; // slot # + sendCommand(6); + } +} + +void Adafruit_Si4713::setRDSbuffer(char *s) { + uint8_t i, len = strlen(s); + uint8_t slots = (len+3) / 4; + char slot[5]; + + for (uint8_t i=0; i<slots; i++) { + memset(_i2ccommand, ' ', 8); // clear it with ' ' + memcpy(_i2ccommand+4, s, min(4, strlen(s))); + s+=4; + _i2ccommand[8] = 0; + //Serial.print("Set buff #"); Serial.print(i); + //char *slot = (char *)( _i2ccommand+4); + //Serial.print(" to '"); Serial.print(slot); Serial.println("'"); + _i2ccommand[0] = SI4710_CMD_TX_RDS_BUFF; + if (i == 0) + _i2ccommand[1] = 0x06; + else + _i2ccommand[1] = 0x04; + + _i2ccommand[2] = 0x20; + _i2ccommand[3] = i; + sendCommand(8); + } + + + /* + // set time + _i2ccommand[0] = SI4710_CMD_TX_RDS_BUFF; + _i2ccommand[1] = 0x84; + _i2ccommand[2] = 0x40; // RTC + _i2ccommand[3] = 01; + _i2ccommand[4] = 0xA7; + _i2ccommand[5] = 0x0B; + _i2ccommand[6] = 0x2D; + _i2ccommand[7] = 0x6C; + sendCommand(8); + + Wire.requestFrom((uint8_t)_i2caddr, (uint8_t)6); + Wire.read(); // status + Serial.print("FIFO overflow: 0x"); Serial.println(Wire.read(), HEX); + Serial.print("Circ avail: "); Serial.println(Wire.read()); + Serial.print("Circ used: "); Serial.println(Wire.read()); + Serial.print("FIFO avail: "); Serial.println(Wire.read()); + Serial.print("FIFO used: "); Serial.println(Wire.read()); + */ + + // enable! + //Serial.println("Enable RDS"); + setProperty(SI4713_PROP_TX_COMPONENT_ENABLE, 0x0007); // stereo, pilot+rds + /* + // wait till ready + while (getStatus() != 0x80) { + Serial.println(getStatus(), HEX); + delay(100); + } + delay(500); + _i2ccommand[0] = SI4710_CMD_TX_RDS_BUFF; + _i2ccommand[1] = 0x01; // clear RDSINT + _i2ccommand[2] = 0x0; + _i2ccommand[3] = 0x0; + _i2ccommand[4] = 0x0; + _i2ccommand[5] = 0x0; + _i2ccommand[6] = 0x0; + _i2ccommand[7] = 0x0; + sendCommand(8); + // get reply! + Wire.requestFrom((uint8_t)_i2caddr, (uint8_t)6); + for (uint8_t x=0; x<7; x++) { + Wire.read(); + } + */ + /* or you can read the status + Wire.read(); // status + Serial.print("FIFO overflow: 0x"); Serial.println(Wire.read(), HEX); + Serial.print("Circ avail: "); Serial.println(Wire.read()); + Serial.print("Circ used: "); Serial.println(Wire.read()); + Serial.print("FIFO avail: "); Serial.println(Wire.read()); + Serial.print("FIFO used: "); Serial.println(Wire.read()); + */ +} + +uint8_t Adafruit_Si4713::getStatus(void) { + _i2c.start(); + _i2c.write(_i2caddr); + _i2c.write(SI4710_CMD_GET_INT_STATUS); + _i2c.stop(); + + uint8_t status; + _i2c.start(); + _i2c.write(_i2caddr|0x01); + status = _i2c.read(0); + _i2c.stop(); + return status; +} + +void Adafruit_Si4713::powerUp(void) { + _i2ccommand[0] = SI4710_CMD_POWER_UP; + _i2ccommand[1] = 0x12; + // CTS interrupt disabled + // GPO2 output disabled + // Boot normally + // xtal oscillator ENabled + // FM transmit + _i2ccommand[2] = 0x50; // analog input mode + sendCommand(3); + + // configuration! see page 254 + setProperty(SI4713_PROP_REFCLK_FREQ, 32768); // crystal is 32.768 + setProperty(SI4713_PROP_TX_PREEMPHASIS, 0); // 74uS pre-emph (USA std) + setProperty(SI4713_PROP_TX_ACOMP_GAIN, 10); // max gain? + setProperty(SI4713_PROP_TX_ACOMP_ENABLE, 0x02); // turn on limiter, but no dynamic ranging + //setProperty(SI4713_PROP_TX_ACOMP_ENABLE, 0x0); // turn on limiter and AGC +} + +uint8_t Adafruit_Si4713::getRev(void) { + _i2ccommand[0] = SI4710_CMD_GET_REV; + _i2ccommand[1] = 0; + + sendCommand(2); + + char rawBytes[9]; + _i2c.read(_i2caddr, rawBytes, 9); + uint8_t pn = rawBytes[1]; + uint16_t fw = ((uint16_t)rawBytes[2] << 8) | (uint16_t)rawBytes[3]; + uint16_t patch = ((uint16_t)rawBytes[4] << 8) | (uint16_t)rawBytes[5]; + uint16_t cmp = ((uint16_t)rawBytes[6] << 8) | (uint16_t)rawBytes[7]; + uint8_t chiprev = rawBytes[8]; + + printf("Part #Si47%d - %x\r\n", pn, fw); + printf("Patch 0x%x\r\n", patch); + printf("Chip rev %d\r\n", chiprev); + return pn; +} + +void Adafruit_Si4713::setGPIOctrl(uint8_t x) { + // Serial.println("GPIO direction"); + _i2ccommand[0] = SI4710_CMD_GPO_CTL; + _i2ccommand[1] = x; + + sendCommand(2); +} + +void Adafruit_Si4713::setGPIO(uint8_t x) { + //Serial.println("GPIO set"); + _i2ccommand[0] = SI4710_CMD_GPO_SET; + _i2ccommand[1] = x; + + sendCommand(2); +} + + +/// + +/* +void Adafruit_Si4713::rdstest() { + _i2ccommand[0] = SI4710_CMD_TX_RDS_BUFF; + _i2ccommand[1] = 0x02; + _i2ccommand[2] = 0; + _i2ccommand[3] = 0; + _i2ccommand[4] = 0; + _i2ccommand[5] = 0; + _i2ccommand[6] = 0; + _i2ccommand[7] = 0; + sendCommand(8); + Wire.requestFrom((uint8_t)_i2caddr, (uint8_t)6); + Wire.read(); // status + Serial.print("FIFO overflow: 0x"); Serial.println(Wire.read(), HEX); + Serial.print("Circ avail: "); Serial.println(Wire.read()); + Serial.print("Circ used: "); Serial.println(Wire.read()); + Serial.print("FIFO avail: "); Serial.println(Wire.read()); + Serial.print("FIFO used: "); Serial.println(Wire.read()); + + _i2ccommand[0] = SI4710_CMD_TX_RDS_BUFF; + _i2ccommand[1] = 0x04; + _i2ccommand[2] = 0x20; + _i2ccommand[3] = 0x00; + _i2ccommand[4] = 0x54; + _i2ccommand[5] = 0x65; + _i2ccommand[6] = 0x73; + _i2ccommand[7] = 0x74; + sendCommand(8); + Wire.requestFrom((uint8_t)_i2caddr, (uint8_t)6); + Wire.read(); // status + Serial.print("FIFO overflow: 0x"); Serial.println(Wire.read(), HEX); + Serial.print("Circ avail: "); Serial.println(Wire.read()); + Serial.print("Circ used: "); Serial.println(Wire.read()); + Serial.print("FIFO avail: "); Serial.println(Wire.read()); + Serial.print("FIFO used: "); Serial.println(Wire.read()); + + + _i2ccommand[0] = SI4710_CMD_TX_RDS_BUFF; + _i2ccommand[1] = 0x04; + _i2ccommand[2] = 0x20; + _i2ccommand[3] = 0x01; + _i2ccommand[4] = 0xD0; + _i2ccommand[5] = 0x00; + _i2ccommand[6] = 0x00; + _i2ccommand[7] = 0x00; + sendCommand(8); + Wire.requestFrom((uint8_t)_i2caddr, (uint8_t)6); + Wire.read(); // status + Serial.print("FIFO overflow: 0x"); Serial.println(Wire.read(), HEX); + Serial.print("Circ avail: "); Serial.println(Wire.read()); + Serial.print("Circ used: "); Serial.println(Wire.read()); + Serial.print("FIFO avail: "); Serial.println(Wire.read()); + Serial.print("FIFO used: "); Serial.println(Wire.read()); +} +*/