A mbed Port of 'Sparkfun Si4703 Arduino Library'.
Fork of Si4703 by
Diff: SparkFun-Si4703.cpp
- 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]); } +}