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.
Revision 0:dae1bf95c49e, committed 2010-11-09
- Comitter:
- soldeerridder
- Date:
- Tue Nov 09 20:56:52 2010 +0000
- Commit message:
- added documentation
Changed in this revision
| SI570.cpp | Show annotated file Show diff for this revision Revisions of this file |
| SI570.h | Show annotated file Show diff for this revision Revisions of this file |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/SI570.cpp Tue Nov 09 20:56:52 2010 +0000
@@ -0,0 +1,310 @@
+/* mbed SI570 Library, for driving the SI570 programable VCXO
+ * Copyright (c) 2010, Gerrit Polder, PA3BYA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "SI570.h"
+#include "mbed.h"
+
+SI570::SI570(PinName sda, PinName scl, int address)
+ : _i2c(sda, scl) {
+ _address = address;
+ si570reset();
+}
+
+
+
+void SI570::si570reset(void) {
+ _i2c.frequency(100000);
+
+ cmd[0] = 135; // reset
+ cmd[1] = 0x01; //
+ _i2c.write(_address, cmd, 2); // Send command string
+
+ get_registers();
+ fxtal_device = (FOUT_START_UP * n1 * hsdiv) / rfreq; //MHz
+
+ currentFreq = FOUT_START_UP;
+}
+
+void SI570::get_registers() {
+
+ // Set pointer to location 7 (first echo)
+ cmd[0] = 0x7;
+ _i2c.write(_address, cmd, 1);
+
+ _i2c.read(_address, buf, 6); // read the six-byte result
+
+ // HS_DIV conversion
+ hsdiv = ((buf[0] & 0xE0) >> 5) + 4; // get reg 7 bits 5, 6, 7
+ // hsdiv's value could be verified here to ensure that it is one
+ // of the valid HS_DIV values from the datasheet.
+ // n1 conversion
+ n1 = (( buf[0] & 0x1F ) << 2 ) + // get reg 7 bits 0 to 4
+ (( buf[1] & 0xC0 ) >> 6 ); // add with reg 8 bits 7 and 8
+ if (n1 == 0) {
+ n1 = 1;
+ } else if (n1 & 1 != 0) {
+ // add one to an odd number
+ n1 = n1 + 1;
+ }
+
+ frac_bits = (( buf[2] & 0xF ) * POW_2_24 );
+ frac_bits = frac_bits + (buf[3] * POW_2_16);
+ frac_bits = frac_bits + (buf[4] * 256);
+ frac_bits = frac_bits + buf[5];
+
+ rfreq = frac_bits;
+ rfreq = rfreq / POW_2_28;
+ rfreq = rfreq + ( (( buf[1] & 0x3F ) << 4 ) + (( buf[2] & 0xF0 ) >> 4 ) );
+}
+
+
+double SI570::get_frequency(void) {
+ get_registers();
+ return (rfreq*fxtal_device)/(hsdiv*n1);
+}
+
+double SI570::get_rfreq(void) {
+ get_registers();
+ return rfreq;
+}
+
+int SI570::get_n1(void) {
+ get_registers();
+ return n1;
+}
+
+int SI570::get_hsdiv(void) {
+ get_registers();
+ return hsdiv;
+}
+
+int SI570::set_frequency(double frequency) {
+ int err;
+ float diff = 1000000 * (abs(frequency - currentFreq) / currentFreq);
+ if (diff < PPM) {
+ err = set_frequency_small_change(frequency);
+ } else {
+ err = set_frequency_large_change(frequency);
+ }
+ return err;
+}
+
+int SI570::set_frequency_small_change(double frequency) {
+ unsigned char reg135;
+ unsigned int whole;
+ unsigned char counter;
+ int i;
+ char reg[6];
+
+ rfreq = currentRfreq * frequency / currentFreq;
+
+ cmd[0] = 0x8;
+ _i2c.write(_address, cmd, 1);
+ _i2c.read(_address, buf, 1); // read register 0x8
+ reg[1] = buf[0];
+ reg[2] = 0;
+
+ // convert new RFREQ to the binary representation
+ // separate the integer part
+ whole = floor(rfreq);
+ // get the binary representation of the fractional part
+ frac_bits = floor((rfreq - whole) * POW_2_28);
+ // set reg 12 to 10 making frac_bits smaller by
+ // shifting off the last 8 bits everytime
+ for (counter=5; counter >=3; counter--) {
+ reg[counter] = frac_bits & 0xFF;
+ frac_bits = frac_bits >> 8;
+ }
+ // set the last 4 bits of the fractional portion in reg 9
+ reg[2] = SetBits(reg[2], 0xF0, (frac_bits & 0xF));
+ // set the integer portion of RFREQ across reg 8 and 9
+ reg[2] = SetBits(reg[2], 0x0F, (whole & 0xF) << 4);
+ reg[1] = SetBits(reg[1], 0xC0, (whole >> 4) & 0x3F);
+
+ // Load the new frequency
+ // get the current state of register 137
+ buf[0]=135;
+ _i2c.write(_address, buf, 1);
+ _i2c.read(_address, buf, 1);
+ reg135 = buf[0];
+
+ // set the Freeze M bit in that register
+ buf[0]=135;
+ buf[1]=reg135 | 0x20;
+ _i2c.write(_address, buf, 2);
+
+ // load the new values into the device at registers 8 to 12;
+ buf[0]=8;
+ for (i=1;i<6;i++) {
+ buf[i]=reg[i];
+ }
+ _i2c.write(_address, buf, 6);
+
+ // get the current state of register 135
+ buf[0]=135;
+ _i2c.write(_address, buf, 1);
+ _i2c.read(_address, buf, 1);
+ reg135 = buf[0];
+ // clear the M bit in that register
+ buf[0]=135;
+ buf[1]= reg135 & 0xDF;
+ _i2c.write(_address, buf, 2);
+
+ return 0;
+}
+
+
+
+int SI570::set_frequency_large_change(double frequency) {
+ const unsigned char HS_DIV[6] = {11, 9, 7, 6, 5, 4};
+ int i;
+// float ratio = 0;
+ unsigned char counter;
+ unsigned char reg137;
+ char buf[7];
+ char reg[6];
+ unsigned int divider_max;
+ unsigned int curr_div;
+ unsigned int whole;
+ unsigned char validCombo;
+ float curr_n1;
+ float n1_tmp;
+
+ // find dividers (get the max and min divider range for the HS_DIV and N1 combo)
+ divider_max = floor(FDCO_MAX / frequency); //floorf for SDCC
+ curr_div = ceil(FDCO_MIN / frequency); //ceilf for SDCC
+ validCombo = 0;
+ while (curr_div <= divider_max) {
+ //check all the HS_DIV values with the next curr_div
+ for (counter=0; counter<6; counter++) {
+ // get the next possible n1 value
+ hsdiv = HS_DIV[counter];
+ curr_n1 = (curr_div * 1.0) / (hsdiv * 1.0);
+ // determine if curr_n1 is an integer and an even number or one
+ // then it will be a valid divider option for the new frequency
+ n1_tmp = floor(curr_n1);
+ n1_tmp = curr_n1 - n1_tmp;
+ if (n1_tmp == 0.0) {
+ //then curr_n1 is an integer
+ n1 = (unsigned char) curr_n1;
+ if ( (n1 == 1) || ((n1 & 1) == 0) ) {
+ // then the calculated N1 is either 1 or an even number
+ validCombo = 1;
+ }
+ }
+ if (validCombo == 1) break;
+ }
+ if (validCombo == 1) break;
+ //increment curr_div to find the next divider
+ //since the current one was not valid
+ curr_div = curr_div + 1;
+ }
+
+ // if(validCombo == 0) at this point then there's an error
+ // in the calculation. Check if the provided frequencies
+ // are valid.
+ if (validCombo == 0)
+ return -1;
+
+ rfreq = (frequency * n1 * hsdiv) / fxtal_device; //using float
+ for (counter = 0; counter < 6; counter++) {
+ reg[counter] = 0; //clear registers
+ }
+
+ // new HS_DIV conversion
+ hsdiv = hsdiv - 4;
+ //reset this memory
+ reg[0] = 0;
+ //set the top 3 bits of reg 13
+ reg[0] = (hsdiv << 5);
+ // convert new N1 to the binary representation
+ if (n1 == 1) n1 = 0;
+ else if ((n1 & 1) == 0) n1 = n1 - 1; //if n1 is even, subtract one
+ // set reg 7 bits 0 to 4
+ reg[0] = SetBits(reg[0], 0xE0, n1 >> 2);
+ // set reg 8 bits 6 and 7
+ reg[1] = (n1 & 3) << 6;
+
+ // convert new RFREQ to the binary representation
+ // separate the integer part
+ whole = floor(rfreq);
+ // get the binary representation of the fractional part
+ frac_bits = floor((rfreq - whole) * POW_2_28);
+ // set reg 12 to 10 making frac_bits smaller by
+ // shifting off the last 8 bits everytime
+ for (counter=5; counter >=3; counter--) {
+ reg[counter] = frac_bits & 0xFF;
+ frac_bits = frac_bits >> 8;
+ }
+ // set the last 4 bits of the fractional portion in reg 9
+ reg[2] = SetBits(reg[2], 0xF0, (frac_bits & 0xF));
+ // set the integer portion of RFREQ across reg 8 and 9
+ reg[2] = SetBits(reg[2], 0x0F, (whole & 0xF) << 4);
+ reg[1] = SetBits(reg[1], 0xC0, (whole >> 4) & 0x3F);
+
+
+ // Load the new frequency
+ // get the current state of register 137
+ buf[0]=137;
+ _i2c.write(_address, buf, 1);
+ _i2c.read(_address, buf, 1);
+ reg137 = buf[0];
+
+ // set the Freeze DCO bit in that register
+ buf[0]=137;
+ buf[1]=reg137 | 0x10;
+ _i2c.write(_address, buf, 2);
+
+ // load the new values into the device at registers 7 to 12;
+ buf[0]=7;
+ for (i=1;i<7;i++) {
+ buf[i]=reg[i-1];
+ }
+ _i2c.write(_address, buf, 7);
+
+
+ // get the current state of register 137
+ buf[0]=137;
+ _i2c.write(_address, buf, 1);
+ _i2c.read(_address, buf, 1);
+ reg137 = buf[0];
+ // clear the FZ_DCO bit in that register
+ buf[0]=137;
+ buf[1]= reg137 & 0xEF;
+ _i2c.write(_address, buf, 2);
+
+
+ // set the NewFreq bit, bit will clear itself once the device is ready
+ buf[0]=135;
+ buf[1]= 0x40;
+ _i2c.write(_address, buf, 2);
+
+ currentFreq = frequency;
+ currentRfreq = rfreq;
+ return 0;
+}
+
+
+unsigned char SI570::SetBits(unsigned char original, unsigned char reset_mask, unsigned char new_val) {
+ return (( original & reset_mask ) | new_val );
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/SI570.h Tue Nov 09 20:56:52 2010 +0000
@@ -0,0 +1,150 @@
+/* mbed SI570 Library, for driving the SI570 programable VCXO
+ * Copyright (c) 2010, Gerrit Polder, PA3BYA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MBED_SI570_H
+#define MBED_SI570_H
+
+#include "mbed.h"
+
+//these must be floating point number especially 2^28 so that
+//there is enough memory to use them in the calculation
+#define POW_2_16 65536.0
+#define POW_2_24 16777216.0
+#define POW_2_28 268435456.0
+#define FOUT_START_UP 56.320 //MHz
+#define PPM 3500 // +/- max ppm from center frequency
+#define FDCO_MAX 5670.0 //MHz
+#define FDCO_MIN 4850.0 //MHz
+
+
+/** Interface to the popular SI570 VCXO */
+class SI570 {
+public:
+ /** Create an instance of the SI570 connected to specified I2C pins, with the specified address.
+ *
+ * Example:
+ * @code
+ * #include "mbed.h"
+ * #include "TextLCD.h"
+ * #include "SI570.h"
+ * #include "QEI.h"
+ *
+ * TextLCD lcd(p11, p12, p15, p16, p29, p30); // rs, e, d0-d3
+ * SI570 si570(p9, p10, 0xAA);
+ * QEI wheel (p5, p6, NC, 360);
+ *
+ * int main() {
+ * int wp,swp=0;
+ * float startfreq=7.0;
+ * float freq;
+ *
+ * while (1) {
+ * wp = wheel.getPulses();
+ * freq=startfreq+wp*0.00001;
+ * if (swp != wp) {
+ * si570.set_frequency(freq);
+ * swp = wp;
+ * }
+ * lcd.locate(0,0);
+ * lcd.printf("%f MHz", si570.get_frequency());
+ * }
+ * }
+ * @endcode
+ *
+ * @param sda The I2C data pin
+ * @param scl The I2C clock pin
+ * @param address The I2C address for this SI570
+ */
+ SI570(PinName sda, PinName scl, int address);
+
+ /** Resets the SI570.
+ *
+ * Resets and reads the startup configuration from the Si570
+ */
+ void si570reset(void);
+
+ /** Read the current frequency.
+ *
+ * get the SI570 registers an calculate the current frequency
+ *
+ * @returns the current frequency
+ */
+ double get_frequency(void);
+
+ /** Read the current rfreq value.
+ *
+ * get the SI570 registers an calculate the current rfreq
+ *
+ * @returns the current rfreq
+ */
+ double get_rfreq(void);
+
+ /** Read the current n1.
+ *
+ * get the SI570 registers an calculate the current n1
+ *
+ * @returns the current n1
+ */
+ int get_n1(void);
+
+ /** Read the current hsdiv.
+ *
+ * get the SI570 registers an calculate the current hsdiv
+ *
+ * @returns the current hsdiv
+ */
+ int get_hsdiv(void);
+
+ /** Set a new frequency.
+ *
+ * Set the SI570 registers to output frequency
+ * When the new frequency is within the 3500 PPM range of the center frequency, hsdiv and n1 needs not to be reprogrammed, resulting in a glitch free transition.
+ * For changes larger than 3500 PPM, the process of freezing and unfreezing the DCO will cause the output clock to momentarily stop and start at any arbitrary point during a clock cycle. This process can take up to 10 ms.
+ *
+ * @param frequency the frequency to set.
+ * @returns the current frequency
+ */
+ int set_frequency(double frequency);
+
+
+private:
+ I2C _i2c;
+ int _address;
+ char cmd[2];
+ char buf[6];
+ unsigned char n1;
+ unsigned char hsdiv;
+ unsigned long frac_bits;
+ double rfreq;
+ double fxtal_device;
+ double currentFreq;
+ double currentRfreq;
+
+ void get_registers(void);
+ int set_frequency_small_change(double currentFrequency);
+ int set_frequency_large_change(double currentFrequency);
+
+ unsigned char SetBits(unsigned char original, unsigned char reset_mask, unsigned char new_val);
+};
+
+
+#endif
\ No newline at end of file
SI570