├── examples ├── README.md └── Si4703_Radio_Test │ └── Si4703_Radio_Test.ino ├── src ├── README.md ├── Standard_code_header.c ├── SparkFunSi4703.h └── SparkFunSi4703.cpp ├── library.properties ├── keywords.txt ├── .gitattributes ├── README.md └── .gitignore /examples/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | This folder should contain the .cpp and .h files for the library. 2 | 3 | If backward compatibility is needed, source code should be placed in the library root folder and in a "utilyt" folder. 4 | 5 | Check out the [library specification](https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification) for more details. -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun Si4703 2 | version=1.3.0 3 | author=Simon Monk, SparkFun Electronics 4 | maintainer=SparkFun Electronics 5 | sentence=Basic functionality of the Si4703 FM tuner chip. 6 | paragraph=Allows user to tune to different FM stations, find station ID and song name, and RDS and RBDS information. 7 | category=Other 8 | url=https://github.com/sparkfun/SparkFun_Si4703_Arduino_Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Si4703 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | Si4703_Breakout KEYWORD1 9 | 10 | ####################################### 11 | # Methods and Functions (KEYWORD2) 12 | ####################################### 13 | powerOn KEYWORD2 14 | setChannel KEYWORD2 15 | seekUp KEYWORD2 16 | seekDown KEYWORD2 17 | setVolume KEYWORD2 18 | readRDS KEYWORD2 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /src/Standard_code_header.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | /****************************************************************************** 4 | 5 | 6 | <name @ SparkFun Electronics> 7 | <original creation date> 8 | <github repository address> 9 | 10 | <multiline verbose description of file functionality> 11 | 12 | Resources: 13 | <additional library requirements> 14 | 15 | Development environment specifics: 16 | <arduino/development environment version> 17 | <hardware version> 18 | <etc> 19 | 20 | This code is beerware; if you see me (or any other SparkFun employee) at the 21 | local, and you've found our code helpful, please buy us a round! 22 | 23 | Distributed as-is; no warranty is given. 24 | ******************************************************************************/ -------------------------------------------------------------------------------- /examples/Si4703_Radio_Test/Si4703_Radio_Test.ino: -------------------------------------------------------------------------------- 1 | #include <SparkFunSi4703.h> 2 | #include <Wire.h> 3 | 4 | int resetPin = 2; 5 | int SDIO = A4; 6 | int SCLK = A5; 7 | int STC = 3; 8 | 9 | Si4703_Breakout radio(resetPin, SDIO, SCLK, STC); 10 | int channel; 11 | int volume; 12 | char rdsBuffer[10]; 13 | 14 | void setup() 15 | { 16 | Serial.begin(9600); 17 | Serial.println("\n\nSi4703_Breakout Test Sketch"); 18 | Serial.println("==========================="); 19 | Serial.println("a b Favourite stations"); 20 | Serial.println("+ - Volume (max 15)"); 21 | Serial.println("u d Seek up / down"); 22 | Serial.println("r Listen for RDS Data (15 sec timeout)"); 23 | Serial.println("Send me a command letter."); 24 | 25 | 26 | radio.powerOn(); 27 | radio.setVolume(0); 28 | } 29 | 30 | void loop() 31 | { 32 | if (Serial.available()) 33 | { 34 | char ch = Serial.read(); 35 | if (ch == 'u') 36 | { 37 | channel = radio.seekUp(); 38 | displayInfo(); 39 | } 40 | else if (ch == 'd') 41 | { 42 | channel = radio.seekDown(); 43 | displayInfo(); 44 | } 45 | else if (ch == '+') 46 | { 47 | volume ++; 48 | if (volume == 16) volume = 15; 49 | radio.setVolume(volume); 50 | displayInfo(); 51 | } 52 | else if (ch == '-') 53 | { 54 | volume --; 55 | if (volume < 0) volume = 0; 56 | radio.setVolume(volume); 57 | displayInfo(); 58 | } 59 | else if (ch == 'a') 60 | { 61 | channel = 930; // Rock FM 62 | radio.setChannel(channel); 63 | displayInfo(); 64 | } 65 | else if (ch == 'b') 66 | { 67 | channel = 974; // BBC R4 68 | radio.setChannel(channel); 69 | displayInfo(); 70 | } 71 | else if (ch == 'r') 72 | { 73 | Serial.println("RDS listening"); 74 | radio.readRDS(rdsBuffer, 15000); 75 | Serial.print("RDS heard:"); 76 | Serial.println(rdsBuffer); 77 | } 78 | } 79 | } 80 | 81 | void displayInfo() 82 | { 83 | Serial.print("Channel:"); Serial.print(channel); 84 | Serial.print(" Volume:"); Serial.println(volume); 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun Si4703 Arduino Library 2 | ======================================== 3 | 4 | <table class="table table-hover table-striped table-bordered"> 5 | <tr align="center"> 6 | <td><a href="https://www.sparkfun.com/products/11083"><img src="https://cdn.sparkfun.com/r/600-600/assets/parts/6/2/3/5/11083-02.jpg" alt="SparkFun Si4703"></a></td> 7 | <td><a href="https://www.sparkfun.com/products/12938"><img src="https://cdn.sparkfun.com/r/600-600/assets/parts/9/8/6/6/12938-01.jpg" alt="SparkFun FM Tuner Evaluation Board - Si4703"></a></td> 8 | </tr> 9 | <tr align="center"> 10 | <td><i>SparkFun Si4703 Breakout [<a href="https://www.sparkfun.com/products/11083">BOB-11083</a>]</i></td> 11 | <td><i>SparkFun FM Tuner Evaluation Board - Si4703 [<a href="https://www.sparkfun.com/products/12938">WRL-12938</a>]</i></td> 12 | </tr> 13 | </table> 14 | 15 | 16 | Basic functionality of the Si4703 FM tuner chip. Allows user to tune to different FM stations, find station ID and song name, and RDS and RBDS information. 17 | 18 | Repository Contents 19 | ------------------- 20 | 21 | * **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. 22 | * **/src** - Source files for the library (.cpp, .h). 23 | * **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE. 24 | * **library.properties** - General library properties for the Arduino package manager. 25 | 26 | Documentation 27 | -------------- 28 | 29 | * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. 30 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/si4703-fm-radio-receiver-hookup-guide)** - Basic hookup Guide for the SI4703 Evaluation board. 31 | * **[Product Repository](https://github.com/sparkfun/FM_Tuner_Basic_Breakout-Si4703)** - Main repository (including hardware files) for the Si4703 Breakout. 32 | 33 | Products that use this Library 34 | --------------------------------- 35 | * [SparkFun FM Tuner Evaluation Board](https://www.sparkfun.com/products/10663)- Evaluation board for Si4703. Includes audio jack. 36 | * [SparkFun FM Tuner Basic Breakout](https://www.sparkfun.com/products/11083)- Basic breakout of Si4703. 37 | 38 | License Information 39 | ------------------- 40 | 41 | This product is _**open source**_! 42 | 43 | Distributed as-is; no warranty is given. 44 | 45 | - Your friends at SparkFun. 46 | 47 | _The original SparkFun code was modified by Simon Monk. Thanks Simon!_ 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## SparkFun Useful stuff 3 | ################# 4 | 5 | ## AVR Development 6 | *.eep 7 | *.elf 8 | *.lst 9 | *.lss 10 | *.sym 11 | *.d 12 | *.o 13 | *.srec 14 | *.map 15 | 16 | ## Notepad++ backup files 17 | *.bak 18 | 19 | ## BOM files 20 | *bom* 21 | 22 | ################# 23 | ## Eclipse 24 | ################# 25 | 26 | *.pydevproject 27 | .project 28 | .metadata 29 | bin/ 30 | tmp/ 31 | *.tmp 32 | *.bak 33 | *.swp 34 | *~.nib 35 | local.properties 36 | .classpath 37 | .settings/ 38 | .loadpath 39 | 40 | # External tool builders 41 | .externalToolBuilders/ 42 | 43 | # Locally stored "Eclipse launch configurations" 44 | *.launch 45 | 46 | # CDT-specific 47 | .cproject 48 | 49 | # PDT-specific 50 | .buildpath 51 | 52 | 53 | ############# 54 | ## Eagle 55 | ############# 56 | 57 | # Ignore the board and schematic backup files 58 | *.b#? 59 | *.s#? 60 | 61 | 62 | ################# 63 | ## Visual Studio 64 | ################# 65 | 66 | ## Ignore Visual Studio temporary files, build results, and 67 | ## files generated by popular Visual Studio add-ons. 68 | 69 | # User-specific files 70 | *.suo 71 | *.user 72 | *.sln.docstates 73 | 74 | # Build results 75 | [Dd]ebug/ 76 | [Rr]elease/ 77 | *_i.c 78 | *_p.c 79 | *.ilk 80 | *.meta 81 | *.obj 82 | *.pch 83 | *.pdb 84 | *.pgc 85 | *.pgd 86 | *.rsp 87 | *.sbr 88 | *.tlb 89 | *.tli 90 | *.tlh 91 | *.tmp 92 | *.vspscc 93 | .builds 94 | *.dotCover 95 | 96 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 97 | #packages/ 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opensdf 104 | *.sdf 105 | 106 | # Visual Studio profiler 107 | *.psess 108 | *.vsp 109 | 110 | # ReSharper is a .NET coding add-in 111 | _ReSharper* 112 | 113 | # Installshield output folder 114 | [Ee]xpress 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish 128 | 129 | # Others 130 | [Bb]in 131 | [Oo]bj 132 | sql 133 | TestResults 134 | *.Cache 135 | ClientBin 136 | stylecop.* 137 | ~$* 138 | *.dbmdl 139 | Generated_Code #added for RIA/Silverlight projects 140 | 141 | # Backup & report files from converting an old project file to a newer 142 | # Visual Studio version. Backup files are not needed, because we have git ;-) 143 | _UpgradeReport_Files/ 144 | Backup*/ 145 | UpgradeLog*.XML 146 | 147 | 148 | ############ 149 | ## Windows 150 | ############ 151 | 152 | # Windows image file caches 153 | Thumbs.db 154 | 155 | # Folder config file 156 | Desktop.ini 157 | 158 | 159 | ############# 160 | ## Python 161 | ############# 162 | 163 | *.py[co] 164 | 165 | # Packages 166 | *.egg 167 | *.egg-info 168 | dist 169 | build 170 | eggs 171 | parts 172 | bin 173 | var 174 | sdist 175 | develop-eggs 176 | .installed.cfg 177 | 178 | # Installer logs 179 | pip-log.txt 180 | 181 | # Unit test / coverage reports 182 | .coverage 183 | .tox 184 | 185 | #Translations 186 | *.mo 187 | 188 | #Mr Developer 189 | .mr.developer.cfg 190 | 191 | # Mac crap 192 | .DS_Store 193 | -------------------------------------------------------------------------------- /src/SparkFunSi4703.h: -------------------------------------------------------------------------------- 1 | /* 2 | Library for Sparkfun Si4703 breakout board. 3 | Simon Monk. 2011-09-09 4 | 5 | This is a library wrapper and a few extras to the excellent code produced 6 | by Nathan Seidle from Sparkfun (Beerware). 7 | 8 | Nathan's comments...... 9 | 10 | Look for serial output at 57600bps. 11 | 12 | The Si4703 ACKs the first byte, and NACKs the 2nd byte of a read. 13 | 14 | 1/18 - after much hacking, I suggest NEVER write to a register without first reading the contents of a chip. 15 | ie, don't updateRegisters without first readRegisters. 16 | 17 | If anyone manages to get this datasheet downloaded 18 | http://wenku.baidu.com/view/d6f0e6ee5ef7ba0d4a733b61.html 19 | Please let us know. It seem to be the latest version of the programming guide. It had a change on page 12 (write 0x8100 to 0x07) 20 | that allowed me to get the chip working.. 21 | 22 | Also, if you happen to find "AN243: Using RDS/RBDS with the Si4701/03", please share. I love it when companies refer to 23 | documents that don't exist. 24 | 25 | 1/20 - Picking up FM stations from a plane flying over Portugal! Sweet! 93.9MHz sounds a little soft for my tastes,s but 26 | it's in Porteguese. 27 | 28 | ToDo: 29 | Display current status (from 0x0A) - done 1/20/11 30 | Add RDS decoding - works, sort of 31 | Volume Up/Down - done 1/20/11 32 | Mute toggle - done 1/20/11 33 | Tune Up/Down - done 1/20/11 34 | Read current channel (0xB0) - done 1/20/11 35 | Setup for Europe - done 1/20/11 36 | Seek up/down - done 1/25/11 37 | 38 | The Si4703 breakout does work with line out into a stereo or other amplifier. Be sure to test with different length 3.5mm 39 | cables. Too short of a cable may degrade reception. 40 | */ 41 | 42 | #ifndef SparkFunSi4703_h 43 | #define SparkFunSi4703_h 44 | 45 | #include "Arduino.h" 46 | 47 | 48 | 49 | class Si4703_Breakout 50 | { 51 | public: 52 | Si4703_Breakout(int resetPin, int sdioPin, int sclkPin, int stcIntPin); 53 | void powerOn(); // call in setup 54 | void setChannel(int channel); // 3 digit channel number 55 | int seekUp(); // returns the tuned channel or 0 56 | int seekDown(); 57 | void setVolume(int volume); // 0 to 15 58 | void readRDS(char* message, long timeout); 59 | // message should be at least 9 chars 60 | // result will be null terminated 61 | // timeout in milliseconds 62 | private: 63 | int _resetPin; 64 | int _sdioPin; 65 | int _sclkPin; 66 | int _stcIntPin; 67 | void si4703_init(); 68 | void readRegisters(); 69 | byte updateRegisters(); 70 | int seek(byte seekDirection); 71 | int getChannel(); 72 | uint16_t si4703_registers[16]; //There are 16 registers, each 16 bits large 73 | static const uint16_t FAIL = 0; 74 | static const uint16_t SUCCESS = 1; 75 | 76 | static const int SI4703 = 0x10; //0b._001.0000 = I2C address of Si4703 - note that the Wire function assumes non-left-shifted I2C address, not 0b.0010.000W 77 | static const uint16_t I2C_FAIL_MAX = 10; //This is the number of attempts we will try to contact the device before erroring out 78 | static const uint16_t SEEK_DOWN = 0; //Direction used for seeking. Default is down 79 | static const uint16_t SEEK_UP = 1; 80 | 81 | //Define the register names 82 | static const uint16_t DEVICEID = 0x00; 83 | static const uint16_t CHIPID = 0x01; 84 | static const uint16_t POWERCFG = 0x02; 85 | static const uint16_t CHANNEL = 0x03; 86 | static const uint16_t SYSCONFIG1 = 0x04; 87 | static const uint16_t SYSCONFIG2 = 0x05; 88 | static const uint16_t STATUSRSSI = 0x0A; 89 | static const uint16_t READCHAN = 0x0B; 90 | static const uint16_t RDSA = 0x0C; 91 | static const uint16_t RDSB = 0x0D; 92 | static const uint16_t RDSC = 0x0E; 93 | static const uint16_t RDSD = 0x0F; 94 | 95 | //Register 0x02 - POWERCFG 96 | static const uint16_t SMUTE = 15; 97 | static const uint16_t DMUTE = 14; 98 | static const uint16_t SKMODE = 10; 99 | static const uint16_t SEEKUP = 9; 100 | static const uint16_t SEEK = 8; 101 | 102 | //Register 0x03 - CHANNEL 103 | static const uint16_t TUNE = 15; 104 | 105 | //Register 0x04 - SYSCONFIG1 106 | static const uint16_t RDS = 12; 107 | static const uint16_t DE = 11; 108 | 109 | //Register 0x05 - SYSCONFIG2 110 | static const uint16_t SPACE1 = 5; 111 | static const uint16_t SPACE0 = 4; 112 | 113 | //Register 0x0A - STATUSRSSI 114 | static const uint16_t RDSR = 15; 115 | static const uint16_t STC = 14; 116 | static const uint16_t SFBL = 13; 117 | static const uint16_t AFCRL = 12; 118 | static const uint16_t RDSS = 11; 119 | static const uint16_t STEREO = 8; 120 | }; 121 | 122 | #endif -------------------------------------------------------------------------------- /src/SparkFunSi4703.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "SparkFunSi4703.h" 3 | #include "Wire.h" 4 | 5 | Si4703_Breakout::Si4703_Breakout(int resetPin, int sdioPin, int sclkPin, int stcIntPin) 6 | { 7 | _resetPin = resetPin; 8 | _sdioPin = sdioPin; 9 | _sclkPin = sclkPin; 10 | _stcIntPin = stcIntPin; 11 | } 12 | 13 | void Si4703_Breakout::powerOn() 14 | { 15 | si4703_init(); 16 | } 17 | 18 | void Si4703_Breakout::setChannel(int channel) 19 | { 20 | //Freq(MHz) = 0.200(in USA) * Channel + 87.5MHz 21 | //97.3 = 0.2 * Chan + 87.5 22 | //9.8 / 0.2 = 49 23 | int newChannel = channel * 10; //973 * 10 = 9730 24 | newChannel -= 8750; //9730 - 8750 = 980 25 | newChannel /= 10; //980 / 10 = 98 26 | 27 | //These steps come from AN230 page 20 rev 0.5 28 | readRegisters(); 29 | si4703_registers[CHANNEL] &= 0xFE00; //Clear out the channel bits 30 | si4703_registers[CHANNEL] |= newChannel; //Mask in the new channel 31 | si4703_registers[CHANNEL] |= (1<<TUNE); //Set the TUNE bit to start 32 | updateRegisters(); 33 | 34 | //delay(60); //Wait 60ms - you can use or skip this delay 35 | 36 | while(_stcIntPin == 1) {} //Wait for interrupt indicating STC (Seek/Tune Complete) 37 | 38 | readRegisters(); 39 | si4703_registers[CHANNEL] &= ~(1<<TUNE); //Clear the tune after a tune has completed 40 | updateRegisters(); 41 | 42 | //Wait for the si4703 to clear the STC as well 43 | while(1) { 44 | readRegisters(); 45 | if( (si4703_registers[STATUSRSSI] & (1<<STC)) == 0) break; //Tuning complete! 46 | } 47 | } 48 | 49 | int Si4703_Breakout::seekUp() 50 | { 51 | return seek(SEEK_UP); 52 | } 53 | 54 | int Si4703_Breakout::seekDown() 55 | { 56 | return seek(SEEK_DOWN); 57 | } 58 | 59 | void Si4703_Breakout::setVolume(int volume) 60 | { 61 | readRegisters(); //Read the current register set 62 | if(volume < 0) volume = 0; 63 | if (volume > 15) volume = 15; 64 | si4703_registers[SYSCONFIG2] &= 0xFFF0; //Clear volume bits 65 | si4703_registers[SYSCONFIG2] |= volume; //Set new volume 66 | updateRegisters(); //Update 67 | } 68 | 69 | void Si4703_Breakout::readRDS(char* buffer, long timeout) 70 | { 71 | long endTime = millis() + timeout; 72 | boolean completed[] = {false, false, false, false}; 73 | int completedCount = 0; 74 | while(completedCount < 4 && millis() < endTime) { 75 | readRegisters(); 76 | if(si4703_registers[STATUSRSSI] & (1<<RDSR)){ 77 | // ls 2 bits of B determine the 4 letter pairs 78 | // once we have a full set return 79 | // if you get nothing after 20 readings return with empty string 80 | uint16_t b = si4703_registers[RDSB]; 81 | int index = b & 0x03; 82 | if (! completed[index] && b < 500) 83 | { 84 | completed[index] = true; 85 | completedCount ++; 86 | char Dh = (si4703_registers[RDSD] & 0xFF00) >> 8; 87 | char Dl = (si4703_registers[RDSD] & 0x00FF); 88 | buffer[index * 2] = Dh; 89 | buffer[index * 2 +1] = Dl; 90 | // Serial.print(si4703_registers[RDSD]); Serial.print(" "); 91 | // Serial.print(index);Serial.print(" "); 92 | // Serial.write(Dh); 93 | // Serial.write(Dl); 94 | // Serial.println(); 95 | } 96 | delay(40); //Wait for the RDS bit to clear 97 | } 98 | else { 99 | delay(30); //From AN230, using the polling method 40ms should be sufficient amount of time between checks 100 | } 101 | } 102 | if (millis() >= endTime) { 103 | buffer[0] ='\0'; 104 | return; 105 | } 106 | 107 | buffer[8] = '\0'; 108 | } 109 | 110 | 111 | 112 | 113 | //To get the Si4703 inito 2-wire mode, SEN needs to be high and SDIO needs to be low after a reset 114 | //The breakout board has SEN pulled high, but also has SDIO pulled high. Therefore, after a normal power up 115 | //The Si4703 will be in an unknown state. RST must be controlled 116 | void Si4703_Breakout::si4703_init() 117 | { 118 | pinMode(_resetPin, OUTPUT); 119 | pinMode(_sdioPin, OUTPUT); //SDIO is connected to A4 for I2C 120 | pinMode(_stcIntPin, OUTPUT); //STC (search/tune complete) interrupt pin 121 | digitalWrite(_sdioPin, LOW); //A low SDIO indicates a 2-wire interface 122 | digitalWrite(_resetPin, LOW); //Put Si4703 into reset 123 | digitalWrite(_stcIntPin, HIGH); //STC goes low on interrupt 124 | delay(1); //Some delays while we allow pins to settle 125 | digitalWrite(_resetPin, HIGH); //Bring Si4703 out of reset with SDIO set to low and SEN pulled high with on-board resistor 126 | delay(1); //Allow Si4703 to come out of reset 127 | 128 | Wire.begin(); //Now that the unit is reset and I2C inteface mode, we need to begin I2C 129 | 130 | readRegisters(); //Read the current register set 131 | //si4703_registers[0x07] = 0xBC04; //Enable the oscillator, from AN230 page 9, rev 0.5 (DOES NOT WORK, wtf Silicon Labs datasheet?) 132 | si4703_registers[0x07] = 0x8100; //Enable the oscillator, from AN230 page 9, rev 0.61 (works) 133 | si4703_registers[0x04] |= 0x2000; //Set bit 14 to high to enable STC Interrupt on GPIO2 134 | updateRegisters(); //Update 135 | 136 | delay(500); //Wait for clock to settle - from AN230 page 9 137 | 138 | readRegisters(); //Read the current register set 139 | si4703_registers[POWERCFG] = 0x4001; //Enable the IC 140 | // si4703_registers[POWERCFG] |= (1<<SMUTE) | (1<<DMUTE); //Disable Mute, disable softmute 141 | si4703_registers[SYSCONFIG1] |= (1<<RDS); //Enable RDS 142 | 143 | si4703_registers[SYSCONFIG1] |= (1<<DE); //50kHz Europe setup 144 | si4703_registers[SYSCONFIG2] |= (1<<SPACE0); //100kHz channel spacing for Europe 145 | 146 | si4703_registers[SYSCONFIG2] &= 0xFFF0; //Clear volume bits 147 | si4703_registers[SYSCONFIG2] |= 0x0001; //Set volume to lowest 148 | updateRegisters(); //Update 149 | 150 | delay(110); //Max powerup time, from datasheet page 13 151 | } 152 | 153 | //Read the entire register control set from 0x00 to 0x0F 154 | void Si4703_Breakout::readRegisters(){ 155 | 156 | //Si4703 begins reading from register upper register of 0x0A and reads to 0x0F, then loops to 0x00. 157 | Wire.requestFrom(SI4703, 32); //We want to read the entire register set from 0x0A to 0x09 = 32 bytes. 158 | 159 | //Remember, register 0x0A comes in first so we have to shuffle the array around a bit 160 | for(int x = 0x0A ; ; x++) { //Read in these 32 bytes 161 | if(x == 0x10) x = 0; //Loop back to zero 162 | si4703_registers[x] = Wire.read() << 8; 163 | si4703_registers[x] |= Wire.read(); 164 | if(x == 0x09) break; //We're done! 165 | } 166 | } 167 | 168 | //Write the current 9 control registers (0x02 to 0x07) to the Si4703 169 | //It's a little weird, you don't write an I2C addres 170 | //The Si4703 assumes you are writing to 0x02 first, then increments 171 | byte Si4703_Breakout::updateRegisters() { 172 | 173 | Wire.beginTransmission(SI4703); 174 | //A write command automatically begins with register 0x02 so no need to send a write-to address 175 | //First we send the 0x02 to 0x07 control registers 176 | //In general, we should not write to registers 0x08 and 0x09 177 | for(int regSpot = 0x02 ; regSpot < 0x08 ; regSpot++) { 178 | byte high_byte = si4703_registers[regSpot] >> 8; 179 | byte low_byte = si4703_registers[regSpot] & 0x00FF; 180 | 181 | Wire.write(high_byte); //Upper 8 bits 182 | Wire.write(low_byte); //Lower 8 bits 183 | } 184 | 185 | //End this transmission 186 | byte ack = Wire.endTransmission(); 187 | if(ack != 0) { //We have a problem! 188 | return(FAIL); 189 | } 190 | 191 | return(SUCCESS); 192 | } 193 | 194 | //Seeks out the next available station 195 | //Returns the freq if it made it 196 | //Returns zero if failed 197 | int Si4703_Breakout::seek(byte seekDirection){ 198 | readRegisters(); 199 | //Set seek mode wrap bit 200 | si4703_registers[POWERCFG] |= (1<<SKMODE); //Allow wrap 201 | //si4703_registers[POWERCFG] &= ~(1<<SKMODE); //Disallow wrap - if you disallow wrap, you may want to tune to 87.5 first 202 | if(seekDirection == SEEK_DOWN) si4703_registers[POWERCFG] &= ~(1<<SEEKUP); //Seek down is the default upon reset 203 | else si4703_registers[POWERCFG] |= 1<<SEEKUP; //Set the bit to seek up 204 | 205 | si4703_registers[POWERCFG] |= (1<<SEEK); //Start seek 206 | updateRegisters(); //Seeking will now start 207 | 208 | while(_stcIntPin == 1) {} //Wait for interrupt indicating STC (Seek/Tune complete) 209 | 210 | readRegisters(); 211 | int valueSFBL = si4703_registers[STATUSRSSI] & (1<<SFBL); //Store the value of SFBL 212 | si4703_registers[POWERCFG] &= ~(1<<SEEK); //Clear the seek bit after seek has completed 213 | updateRegisters(); 214 | 215 | //Wait for the si4703 to clear the STC as well 216 | while(1) { 217 | readRegisters(); 218 | if( (si4703_registers[STATUSRSSI] & (1<<STC)) == 0) break; //Tuning complete! 219 | } 220 | 221 | if(valueSFBL) { //The bit was set indicating we hit a band limit or failed to find a station 222 | return(0); 223 | } 224 | return getChannel(); 225 | } 226 | 227 | //Reads the current channel from READCHAN 228 | //Returns a number like 973 for 97.3MHz 229 | int Si4703_Breakout::getChannel() { 230 | readRegisters(); 231 | int channel = si4703_registers[READCHAN] & 0x03FF; //Mask out everything but the lower 10 bits 232 | //Freq(MHz) = 0.100(in Europe) * Channel + 87.5MHz 233 | //X = 0.1 * Chan + 87.5 234 | channel += 875; //98 + 875 = 973 235 | return(channel); 236 | } 237 | --------------------------------------------------------------------------------