A mbed Port of 'Sparkfun Si4703 Arduino Library'.

Dependents:   projekt_Si4703

Fork of Si4703 by Moran Z.

Revision:
0:1f830fa5c9b8
Child:
1:3d2b66e5d09e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SparkFun-Si4703.cpp	Fri Aug 07 04:26:47 2015 +0000
@@ -0,0 +1,300 @@
+#include <mbed.h>
+#include "SparkFun-Si4703.hpp"
+
+Si4703_Breakout::Si4703_Breakout(PinName sdioPin, PinName sclkPin, PinName resetPin, Serial *pc)
+{
+  _resetPin = resetPin;
+  _sdioPin = sdioPin;
+  _sclkPin = sclkPin;
+
+ this->pc = pc;
+}
+
+void Si4703_Breakout::powerOn()
+{
+    si4703_init();
+}
+
+void Si4703_Breakout::powerOff()
+{
+// a Minimal Power-Down Sequence - According To SI AN230 (rev. 0.9), p.13 - Table 4
+
+readRegisters();
+
+si4703_registers[POWERCFG] &= ~(1<<DMUTE); // 'Enable Mute'
+si4703_registers[POWERCFG] |= (1<<ENABLE); // 'Enable IC'
+si4703_registers[POWERCFG] |= (1<<DISABLE); // & 'Disable IC'
+											// To Init. Power-Down Sequence
+
+updateRegisters();
+// Notice : This Does NOT Perform a Reset of The IC.
+}
+
+void Si4703_Breakout::setChannel(int channel)
+{
+  uint8_t ack;
+  //Freq(MHz) = 0.1 (in Europe) * Channel + 87.5MHz
+  //97.3 = 0.1 * Chan + 87.5
+  //9.8 / 0.1 = 98
+  int newChannel = channel * 10; //973 * 10 = 9730
+  newChannel -= 8750; //9730 - 8750 = 980
+  newChannel /= 10; //980 / 10 = 98
+
+  //These steps come from AN230 page 20 rev 0.5
+  readRegisters();
+  si4703_registers[CHANNEL] &= 0xFE00; //Clear out the channel bits
+  si4703_registers[CHANNEL] |= newChannel; //Mask in the new channel
+  si4703_registers[CHANNEL] |= (1<<TUNE); //Set the TUNE bit to start
+  updateRegisters();
+
+  wait_ms(60); //Wait 60ms - you can use or skip this delay
+
+  //Poll to see if STC is set
+  while(1) {
+    ack = readRegisters();
+    wait_ms(1); // Just In Case...
+    if (( (si4703_registers[STATUSRSSI] & (1<<STC)) != 0) || (ack != SUCCESS)) break; //Tuning complete! (or FAILED)
+  }
+
+  readRegisters();
+  si4703_registers[CHANNEL] &= ~(1<<TUNE); //Clear the tune after a tune has completed
+  updateRegisters();
+
+  //Wait for the si4703 to clear the STC as well
+  while(1) {
+    ack = readRegisters();
+    wait_ms(1); // Just In Case...
+    if (( (si4703_registers[STATUSRSSI] & (1<<STC)) == 0) || (ack != SUCCESS)) break; //Tuning complete! (or FAILED)
+  }
+}
+
+int Si4703_Breakout::seekUp()
+{
+	return seek(SEEK_UP);
+}
+
+int Si4703_Breakout::seekDown()
+{
+	return seek(SEEK_DOWN);
+}
+
+void Si4703_Breakout::setVolume(int volume)
+{
+  readRegisters(); //Read the current register set
+  if(volume < 0) volume = 0;
+  if (volume > 15) volume = 15;
+  si4703_registers[SYSCONFIG2] &= 0xFFF0; //Clear volume bits
+  si4703_registers[SYSCONFIG2] |= volume; //Set new volume
+  updateRegisters(); //Update
+}
+
+uint8_t Si4703_Breakout::getVolume()
+{
+  readRegisters(); //Read the current register set
+
+  return (si4703_registers[SYSCONFIG2] & 0x000F);
+}
+
+/*
+void Si4703_Breakout::readRDS(char* buffer, long timeout)
+{ 
+	long endTime = millis() + timeout;
+  boolean completed[] = {false, false, false, false};
+  int completedCount = 0;
+  while(completedCount < 4 && millis() < endTime) {
+	readRegisters();
+	if(si4703_registers[STATUSRSSI] & (1<<RDSR)){
+		// ls 2 bits of B determine the 4 letter pairs
+		// once we have a full set return
+		// if you get nothing after 20 readings return with empty string
+	  uint16_t b = si4703_registers[RDSB];
+	  int index = b & 0x03;
+	  if (! completed[index] && b < 500)
+	  {
+		completed[index] = true;
+		completedCount ++;
+	  	char Dh = (si4703_registers[RDSD] & 0xFF00) >> 8;
+      	char Dl = (si4703_registers[RDSD] & 0x00FF);
+		buffer[index * 2] = Dh;
+		buffer[index * 2 +1] = Dl;
+		// Serial.print(si4703_registers[RDSD]); Serial.print(" ");
+		// Serial.print(index);Serial.print(" ");
+		// Serial.write(Dh);
+		// Serial.write(Dl);
+		// Serial.println();
+      }
+      delay(40); //Wait for the RDS bit to clear
+	}
+	else {
+	  delay(30); //From AN230, using the polling method 40ms should be sufficient amount of time between checks
+	}
+  }
+	if (millis() >= endTime) {
+		buffer[0] ='\0';
+		return;
+	}
+
+  buffer[8] = '\0';
+}
+*/
+
+
+
+//To get the Si4703 inito 2-wire mode, SEN needs to be high and SDIO needs to be low after a reset
+//The breakout board has SEN pulled high, but also has SDIO pulled high. Therefore, after a normal power up
+//The Si4703 will be in an unknown state. RST must be controlled
+void Si4703_Breakout::si4703_init() 
+{
+  _reset_ = new DigitalOut(_resetPin);
+  _sdio_ = new DigitalOut(_sdioPin);
+
+  _sdio_->write(0); //A low SDIO indicates a 2-wire interface
+  _reset_->write(0); //Put Si4703 into reset
+  wait_ms(1); //Some delays while we allow pins to settle
+  _reset_->write(1); //Bring Si4703 out of reset with SDIO set to low and SEN pulled high with on-board resistor
+  wait_ms(1); //Allow Si4703 to come out of reset
+
+  //Now that the unit is reset and I2C inteface mode, we need to begin I2C
+  i2c_ = new I2C(_sdioPin, _sclkPin);
+  i2c_->frequency(100000);
+  ///
+
+  readRegisters(); //Read the current register set
+  si4703_registers[0x07] = 0x8100; //Enable the oscillator, from AN230 page 9, rev 0.61 (works)
+  updateRegisters(); //Update
+
+  wait_ms(500); //Wait for clock to settle - from AN230 page 9
+
+  readRegisters(); //Read the current register set
+  si4703_registers[POWERCFG] = 0x4001; //Enable the IC
+  //  si4703_registers[POWERCFG] |= (1<<SMUTE) | (1<<DMUTE); //Disable Mute, disable softmute
+  si4703_registers[SYSCONFIG1] |= (1<<RDS); //Enable RDS
+
+  si4703_registers[SYSCONFIG1] |= (1<<DE); //50kHz Europe setup
+  si4703_registers[SYSCONFIG2] |= (1<<SPACE0); //100kHz channel spacing for Europe
+
+  si4703_registers[SYSCONFIG2] &= 0xFFF0; //Clear volume bits
+  si4703_registers[SYSCONFIG2] |= 0x0001; //Set volume to lowest
+  updateRegisters(); //Update
+
+  wait_ms(110); //Max powerup time, from datasheet page 13
+  
+}
+
+//Read the entire register control set from 0x00 to 0x0F
+uint8_t Si4703_Breakout::readRegisters(){
+
+  //Si4703 begins reading from register upper register of 0x0A and reads to 0x0F, then loops to 0x00.
+//  Wire.requestFrom(SI4703, 32); //We want to read the entire register set from 0x0A to 0x09 = 32 uint8_ts.
+    char data[32];
+    uint8_t ack = i2c_->read(SI4703, data, 32); //Read in these 32 uint8_ts
+
+  if (ack != 0) { //We have a problem! 
+    return(FAIL);
+  }
+
+//Remember, register 0x0A comes in first so we have to shuffle the array around a bit
+	for (int y=0; y<6; y++)
+		{
+			si4703_registers[0x0A+y] = 0;
+			si4703_registers[0x0A+y] = data[(y*2)+1];
+			si4703_registers[0x0A+y] |= (data[(y*2)] << 8);
+		}
+
+	for (int y=0; y<10; y++)
+		{
+			si4703_registers[y] = 0;
+			si4703_registers[y] = data[(12)+(y*2)+1];
+			si4703_registers[y] |= (data[(12)+(y*2)] << 8);
+		}
+//We're done!
+///
+  return(SUCCESS);
+}
+
+//Write the current 9 control registers (0x02 to 0x07) to the Si4703
+//It's a little weird, you don't write an I2C address
+//The Si4703 assumes you are writing to 0x02 first, then increments
+uint8_t Si4703_Breakout::updateRegisters() {
+
+  char data[12];
+
+  //First we send the 0x02 to 0x07 control registers
+  //In general, we should not write to registers 0x08 and 0x09
+  for(int regSpot = 0x02 ; regSpot < 0x08 ; regSpot++) {
+    data[(regSpot-2)*2] = si4703_registers[regSpot] >> 8;
+    data[((regSpot-2)*2)+1] = si4703_registers[regSpot] & 0x00FF;
+  }
+
+  uint8_t ack = i2c_->write(SI4703, data, 12);  // a write command automatically begins with register 0x02 so no need to send a write-to address
+
+  if(ack != 0) { //We have a problem! 
+    return(FAIL);
+  }
+
+  return(SUCCESS);
+}
+
+//Returns The Value of a Register
+uint16_t Si4703_Breakout::getRegister(uint8_t regNum)
+{
+  readRegisters();
+  return si4703_registers[regNum];
+// No Error Status Checking
+}
+
+//Seeks out the next available station
+//Returns the freq if it made it
+//Returns zero if failed
+int Si4703_Breakout::seek(bool seekDirection){
+  uint8_t ack;
+  readRegisters();
+  //Set seek mode wrap bit
+  si4703_registers[POWERCFG] |= (1<<SKMODE); //Allow wrap
+  //si4703_registers[POWERCFG] &= ~(1<<SKMODE); //Disallow wrap - if you disallow wrap, you may want to tune to 87.5 first
+  if(seekDirection == SEEK_DOWN) si4703_registers[POWERCFG] &= ~(1<<SEEKUP); //Seek down is the default upon reset
+  else si4703_registers[POWERCFG] |= 1<<SEEKUP; //Set the bit to seek up
+
+  si4703_registers[POWERCFG] |= (1<<SEEK); //Start seek
+  updateRegisters(); //Seeking will now start
+
+  //Poll to see if STC is set
+  while(1) {
+    ack = readRegisters();
+    wait_ms(1); // Just In Case...
+    if (((si4703_registers[STATUSRSSI] & (1<<STC)) != 0) || (ack != SUCCESS)) break; //Tuning complete! (or FAILED)
+  }
+
+  readRegisters();
+  int valueSFBL = si4703_registers[STATUSRSSI] & (1<<SFBL); //Store the value of SFBL
+  si4703_registers[POWERCFG] &= ~(1<<SEEK); //Clear the seek bit after seek has completed
+  updateRegisters();
+
+  //Wait for the si4703 to clear the STC as well
+  while(1) {
+    ack = readRegisters();
+    wait_ms(1); // Just In Case...   
+    if (((si4703_registers[STATUSRSSI] & (1<<STC)) == 0) || (ack != SUCCESS)) break; //Tuning complete! (or FAILED)
+  }
+
+  if(valueSFBL) { //The bit was set indicating we hit a band limit or failed to find a station
+    return(0);
+  }
+return getChannel();
+}
+
+//Reads the current channel from READCHAN
+//Returns a number like 973 for 97.3MHz
+int Si4703_Breakout::getChannel() {
+  readRegisters();
+  int channel = (si4703_registers[READCHAN] & 0x03FF); //Mask out everything but the lower 10 bits
+  //Freq(MHz) = 0.100(in Europe) * Channel + 87.5MHz
+  //X = 0.1 * Chan + 87.5
+  channel += 875; //98 + 875 = 973 ( for 97.3 MHz )
+  return(channel);
+}
+
+void Si4703_Breakout::printRegs() {
+  readRegisters();
+  for (int x=0; x<16; x++) { pc->printf("Reg# 0x%X = 0x%X\r\n",x,si4703_registers[x]); }
+}