Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: APDS_9960 TextLCD mbed
Fork of Si4703 by
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 }
Generated on Thu Jul 28 2022 05:03:58 by
1.7.2
