Dependents:   Adafruit_Si4173_Demo Radio_Transmitter_Working

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());
+}
+*/