Dependents: Adafruit_Si4173_Demo Radio_Transmitter_Working
Revision 0:6643c5542090, committed 2017-01-24
- Comitter:
- JLarkin
- Date:
- Tue Jan 24 06:55:43 2017 +0000
- Commit message:
- Translated Adafruit library from Arduino to mbed. Need extra delays between I2C commands because of mbed's faster speed.
Changed in this revision
Adafruit_Si4713.cpp | Show annotated file Show diff for this revision Revisions of this file |
Adafruit_Si4713.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 6643c5542090 Adafruit_Si4713.cpp --- /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()); +} +*/
diff -r 000000000000 -r 6643c5542090 Adafruit_Si4713.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adafruit_Si4713.h Tue Jan 24 06:55:43 2017 +0000 @@ -0,0 +1,145 @@ +/*************************************************** + 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 +******************************************************/ + +//!Library for the Adafruit Si4713. +/*! +The Si4713 is an FM radio transmitter with RDS +*/ + +#include "mbed.h" + +//#define SI4713_CMD_DEBUG + +#define SI4710_ADDR0 0x11<<1 // if SEN is low +#define SI4710_ADDR1 0x63<<1 // if SEN is high, default! +#define SI4710_STATUS_CTS 0x80 + +/* COMMANDS */ +#define SI4710_CMD_POWER_UP 0x01 +#define SI4710_CMD_GET_REV 0x10 +#define SI4710_CMD_POWER_DOWN 0x11 +#define SI4710_CMD_SET_PROPERTY 0x12 +#define SI4710_CMD_GET_PROPERTY 0x13 +#define SI4710_CMD_GET_INT_STATUS 0x14 +#define SI4710_CMD_PATCH_ARGS 0x15 +#define SI4710_CMD_PATCH_DATA 0x16 +#define SI4710_CMD_TX_TUNE_FREQ 0x30 +#define SI4710_CMD_TX_TUNE_POWER 0x31 +#define SI4710_CMD_TX_TUNE_MEASURE 0x32 +#define SI4710_CMD_TX_TUNE_STATUS 0x33 +#define SI4710_CMD_TX_ASQ_STATUS 0x34 +#define SI4710_CMD_TX_RDS_BUFF 0x35 +#define SI4710_CMD_TX_RDS_PS 0x36 +#define SI4710_CMD_TX_AGC_OVERRIDE 0x48 +#define SI4710_CMD_GPO_CTL 0x80 +#define SI4710_CMD_GPO_SET 0x81 + +/* Parameters */ + +#define SI4713_PROP_GPO_IEN 0x0001 +#define SI4713_PROP_DIGITAL_INPUT_FORMAT 0x0101 +#define SI4713_PROP_DIGITAL_INPUT_SAMPLE_RATE 0x0103 +#define SI4713_PROP_REFCLK_FREQ 0x0201 +#define SI4713_PROP_REFCLK_PRESCALE 0x0202 +#define SI4713_PROP_TX_COMPONENT_ENABLE 0x2100 +#define SI4713_PROP_TX_AUDIO_DEVIATION 0x2101 +#define SI4713_PROP_TX_PILOT_DEVIATION 0x2102 +#define SI4713_PROP_TX_RDS_DEVIATION 0x2103 +#define SI4713_PROP_TX_LINE_LEVEL_INPUT_LEVEL 0x2104 +#define SI4713_PROP_TX_LINE_INPUT_MUTE 0x2105 +#define SI4713_PROP_TX_PREEMPHASIS 0x2106 +#define SI4713_PROP_TX_PILOT_FREQUENCY 0x2107 +#define SI4713_PROP_TX_ACOMP_ENABLE 0x2200 +#define SI4713_PROP_TX_ACOMP_THRESHOLD 0x2201 +#define SI4713_PROP_TX_ATTACK_TIME 0x2202 +#define SI4713_PROP_TX_RELEASE_TIME 0x2203 +#define SI4713_PROP_TX_ACOMP_GAIN 0x2204 +#define SI4713_PROP_TX_LIMITER_RELEASE_TIME 0x2205 +#define SI4713_PROP_TX_ASQ_INTERRUPT_SOURCE 0x2300 +#define SI4713_PROP_TX_ASQ_LEVEL_LOW 0x2301 +#define SI4713_PROP_TX_ASQ_DURATION_LOW 0x2302 +#define SI4713_PROP_TX_AQS_LEVEL_HIGH 0x2303 +#define SI4713_PROP_TX_AQS_DURATION_HIGH 0x2304 + +#define SI4713_PROP_TX_RDS_INTERRUPT_SOURCE 0x2C00 +#define SI4713_PROP_TX_RDS_PI 0x2C01 +#define SI4713_PROP_TX_RDS_PS_MIX 0x2C02 +#define SI4713_PROP_TX_RDS_PS_MISC 0x2C03 +#define SI4713_PROP_TX_RDS_PS_REPEAT_COUNT 0x2C04 +#define SI4713_PROP_TX_RDS_MESSAGE_COUNT 0x2C05 +#define SI4713_PROP_TX_RDS_PS_AF 0x2C06 +#define SI4713_PROP_TX_RDS_FIFO_SIZE 0x2C07 + + +/* REGISTERS */ + + +int min(int a, int b); + +class Adafruit_Si4713 { + public: + //!Creates an instance of the class. + /*! + Connect module at I2C address addr using I2C port pins sda and scl. A digital output is used to reset the device. + TMP102 + \param i2c An I2C object created elsewhere + \param rstpin A digital out pin used to toggle the device reset. + \param addr The I2C address the device. + */ + Adafruit_Si4713(I2C i2c, PinName rstpin, uint8_t addr = SI4710_ADDR1); + bool begin(); + void reset(); + + void powerUp(void); + void configure(void); + uint8_t getRev(void); + + void tuneFM(uint16_t freqKHz); + uint8_t getStatus(void); + void readTuneStatus(void); + void readTuneMeasure(uint16_t freq); + void setTXpower(uint8_t pwr, uint8_t antcap = 0); + void readASQ(void); + void setProperty(uint16_t p, uint16_t v); + + // RDS stuff + void beginRDS(uint16_t programID = 0xADAF); + void setRDSstation(char *s); + void setRDSbuffer(char *s); + + uint16_t currFreq; + uint8_t currdBuV, currAntCap, currNoiseLevel, currASQ; + int8_t currInLevel; + + + void setGPIO(uint8_t x); + void setGPIOctrl(uint8_t x); + + private: + + void sendCommand(uint8_t len); + + I2C _i2c; + DigitalOut _rst; + char _i2ccommand[10]; // holds the command buffer + char _i2caddr; +}; +