Library to control Silicon Labs SI570 10 MHZ TO 1.4 GHZ I2C PROGRAMMABLE XO/VCXO.

Dependencies:   mbed

Fork of SI570 by Gerrit Polder

Revision:
1:1556bcaaf759
Parent:
0:dae1bf95c49e
--- a/SI570.cpp	Tue Nov 09 20:56:52 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,310 +0,0 @@
-/* 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 );
-}
-