Library to control Silicon Labs SI570 10 MHZ TO 1.4 GHZ I2C PROGRAMMABLE XO/VCXO.
Embed:
(wiki syntax)
Show/hide line numbers
SI570.cpp
00001 /* mbed SI570 Library, for driving the SI570 programable VCXO 00002 * Copyright (c) 2010, Gerrit Polder, PA3BYA 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy 00005 * of this software and associated documentation files (the "Software"), to deal 00006 * in the Software without restriction, including without limitation the rights 00007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 * copies of the Software, and to permit persons to whom the Software is 00009 * furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included in 00012 * all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00020 * THE SOFTWARE. 00021 */ 00022 00023 #include "SI570.h" 00024 #include "mbed.h" 00025 00026 SI570::SI570(PinName sda, PinName scl, int address) 00027 : _i2c(sda, scl) { 00028 _address = address; 00029 si570reset(); 00030 } 00031 00032 00033 00034 void SI570::si570reset(void) { 00035 _i2c.frequency(100000); 00036 00037 cmd[0] = 135; // reset 00038 cmd[1] = 0x01; // 00039 _i2c.write(_address, cmd, 2); // Send command string 00040 00041 get_registers(); 00042 fxtal_device = (FOUT_START_UP * n1 * hsdiv) / rfreq; //MHz 00043 00044 currentFreq = FOUT_START_UP; 00045 } 00046 00047 void SI570::get_registers() { 00048 00049 // Set pointer to location 7 (first echo) 00050 cmd[0] = 0x7; 00051 _i2c.write(_address, cmd, 1); 00052 00053 _i2c.read(_address, buf, 6); // read the six-byte result 00054 00055 // HS_DIV conversion 00056 hsdiv = ((buf[0] & 0xE0) >> 5) + 4; // get reg 7 bits 5, 6, 7 00057 // hsdiv's value could be verified here to ensure that it is one 00058 // of the valid HS_DIV values from the datasheet. 00059 // n1 conversion 00060 n1 = (( buf[0] & 0x1F ) << 2 ) + // get reg 7 bits 0 to 4 00061 (( buf[1] & 0xC0 ) >> 6 ); // add with reg 8 bits 7 and 8 00062 if (n1 == 0) { 00063 n1 = 1; 00064 } else if (n1 & 1 != 0) { 00065 // add one to an odd number 00066 n1 = n1 + 1; 00067 } 00068 00069 frac_bits = (( buf[2] & 0xF ) * POW_2_24 ); 00070 frac_bits = frac_bits + (buf[3] * POW_2_16); 00071 frac_bits = frac_bits + (buf[4] * 256); 00072 frac_bits = frac_bits + buf[5]; 00073 00074 rfreq = frac_bits; 00075 rfreq = rfreq / POW_2_28; 00076 rfreq = rfreq + ( (( buf[1] & 0x3F ) << 4 ) + (( buf[2] & 0xF0 ) >> 4 ) ); 00077 } 00078 00079 00080 double SI570::get_frequency(void) { 00081 get_registers(); 00082 return (rfreq*fxtal_device)/(hsdiv*n1); 00083 } 00084 00085 double SI570::get_rfreq(void) { 00086 get_registers(); 00087 return rfreq; 00088 } 00089 00090 int SI570::get_n1(void) { 00091 get_registers(); 00092 return n1; 00093 } 00094 00095 int SI570::get_hsdiv(void) { 00096 get_registers(); 00097 return hsdiv; 00098 } 00099 00100 int SI570::set_frequency(double frequency) { 00101 int err; 00102 float diff = 1000000 * (abs(frequency - currentFreq) / currentFreq); 00103 if (diff < PPM) { 00104 err = set_frequency_small_change(frequency); 00105 } else { 00106 err = set_frequency_large_change(frequency); 00107 } 00108 return err; 00109 } 00110 00111 int SI570::set_frequency_small_change(double frequency) { 00112 unsigned char reg135; 00113 unsigned int whole; 00114 unsigned char counter; 00115 int i; 00116 char reg[6]; 00117 00118 rfreq = currentRfreq * frequency / currentFreq; 00119 00120 cmd[0] = 0x8; 00121 _i2c.write(_address, cmd, 1); 00122 _i2c.read(_address, buf, 1); // read register 0x8 00123 reg[1] = buf[0]; 00124 reg[2] = 0; 00125 00126 // convert new RFREQ to the binary representation 00127 // separate the integer part 00128 whole = floor(rfreq); 00129 // get the binary representation of the fractional part 00130 frac_bits = floor((rfreq - whole) * POW_2_28); 00131 // set reg 12 to 10 making frac_bits smaller by 00132 // shifting off the last 8 bits everytime 00133 for (counter=5; counter >=3; counter--) { 00134 reg[counter] = frac_bits & 0xFF; 00135 frac_bits = frac_bits >> 8; 00136 } 00137 // set the last 4 bits of the fractional portion in reg 9 00138 reg[2] = SetBits(reg[2], 0xF0, (frac_bits & 0xF)); 00139 // set the integer portion of RFREQ across reg 8 and 9 00140 reg[2] = SetBits(reg[2], 0x0F, (whole & 0xF) << 4); 00141 reg[1] = SetBits(reg[1], 0xC0, (whole >> 4) & 0x3F); 00142 00143 // Load the new frequency 00144 // get the current state of register 137 00145 buf[0]=135; 00146 _i2c.write(_address, buf, 1); 00147 _i2c.read(_address, buf, 1); 00148 reg135 = buf[0]; 00149 00150 // set the Freeze M bit in that register 00151 buf[0]=135; 00152 buf[1]=reg135 | 0x20; 00153 _i2c.write(_address, buf, 2); 00154 00155 // load the new values into the device at registers 8 to 12; 00156 buf[0]=8; 00157 for (i=1;i<6;i++) { 00158 buf[i]=reg[i]; 00159 } 00160 _i2c.write(_address, buf, 6); 00161 00162 // get the current state of register 135 00163 buf[0]=135; 00164 _i2c.write(_address, buf, 1); 00165 _i2c.read(_address, buf, 1); 00166 reg135 = buf[0]; 00167 // clear the M bit in that register 00168 buf[0]=135; 00169 buf[1]= reg135 & 0xDF; 00170 _i2c.write(_address, buf, 2); 00171 00172 return 0; 00173 } 00174 00175 00176 00177 int SI570::set_frequency_large_change(double frequency) { 00178 const unsigned char HS_DIV[6] = {11, 9, 7, 6, 5, 4}; 00179 int i; 00180 // float ratio = 0; 00181 unsigned char counter; 00182 unsigned char reg137; 00183 char buf[7]; 00184 char reg[6]; 00185 unsigned int divider_max; 00186 unsigned int curr_div; 00187 unsigned int whole; 00188 unsigned char validCombo; 00189 float curr_n1; 00190 float n1_tmp; 00191 00192 // find dividers (get the max and min divider range for the HS_DIV and N1 combo) 00193 divider_max = floor(FDCO_MAX / frequency); //floorf for SDCC 00194 curr_div = ceil(FDCO_MIN / frequency); //ceilf for SDCC 00195 validCombo = 0; 00196 while (curr_div <= divider_max) { 00197 //check all the HS_DIV values with the next curr_div 00198 for (counter=0; counter<6; counter++) { 00199 // get the next possible n1 value 00200 hsdiv = HS_DIV[counter]; 00201 curr_n1 = (curr_div * 1.0) / (hsdiv * 1.0); 00202 // determine if curr_n1 is an integer and an even number or one 00203 // then it will be a valid divider option for the new frequency 00204 n1_tmp = floor(curr_n1); 00205 n1_tmp = curr_n1 - n1_tmp; 00206 if (n1_tmp == 0.0) { 00207 //then curr_n1 is an integer 00208 n1 = (unsigned char) curr_n1; 00209 if ( (n1 == 1) || ((n1 & 1) == 0) ) { 00210 // then the calculated N1 is either 1 or an even number 00211 validCombo = 1; 00212 } 00213 } 00214 if (validCombo == 1) break; 00215 } 00216 if (validCombo == 1) break; 00217 //increment curr_div to find the next divider 00218 //since the current one was not valid 00219 curr_div = curr_div + 1; 00220 } 00221 00222 // if(validCombo == 0) at this point then there's an error 00223 // in the calculation. Check if the provided frequencies 00224 // are valid. 00225 if (validCombo == 0) 00226 return -1; 00227 00228 rfreq = (frequency * n1 * hsdiv) / fxtal_device; //using float 00229 for (counter = 0; counter < 6; counter++) { 00230 reg[counter] = 0; //clear registers 00231 } 00232 00233 // new HS_DIV conversion 00234 hsdiv = hsdiv - 4; 00235 //reset this memory 00236 reg[0] = 0; 00237 //set the top 3 bits of reg 13 00238 reg[0] = (hsdiv << 5); 00239 // convert new N1 to the binary representation 00240 if (n1 == 1) n1 = 0; 00241 else if ((n1 & 1) == 0) n1 = n1 - 1; //if n1 is even, subtract one 00242 // set reg 7 bits 0 to 4 00243 reg[0] = SetBits(reg[0], 0xE0, n1 >> 2); 00244 // set reg 8 bits 6 and 7 00245 reg[1] = (n1 & 3) << 6; 00246 00247 // convert new RFREQ to the binary representation 00248 // separate the integer part 00249 whole = floor(rfreq); 00250 // get the binary representation of the fractional part 00251 frac_bits = floor((rfreq - whole) * POW_2_28); 00252 // set reg 12 to 10 making frac_bits smaller by 00253 // shifting off the last 8 bits everytime 00254 for (counter=5; counter >=3; counter--) { 00255 reg[counter] = frac_bits & 0xFF; 00256 frac_bits = frac_bits >> 8; 00257 } 00258 // set the last 4 bits of the fractional portion in reg 9 00259 reg[2] = SetBits(reg[2], 0xF0, (frac_bits & 0xF)); 00260 // set the integer portion of RFREQ across reg 8 and 9 00261 reg[2] = SetBits(reg[2], 0x0F, (whole & 0xF) << 4); 00262 reg[1] = SetBits(reg[1], 0xC0, (whole >> 4) & 0x3F); 00263 00264 00265 // Load the new frequency 00266 // get the current state of register 137 00267 buf[0]=137; 00268 _i2c.write(_address, buf, 1); 00269 _i2c.read(_address, buf, 1); 00270 reg137 = buf[0]; 00271 00272 // set the Freeze DCO bit in that register 00273 buf[0]=137; 00274 buf[1]=reg137 | 0x10; 00275 _i2c.write(_address, buf, 2); 00276 00277 // load the new values into the device at registers 7 to 12; 00278 buf[0]=7; 00279 for (i=1;i<7;i++) { 00280 buf[i]=reg[i-1]; 00281 } 00282 _i2c.write(_address, buf, 7); 00283 00284 00285 // get the current state of register 137 00286 buf[0]=137; 00287 _i2c.write(_address, buf, 1); 00288 _i2c.read(_address, buf, 1); 00289 reg137 = buf[0]; 00290 // clear the FZ_DCO bit in that register 00291 buf[0]=137; 00292 buf[1]= reg137 & 0xEF; 00293 _i2c.write(_address, buf, 2); 00294 00295 00296 // set the NewFreq bit, bit will clear itself once the device is ready 00297 buf[0]=135; 00298 buf[1]= 0x40; 00299 _i2c.write(_address, buf, 2); 00300 00301 currentFreq = frequency; 00302 currentRfreq = rfreq; 00303 return 0; 00304 } 00305 00306 00307 unsigned char SI570::SetBits(unsigned char original, unsigned char reset_mask, unsigned char new_val) { 00308 return (( original & reset_mask ) | new_val ); 00309 } 00310
Generated on Tue Jul 12 2022 19:03:22 by 1.7.2