Nicholas Ciulla / Mbed 2 deprecated CiullaNguyenIUPUI495_GestureControlledFMRadio

Dependencies:   APDS_9960 TextLCD mbed

Fork of Si4703 by kris gjika

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers parkFun-Si4703.cpp Source File

parkFun-Si4703.cpp

00001 #include "mbed.h"
00002 #include "SparkFun-Si4703.h"
00003  
00004 Si4703_Breakout::Si4703_Breakout(PinName sdioPin, PinName sclkPin, PinName resetPin, Serial *pc)
00005 {
00006   _resetPin = resetPin;
00007   _sdioPin = sdioPin;
00008   _sclkPin = sclkPin;
00009  
00010  this->pc = pc;
00011 }
00012  
00013 void Si4703_Breakout::powerOn()
00014 {
00015     si4703_init();
00016 }
00017  
00018 void Si4703_Breakout::powerOff()
00019 {
00020 // a Minimal Power-Down Sequence - According To SI AN230 (rev. 0.9), p.13 - Table 4
00021  
00022 readRegisters();
00023  
00024 si4703_registers[POWERCFG] &= ~(1<<DMUTE); // 'Enable Mute'
00025 si4703_registers[POWERCFG] |= (1<<ENABLE); // 'Enable IC'
00026 si4703_registers[POWERCFG] |= (1<<DISABLE); // & 'Disable IC'
00027                                             // To Init. Power-Down Sequence
00028  
00029 updateRegisters();
00030 // Notice : This Does NOT Perform a Reset of The IC.
00031 }
00032  
00033 void Si4703_Breakout::setChannel(int channel)
00034 {
00035   uint8_t ack;
00036   //Freq(MHz) = 0.1 (in Europe) * Channel + 87.5MHz
00037   //97.3 = 0.1 * Chan + 87.5
00038   //9.8 / 0.1 = 98
00039   int newChannel = channel * 10; //973 * 10 = 9730
00040   newChannel -= 8750; //9730 - 8750 = 980
00041   newChannel /= 10; //980 / 10 = 98
00042  
00043   //These steps come from AN230 page 20 rev 0.5
00044   readRegisters();
00045   si4703_registers[CHANNEL] &= 0xFE00; //Clear out the channel bits
00046   si4703_registers[CHANNEL] |= newChannel; //Mask in the new channel
00047   si4703_registers[CHANNEL] |= (1<<TUNE); //Set the TUNE bit to start
00048   updateRegisters();
00049  
00050   wait_ms(60); //Wait 60ms - you can use or skip this delay
00051  
00052   //Poll to see if STC is set
00053   while(1) {
00054     ack = readRegisters();
00055     wait_ms(1); // Just In Case...
00056     if (( (si4703_registers[STATUSRSSI] & (1<<STC)) != 0) || (ack != SUCCESS)) break; //Tuning complete! (or FAILED)
00057   }
00058  
00059   readRegisters();
00060   si4703_registers[CHANNEL] &= ~(1<<TUNE); //Clear the tune after a tune has completed
00061   updateRegisters();
00062  
00063   //Wait for the si4703 to clear the STC as well
00064   while(1) {
00065     ack = readRegisters();
00066     wait_ms(1); // Just In Case...
00067     if (( (si4703_registers[STATUSRSSI] & (1<<STC)) == 0) || (ack != SUCCESS)) break; //Tuning complete! (or FAILED)
00068   }
00069 }
00070  
00071 int Si4703_Breakout::seekUp()
00072 {
00073     return seek(SEEK_UP);
00074 }
00075  
00076 int Si4703_Breakout::seekDown()
00077 {
00078     return seek(SEEK_DOWN);
00079 }
00080  
00081 void Si4703_Breakout::setVolume(int volume)
00082 {
00083   readRegisters(); //Read the current register set
00084   if(volume < 0) volume = 0;
00085   if (volume > 15) volume = 15;
00086   si4703_registers[SYSCONFIG2] &= 0xFFF0; //Clear volume bits
00087   si4703_registers[SYSCONFIG2] |= volume; //Set new volume
00088   updateRegisters(); //Update
00089 }
00090  
00091 uint8_t Si4703_Breakout::getVolume()
00092 {
00093   readRegisters(); //Read the current register set
00094  
00095   return (si4703_registers[SYSCONFIG2] & 0x000F);
00096 }
00097  
00098 /*
00099 void Si4703_Breakout::readRDS(char* buffer, long timeout)
00100 { 
00101     long endTime = millis() + timeout;
00102   boolean completed[] = {false, false, false, false};
00103   int completedCount = 0;
00104   while(completedCount < 4 && millis() < endTime) {
00105     readRegisters();
00106     if(si4703_registers[STATUSRSSI] & (1<<RDSR)){
00107         // ls 2 bits of B determine the 4 letter pairs
00108         // once we have a full set return
00109         // if you get nothing after 20 readings return with empty string
00110       uint16_t b = si4703_registers[RDSB];
00111       int index = b & 0x03;
00112       if (! completed[index] && b < 500)
00113       {
00114         completed[index] = true;
00115         completedCount ++;
00116         char Dh = (si4703_registers[RDSD] & 0xFF00) >> 8;
00117         char Dl = (si4703_registers[RDSD] & 0x00FF);
00118         buffer[index * 2] = Dh;
00119         buffer[index * 2 +1] = Dl;
00120         // Serial.print(si4703_registers[RDSD]); Serial.print(" ");
00121         // Serial.print(index);Serial.print(" ");
00122         // Serial.write(Dh);
00123         // Serial.write(Dl);
00124         // Serial.println();
00125       }
00126       delay(40); //Wait for the RDS bit to clear
00127     }
00128     else {
00129       delay(30); //From AN230, using the polling method 40ms should be sufficient amount of time between checks
00130     }
00131   }
00132     if (millis() >= endTime) {
00133         buffer[0] ='\0';
00134         return;
00135     }
00136  
00137   buffer[8] = '\0';
00138 }
00139 */
00140  
00141  
00142  
00143 //To get the Si4703 inito 2-wire mode, SEN needs to be high and SDIO needs to be low after a reset
00144 //The breakout board has SEN pulled high, but also has SDIO pulled high. Therefore, after a normal power up
00145 //The Si4703 will be in an unknown state. RST must be controlled
00146 void Si4703_Breakout::si4703_init() 
00147 {
00148   _reset_ = new DigitalOut(_resetPin);
00149   _sdio_ = new DigitalOut(_sdioPin);
00150  
00151   _sdio_->write(0); //A low SDIO indicates a 2-wire interface
00152   _reset_->write(0); //Put Si4703 into reset
00153   wait_ms(1); //Some delays while we allow pins to settle
00154   _reset_->write(1); //Bring Si4703 out of reset with SDIO set to low and SEN pulled high with on-board resistor
00155   wait_ms(1); //Allow Si4703 to come out of reset
00156  
00157   //Now that the unit is reset and I2C inteface mode, we need to begin I2C
00158   i2c_ = new I2C(_sdioPin, _sclkPin);
00159   i2c_->frequency(100000);
00160   ///
00161  
00162   readRegisters(); //Read the current register set
00163   si4703_registers[0x07] = 0x8100; //Enable the oscillator, from AN230 page 9, rev 0.61 (works)
00164   updateRegisters(); //Update
00165  
00166   wait_ms(500); //Wait for clock to settle - from AN230 page 9
00167  
00168   readRegisters(); //Read the current register set
00169   si4703_registers[POWERCFG] = 0x4001; //Enable the IC
00170   //  si4703_registers[POWERCFG] |= (1<<SMUTE) | (1<<DMUTE); //Disable Mute, disable softmute
00171   si4703_registers[SYSCONFIG1] |= (1<<RDS); //Enable RDS
00172  
00173   si4703_registers[SYSCONFIG1] |= (1<<DE); //50μS Europe setup
00174   si4703_registers[SYSCONFIG2] |= (1<<SPACE0); //100kHz channel spacing for Europe
00175  
00176   si4703_registers[SYSCONFIG2] &= 0xFFF0; //Clear volume bits
00177   si4703_registers[SYSCONFIG2] |= 0x0001; //Set volume to lowest
00178  
00179   // SI AN230 page 40 - Table 23 ('Good Quality Stations Only' Settings)
00180   si4703_registers[SYSCONFIG2] |= (0xC<<SEEKTH);
00181   si4703_registers[SYSCONFIG3] |= (0x7<<SKSNR);
00182   si4703_registers[SYSCONFIG3] |= (0xF<<SKCNT);
00183   ///
00184   updateRegisters(); //Update
00185  
00186   wait_ms(110); //Max powerup time, from datasheet page 13
00187   
00188 }
00189  
00190 //Read the entire register control set from 0x00 to 0x0F
00191 uint8_t Si4703_Breakout::readRegisters(){
00192  
00193   //Si4703 begins reading from register upper register of 0x0A and reads to 0x0F, then loops to 0x00.
00194 //  Wire.requestFrom(SI4703, 32); //We want to read the entire register set from 0x0A to 0x09 = 32 uint8_ts.
00195     char data[32];
00196     uint8_t ack = i2c_->read(SI4703, data, 32); //Read in these 32 uint8_ts
00197  
00198   if (ack != 0) { //We have a problem! 
00199     return(FAIL);
00200   }
00201  
00202 //Remember, register 0x0A comes in first so we have to shuffle the array around a bit
00203     for (int y=0; y<6; y++)
00204         {
00205             si4703_registers[0x0A+y] = 0;
00206             si4703_registers[0x0A+y] = data[(y*2)+1];
00207             si4703_registers[0x0A+y] |= (data[(y*2)] << 8);
00208         }
00209  
00210     for (int y=0; y<10; y++)
00211         {
00212             si4703_registers[y] = 0;
00213             si4703_registers[y] = data[(12)+(y*2)+1];
00214             si4703_registers[y] |= (data[(12)+(y*2)] << 8);
00215         }
00216 //We're done!
00217 ///
00218   return(SUCCESS);
00219 }
00220  
00221 //Write the current 9 control registers (0x02 to 0x07) to the Si4703
00222 //It's a little weird, you don't write an I2C address
00223 //The Si4703 assumes you are writing to 0x02 first, then increments
00224 uint8_t Si4703_Breakout::updateRegisters() {
00225  
00226   char data[12];
00227  
00228   //First we send the 0x02 to 0x07 control registers
00229   //In general, we should not write to registers 0x08 and 0x09
00230   for(int regSpot = 0x02 ; regSpot < 0x08 ; regSpot++) {
00231     data[(regSpot-2)*2] = si4703_registers[regSpot] >> 8;
00232     data[((regSpot-2)*2)+1] = si4703_registers[regSpot] & 0x00FF;
00233   }
00234  
00235   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
00236  
00237   if(ack != 0) { //We have a problem! 
00238     return(FAIL);
00239   }
00240  
00241   return(SUCCESS);
00242 }
00243  
00244 //Returns The Value of a Register
00245 uint16_t Si4703_Breakout::getRegister(uint8_t regNum)
00246 {
00247   readRegisters();
00248   return si4703_registers[regNum];
00249 // No Error Status Checking
00250 }
00251  
00252 //Seeks out the next available station
00253 //Returns the freq if it made it
00254 //Returns zero if failed
00255 int Si4703_Breakout::seek(bool seekDirection){
00256   uint8_t ack;
00257   readRegisters();
00258   //Set seek mode wrap bit
00259   si4703_registers[POWERCFG] |= (1<<SKMODE); //Disallow wrap - if you disallow wrap, you may want to tune to 87.5 first
00260   //si4703_registers[POWERCFG] &= ~(1<<SKMODE); //Allow wrap
00261   if(seekDirection == SEEK_DOWN) si4703_registers[POWERCFG] &= ~(1<<SEEKUP); //Seek down is the default upon reset
00262   else si4703_registers[POWERCFG] |= 1<<SEEKUP; //Set the bit to seek up
00263  
00264   si4703_registers[POWERCFG] |= (1<<SEEK); //Start seek
00265   updateRegisters(); //Seeking will now start
00266  
00267   //Poll to see if STC is set
00268   while(1) {
00269     ack = readRegisters();
00270     wait_ms(1); // Just In Case...
00271     if (((si4703_registers[STATUSRSSI] & (1<<STC)) != 0) || (ack != SUCCESS)) break; //Tuning complete! (or FAILED)
00272   }
00273  
00274   readRegisters();
00275   int valueSFBL = si4703_registers[STATUSRSSI] & (1<<SFBL); //Store the value of SFBL
00276   si4703_registers[POWERCFG] &= ~(1<<SEEK); //Clear the seek bit after seek has completed
00277   updateRegisters();
00278  
00279   //Wait for the si4703 to clear the STC as well
00280   while(1) {
00281     ack = readRegisters();
00282     wait_ms(1); // Just In Case...   
00283     if (((si4703_registers[STATUSRSSI] & (1<<STC)) == 0) || (ack != SUCCESS)) break; //Tuning complete! (or FAILED)
00284   }
00285  
00286   if(valueSFBL) { //The bit was set indicating we hit a band limit or failed to find a station
00287     return(0);
00288   }
00289 return getChannel();
00290 }
00291  
00292 //Reads the current channel from READCHAN
00293 //Returns a number like 973 for 97.3MHz
00294 int Si4703_Breakout::getChannel() {
00295   readRegisters();
00296   int channel = (si4703_registers[READCHAN] & 0x03FF); //Mask out everything but the lower 10 bits
00297   //Freq(MHz) = 0.100(in Europe) * Channel + 87.5MHz
00298   //X = 0.1 * Chan + 87.5
00299   channel += 875; //98 + 875 = 973 ( for 97.3 MHz )
00300   return(channel);
00301 }
00302  
00303 void Si4703_Breakout::printRegs() {
00304   readRegisters();
00305   for (int x=0; x<16; x++) { pc->printf("Reg# 0x%X = 0x%X\r\n",x,si4703_registers[x]); wait_ms(1); }
00306 }