Si4703 sample code ECE 4180 Georgia Tech

Dependencies:   TextLCD mbed

Fork of Si4735 by Brett Wilson

Files at this revision

API Documentation at this revision

Comitter:
Gjika
Date:
Tue Oct 20 14:58:05 2015 +0000
Parent:
0:42c032fc907a
Commit message:
Sample Code for Si4703 Digital FM Radio Receiver

Changed in this revision

Si4735.cpp Show diff for this revision Revisions of this file
Si4735.h Show diff for this revision Revisions of this file
SparkFun-Si4703.h Show annotated file Show diff for this revision Revisions of this file
TextLCD.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
parkFun-Si4703.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r 42c032fc907a -r 563a11fe39e0 Si4735.cpp
--- a/Si4735.cpp	Wed Oct 12 17:01:38 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,271 +0,0 @@
-/* mbed Si4735 Library
- * Brett Wilson and Brett Berry
- * Georgia Tech ECE 4180
- * Note: this code has only been tested for FM. 
- * Ported from ...
-
- * Arduino Si4735 Library
- * Written by Ryan Owens for SparkFun Electronics
- * 5/17/11
- *
- * This library is for use with the SparkFun Si4735 Shield
- * Released under the 'Buy Me a Beer' license
- * (If we ever meet, you buy me a beer)
- *
- * See the header file for better function documentation.
- *
- * See the example sketches to learn how to use the library in your code.
-*/
-
-#include "Si4735.h"
-#include "mbed.h"
-
-//This is just a constructor.
-Si4735::Si4735(PinName sda, PinName scl, PinName RST_) :
-    _RST_(RST_) {
-    i2c_ = new I2C(sda, scl);
-    i2c_->frequency(100000);
-}
-
-
-void Si4735::begin(char mode){
-    _mode = mode;
-    //Set the initial volume level.
-    _currentVolume=63;
-
-    // Reset the Si4735
-    _RST_ = 0;
-    wait(.2);
-    _RST_ = 1;
-    wait(.2);
-    
-    
-    //Send the POWER_UP command
-    switch(_mode){
-        case FM:
-            sprintf(command, "%c%c%c", 0x01, 0x10, 0x05);
-            break;
-        case AM:
-        case SW:
-        case LW:
-            sprintf(command, "%c%c%c", 0x01, 0x11, 0x05);
-            break;
-        default:
-            return;
-    }
-    sendCommand(command, 3);
-    wait(.2);
-    
-    // Set the RCLK to 32768Hz
-    sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x02, 0x01, 0x80, 0x00);
-    sendCommand(command, 6);
-    wait(.2);
-    
-    // Set default frequency to 99.7 MHz FM
-    sprintf(command, "%c%c%c%c", 0x20, 0x00, 0x26, 0xF2);
-    sendCommand(command, 4);
-    wait(.2);
-    
-    //Set the volume to the current value.
-    sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x00, 0x00, _currentVolume);
-    sendCommand(command, 6);
-    wait(.2);
-
-    //Disable Mute
-    sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x01, 0x00, 0x00);
-    sendCommand(command, 6);
-    wait(.2);
-
-    //Set the seek band for the desired mode (AM and FM can use default values)
-    switch(_mode){
-        case SW:
-            //Set the lower band limit for Short Wave Radio to 2300 kHz
-            sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x34, 0x00, 0x08, 0xFC);
-            sendCommand(command, 6);
-            wait(.001);
-            //Set the upper band limit for Short Wave Radio to 23000kHz
-            sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x34, 0x01, 0x59, 0xD8);
-            sendCommand(command, 6);            
-            wait(.001);
-            break;
-        case LW:
-            //Set the lower band limit for Long Wave Radio to 152 kHz
-            sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x34, 0x00, 0x00, 0x99);
-            sendCommand(command, 6);
-            wait(.001);
-            //Set the upper band limit for Long Wave Radio to 279 kHz
-            sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x34, 0x01, 0x01, 0x17);
-            sendCommand(command, 6);
-            wait(.001);            
-            break;
-        default:
-            break;
-    }
-    
-}
-
-/*
-* Description: Tunes the Si4735 to a frequency
-*
-* Params: int frequency - The desired frequency in kHz
-*
-* Returns: True if tune was successful
-*            False if tune was unsuccessful
-*/
-bool Si4735::tuneFrequency(int frequency){
-    //Split the desired frequency into two character for use in the
-    //set frequency command.
-    char highByte = frequency >> 8;
-    char lowByte = frequency & 0x00FF;
-    
-    //Depending on the current mode, set the new frequency.
-    switch(_mode){
-        case FM:
-            sprintf(command, "%c%c%c%c", 0x20, 0x00, highByte, lowByte);
-            break;
-        case AM:
-        case SW:
-        case LW:
-            sprintf(command, "%c%c%c%c", 0x40, 0x00, highByte, lowByte);
-            break;
-        default:
-            break;
-    }
-    sendCommand(command, 4);
-    wait(.1);
-    
-    return true;
-}
-
-//This function does not work unless you bypass the buffer chip!
-int Si4735::getFrequency(void){
-    char data[8];
-    int freq = 0;
-    // FM only
-    i2c_->start();
-    i2c_->write(address_write);
-    i2c_->write(0x22);
-    i2c_->write(0x00);
-    i2c_->stop();
-    i2c_->start();
-    i2c_->write(address_read);
-    for (int i=0; i<8; i++)
-        data[i] = i2c_->read(1);
-    //i2c_->read(address_read, data, 8, false);
-    i2c_->stop();
-    freq = data[2];
-    freq = (freq << 8) | data[3];
-    return freq;
-}
-
-bool Si4735::seekUp(void){
-    //Use the current mode selection to seek up.
-    switch(_mode){
-        case FM:
-            sprintf(command, "%c%c", 0x21, 0x0C);
-            sendCommand(command, 2);
-            break;
-        case AM:
-        case SW:
-        case LW:
-            sprintf(command, "%c%c%c%c%c%c", 0x41, 0x0C, 0x00, 0x00, 0x00, 0x00);
-            sendCommand(command, 6);
-            break;
-        default:
-            break;
-    }
-    wait(.001);
-    return true;
-}
-
-bool Si4735::seekDown(void){
-    //Use the current mode selection to seek down.
-    switch(_mode){
-        case FM:
-            sprintf(command, "%c%c", 0x21, 0x04);
-            sendCommand(command, 2);
-            break;
-        case AM:
-        case SW:
-        case LW:
-            sprintf(command, "%c%c%c%c%c%c", 0x41, 0x04, 0x00, 0x00, 0x00, 0x00);
-            sendCommand(command, 6);
-            break;
-        default:
-            break;
-    }
-    wait(.001);
-    return true;
-}
-
-void Si4735::volumeUp(void){
-    //If we're not at the maximum volume yet, increase the volume
-    if(_currentVolume < 63){
-        _currentVolume+=1;
-        //Set the volume to the current value.
-        sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x00, 0x00, _currentVolume);
-        sendCommand(command, 6);
-        wait(.01);        
-    }
-}
-
-void Si4735::volumeDown(void){
-    //If we're not at the maximum volume yet, increase the volume
-    if(_currentVolume > 0){
-        _currentVolume-=1;
-        //Set the volume to the current value.
-        sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x00, 0x00, _currentVolume);
-        sendCommand(command, 6);
-        wait(.01);        
-    }
-}
-
-void Si4735::mute(void){
-    //Disable Mute
-    sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x01, 0x00, 0x03);
-    sendCommand(command, 6);
-    wait(.001);
-}
-
-void Si4735::unmute(void){
-    //Disable Mute
-    sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x01, 0x00, 0x00);
-    sendCommand(command, 6);
-    wait(.001);
-}
-
-/*char Si4735::getStatus(void){
-    char response;
-    bool ack1, ack2;
-    i2c_->start();
-    ack1 = i2c_->write(address_);  //Send i2c address and wait for ack (true) to proceed
-    response = spi_->write(0xA0);  //read a single byte
-    _cs_ = 1;
-    wait(.001);
-    return response;
-}*/
-/*void Si4735::getResponse(char * response){
-    
-}*/
-
-void Si4735::end(void){
-    sprintf(command, "%c", 0x11);
-    sendCommand(command, 1);
-    wait(.001);
-}
-
-/*******************************************
-*
-* Private Functions
-*
-*******************************************/
-
-void Si4735::sendCommand(char * command, int length){
-  //ack = i2c_->write(address_write, command, length, false);
-  i2c_->start();
-  bool ack = i2c_->write(address_write);
-  for(int i=0; i<length; i++)
-    ack = i2c_->write(command[i]);        
-  char CTS = i2c_->read(1);
-  i2c_->stop();
-  }
diff -r 42c032fc907a -r 563a11fe39e0 Si4735.h
--- a/Si4735.h	Wed Oct 12 17:01:38 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
-/* mbed Si4735 Library
- * Brett Wilson and Brett Berry
- * Georgia Tech ECE 4180
- * Ported from ...
-
- * Arduino Si4735 Library
- * Written by Ryan Owens for SparkFun Electronics
- * 5/17/11
- *
- * This library is for use with the SparkFun Si4735 Shield
- * Released under the 'Buy Me a Beer' license
- * (If we ever meet, you buy me a beer)
- *
- * See the example sketches to learn how to use the library in your code.
-*/
-
-#include "mbed.h"
-
-#ifndef Si4735_h
-#define Si4735_h
-
-//Assign the radio pin numbers
-#define POWER_PIN    8
-#define    RADIO_RESET_PIN    9
-#define INT_PIN    2
-
-//Define the SPI Pin Numbers
-#define DATAOUT 11        //MOSI
-#define DATAIN  12        //MISO 
-#define SPICLOCK  13    //sck
-#define SS 10            //ss
-
-//List of possible modes for the Si4735 Radio
-#define AM    0
-#define    FM    1
-#define SW    2
-#define    LW    3
-
-#define ON    true
-#define OFF    false
-
-#define address_write 34
-#define address_read 35
-
-class Si4735
-{
-    public:
-        //This is just a constructor.
-        Si4735(PinName sda, PinName scl, PinName RST_);
-        /*
-        * Description: 
-        *    Initializes the Si4735, powers up the radio in the desired mode and limits the bandwidth appropriately.
-        *     This function must be called before any other radio command.
-        *    The bands are set as follows:
-        *    FM - 87.5 - 107.9 MHz
-        *    AM - 520 - 1710 kHz
-        *    SW - 2300 - 23000 khz
-        *    LW - 152 - 279 kHz
-        * Parameters:
-        *    mode - The desired radio mode. Use AM(0), FM(1), SW(2) or LW(3).
-        */
-        void begin(char mode);
-        /*
-        * Description: 
-        *    Used to send an ascii command string to the radio.
-        * Parameters:
-        *    myCommand - A null terminated ascii string limited to hexidecimal characters
-        *                to be sent to the radio module. Instructions for building commands can be found
-        *                in the Si4735 Programmers Guide.
-        */
-        void sendCommand(char * myCommand);
-        /*
-        * Description: 
-        *    Used to to tune the radio to a desired frequency. The library uses the mode indicated in the
-        *     begin() function to determine how to set the frequency.
-        * Parameters:
-        *    frequency - The frequency to tune to, in kHz (or in 10kHz if using FM mode).
-        * Returns:
-        *    True
-        * TODO:
-        *     Make the function return true if the tune was successful, else return false.
-        */
-        bool tuneFrequency(int frequency);
-        /*
-        * Description:
-        *    This function currently does not work!
-        * TODO:
-        *    Make this function work.
-        */
-        int getFrequency(void);
-        /*
-        * Description:
-        *    Commands the radio to seek up to the next valid channel. If the top of the band is reached, the seek
-        *    will continue from the bottom of the band.
-        * Returns:
-        *    True
-        * TODO:
-        *    Make the function return true if a valid channel was found, else return false.
-        */
-        bool seekUp(void);
-        /*
-        * Description:
-        *    Commands the radio to seek down to the next valid channel. If the bottom of the band is reached, the seek
-        *    will continue from the top of the band.
-        * Returns:
-        *    True
-        * TODO:
-        *    Make the function return true if a valid channel was found, else return false.
-        */        
-        bool seekDown(void);
-        /*
-        * Description:
-        *    Increasese the volume by 1. If the maximum volume has been reached, no increase will take place.
-        */
-        void volumeUp(void);
-        /*
-        * Description:
-        *    Decreases the volume by 1. If the minimum volume has been reached, no decrease will take place.
-        */
-        void volumeDown(void);
-        /*
-        * Description:
-        *    Mutes the audio output
-        */
-        void mute(void);
-        /*
-        * Description:
-        *    Disables the mute.
-        */
-        void unmute(void);
-        /*
-        * Description:
-        *    Gets the current status of the radio. Learn more about the status in the Si4735 datasheet.
-        * Returns:
-        *    The status of the radio.
-        */
-        char getStatus(void);
-        /*
-        * Description:
-        *    Gets the long response (16 characters) from the radio. Learn more about the long response in the Si4735 datasheet.
-        * Parameters:
-        *    response - A string for the response from the radio to be stored in.
-        */
-        void getResponse(char * response);
-        /*
-        * Description:
-        *    Powers down the radio
-        */
-        void end(void);
-        
-    private:
-        // Pointer for the SPI bus
-        I2C* i2c_;
-        // Declare digital out pins
-        DigitalOut _RST_;
-        /*
-        * A variable that is assigned the current mode of the radio (AM, FM, SW or LW)
-        */
-        char _mode;
-        /*
-        * A variable the keeps the current volume level. 
-        */
-        char _currentVolume;
-        /*
-        * Command string that holds the binary command string to be sent to the Si4735.
-        */
-        char command[9];
-        /*
-        * Description:
-        *    Sends a binary command string to the Si4735.
-        * Parameters:
-        *    command - Binary command to be sent to the radio.
-        *    length - The number of characters in the command string (since it can't be null terminated!)
-        * TODO:
-        *    Make the command wait for a valid CTS response from the radio before releasing control of the CPU.
-        */
-        void sendCommand(char * command, int length);
-        /*
-        * Description:
-        *    Sends/Receives a character from the SPI bus.
-        * Parameters:
-        *    value - The character to be sent to the SPI bus.
-        * Returns:
-        *    The character read from the SPI bus during the transfer.
-        */
-        char spiTransfer(char value);
-        
-};
-
-#endif
\ No newline at end of file
diff -r 42c032fc907a -r 563a11fe39e0 SparkFun-Si4703.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SparkFun-Si4703.h	Tue Oct 20 14:58:05 2015 +0000
@@ -0,0 +1,147 @@
+/* 
+Library for Sparkfun Si4703 breakout board.
+Simon Monk. 2011-09-09
+ 
+This is a library wrapper and a few extras to the excellent code produced
+by Nathan Seidle from Sparkfun (Beerware).
+ 
+Nathan's comments......
+ 
+Look for serial output at 57600bps.
+ 
+The Si4703 ACKs the first byte, and NACKs the 2nd byte of a read.
+ 
+1/18 - after much hacking, I suggest NEVER write to a register without first reading the contents of a chip.
+ie, don't updateRegisters without first readRegisters.
+ 
+If anyone manages to get this datasheet downloaded
+http://wenku.baidu.com/view/d6f0e6ee5ef7ba0d4a733b61.html
+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)
+that allowed me to get the chip working..
+ 
+Also, if you happen to find "AN243: Using RDS/RBDS with the Si4701/03", please share. I love it when companies refer to
+documents that don't exist.
+ 
+1/20 - Picking up FM stations from a plane flying over Portugal! Sweet! 93.9MHz sounds a little soft for my tastes,s but
+it's in Porteguese.
+ 
+ToDo:
+Display current status (from 0x0A) - done 1/20/11
+Add RDS decoding - works, sort of
+Volume Up/Down - done 1/20/11
+Mute toggle - done 1/20/11
+Tune Up/Down - done 1/20/11
+Read current channel (0xB0) - done 1/20/11
+Setup for Europe - done 1/20/11
+Seek up/down - done 1/25/11
+ 
+The Si4703 breakout does work with line out into a stereo or other amplifier. Be sure to test with different length 3.5mm
+cables. Too short of a cable may degrade reception.
+*/
+ 
+#ifndef SparkFun_Si4703_h
+#define SparkFun_Si4703_h
+ 
+#include "mbed.h"
+ 
+ 
+class Si4703_Breakout
+{
+  public:
+    Si4703_Breakout(PinName sdioPin, PinName sclkPin, PinName resetPin, Serial *pc);
+    void powerOn();                 // call in setup
+    void powerOff();                    // call in de-setup
+    void setChannel(int channel);   // 3 digit channel number
+    int getChannel();               // returns the current channel
+    int seekUp();                   // returns the tuned channel or 0
+    int seekDown();                 
+    void setVolume(int volume);     // 0 to 15
+    uint8_t getVolume();    // Returns The Current Volume (0 .. 15)
+ 
+/*  void readRDS(char* message, long timeout);   */
+                                    // message should be at least 9 chars
+                                    // result will be null terminated
+                                    // timeout in milliseconds
+    uint16_t getRegister(uint8_t regNum); // Returns The Value of a Single Register (0x00 .. 0x0F)
+    void printRegs(); // Prints All of The Registers To The Serial Console
+ 
+  private:
+    PinName _resetPin;
+    PinName _sdioPin;
+    PinName _sclkPin;
+ 
+    mbed::I2C *i2c_;
+    mbed::Serial *pc;
+    DigitalOut *_reset_;
+    DigitalOut *_sdio_;
+ 
+    void si4703_init();
+    uint8_t readRegisters();
+    uint8_t updateRegisters();
+    int seek(bool seekDirection);
+ 
+    uint16_t si4703_registers[16]; //There are 16 registers, each 16 bits large
+    static const uint16_t  FAIL = 0;
+    static const uint16_t  SUCCESS = 1;
+ 
+    static const int  SI4703 = 0x20; //0b._001.0000 = I2C address of Si4703 - note that the Wire function assumes non-left-shifted I2C address, not 0b.0010.000W
+    static const uint16_t  I2C_FAIL_MAX = 10; //This is the number of attempts we will try to contact the device before erroring out
+    static const uint16_t  SEEK_DOWN = 0; //Direction used for seeking. Default is down
+    static const uint16_t  SEEK_UP = 1;
+ 
+    //Define the register names
+    static const uint16_t  DEVICEID = 0x00;
+    static const uint16_t  CHIPID = 0x01;
+    static const uint16_t  POWERCFG = 0x02;
+    static const uint16_t  CHANNEL = 0x03;
+    static const uint16_t  SYSCONFIG1 = 0x04;
+    static const uint16_t  SYSCONFIG2 = 0x05;
+    static const uint16_t  SYSCONFIG3 = 0x06;
+    static const uint16_t  TEST1 = 0x07;
+    static const uint16_t  STATUSRSSI = 0x0A;
+    static const uint16_t  READCHAN = 0x0B;
+    static const uint16_t  RDSA = 0x0C;
+    static const uint16_t  RDSB = 0x0D;
+    static const uint16_t  RDSC = 0x0E;
+    static const uint16_t  RDSD = 0x0F;
+ 
+    //Register 0x00 - DeviceID
+//   part# = 15:12, mfgid = 11:0
+ 
+    //Register 0x02 - POWERCFG
+    static const uint16_t  SMUTE = 15;
+    static const uint16_t  DMUTE = 14;
+    static const uint16_t  SKMODE = 10;
+    static const uint16_t  SEEKUP = 9;
+    static const uint16_t  SEEK = 8;
+    static const uint16_t  DISABLE = 6;
+    static const uint16_t  ENABLE = 0;
+ 
+    //Register 0x03 - CHANNEL
+    static const uint16_t  TUNE = 15;
+ 
+    //Register 0x04 - SYSCONFIG1
+    static const uint16_t  RDS = 12;
+    static const uint16_t  DE = 11;
+ 
+    //Register 0x05 - SYSCONFIG2
+    static const uint16_t  SPACE1 = 5;
+    static const uint16_t  SPACE0 = 4;
+    static const uint16_t  SEEKTH = 8;
+ 
+    //Register 0x06 - SYSCONFIG3
+    static const uint16_t  SKSNR  = 4;
+    static const uint16_t  SKCNT  = 0;
+ 
+    //Register 0x0A - STATUSRSSI
+    static const uint16_t  RDSR = 15;
+    static const uint16_t  STC = 14;
+    static const uint16_t  SFBL = 13;
+    static const uint16_t  AFCRL = 12;
+    static const uint16_t  RDSS = 11;
+    static const uint16_t  BLERA = 9;
+    static const uint16_t  STEREO = 8;
+    static const uint16_t  RSSI = 0;
+};
+ 
+#endif
\ No newline at end of file
diff -r 42c032fc907a -r 563a11fe39e0 TextLCD.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextLCD.lib	Tue Oct 20 14:58:05 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/simon/code/TextLCD/#e4cb7ddee0d3
diff -r 42c032fc907a -r 563a11fe39e0 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Oct 20 14:58:05 2015 +0000
@@ -0,0 +1,87 @@
+#include "mbed.h"
+#include "SparkFun-Si4703.h"
+#include "TextLCD.h"
+
+Serial pc(USBTX, USBRX);
+Si4703_Breakout radio(p28, p27, p26, &pc); // (sda, scl, rst, Serial)
+DigitalIn chanUp(p17);
+DigitalIn chanDown(p18);
+DigitalIn volUp(p19);
+DigitalIn volDown(p20);
+TextLCD lcd(p16, p15, p14, p13, p12, p11); // rs, e, d4-d7
+
+
+
+int main(int argc, char** argv) {
+    
+    int chan = 901;
+    int vol = 9;
+    radio.powerOn();
+    radio.setVolume(vol); // range: 0-15
+    radio.setChannel(chan); // 90.1 WABE  
+    
+    lcd.cls(); 
+    lcd.printf("channel = '%d'", radio.getChannel());  
+    lcd.printf(" volume = '%d'\n", radio.getVolume());  
+    pc.printf("channel = '%d'", radio.getChannel());  
+    pc.printf(" volume = '%d'\n", radio.getVolume());  
+ 
+    
+    while(1){
+        if(chanUp) {
+            chan++;
+            radio.setChannel(chan);
+            lcd.cls();
+            lcd.printf("channel = '%d'", radio.getChannel());  
+            lcd.printf(" volume = '%d'\n", radio.getVolume());  
+            pc.printf("channel = '%d'", radio.getChannel());  
+            pc.printf(" volume = '%d'\n", radio.getVolume());  
+            wait(.25);
+        }
+                if(chanDown) {
+            chan--;
+            radio.setChannel(chan);
+            lcd.cls();
+            lcd.printf("channel = '%d'", radio.getChannel());  
+            lcd.printf(" volume = '%d'\n", radio.getVolume());  
+            pc.printf("channel = '%d'", radio.getChannel());  
+            pc.printf(" volume = '%d'\n", radio.getVolume());  
+            wait(.25);
+        }
+                if(volUp && vol <= 14) {
+            vol++;
+            radio.setVolume(vol);
+            lcd.cls();
+            lcd.printf("channel = '%d'", radio.getChannel());  
+            lcd.printf(" volume = '%d'\n", radio.getVolume());  
+            pc.printf("channel = '%d'", radio.getChannel());  
+            pc.printf(" volume = '%d'\n", radio.getVolume());  
+            wait(.25);
+        }
+                if(volUp && vol == 15) {
+            lcd.cls();
+            lcd.printf("channel = '%d'", radio.getChannel());  
+            lcd.printf(" Max Volume\n", radio.getVolume()); 
+            pc.printf("Max Volume\n");
+            wait(.25);
+        }
+                if(volDown && vol >= 1) {
+            vol--;
+            radio.setVolume(vol);
+            lcd.cls();
+            lcd.printf("channel = '%d'", radio.getChannel());  
+            lcd.printf(" volume = '%d'\n", radio.getVolume());  
+            pc.printf("channel = '%d'", radio.getChannel());  
+            pc.printf(" volume = '%d'\n", radio.getVolume());  
+            wait(.25);
+        }
+                if(volDown && vol == 0) {
+            lcd.cls();
+            lcd.printf("channel = '%d'", radio.getChannel());  
+            lcd.printf(" Min Volume\n", radio.getVolume());  
+            pc.printf("Min Volume\n");
+            wait(.25);
+        }
+
+    }
+}
\ No newline at end of file
diff -r 42c032fc907a -r 563a11fe39e0 parkFun-Si4703.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parkFun-Si4703.cpp	Tue Oct 20 14:58:05 2015 +0000
@@ -0,0 +1,306 @@
+#include "mbed.h"
+#include "SparkFun-Si4703.h"
+ 
+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); //50μS 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
+ 
+  // SI AN230 page 40 - Table 23 ('Good Quality Stations Only' Settings)
+  si4703_registers[SYSCONFIG2] |= (0xC<<SEEKTH);
+  si4703_registers[SYSCONFIG3] |= (0x7<<SKSNR);
+  si4703_registers[SYSCONFIG3] |= (0xF<<SKCNT);
+  ///
+  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); //Disallow wrap - if you disallow wrap, you may want to tune to 87.5 first
+  //si4703_registers[POWERCFG] &= ~(1<<SKMODE); //Allow wrap
+  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]); wait_ms(1); }
+}
\ No newline at end of file