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.
Fork of SI570 by
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 Thu Jul 14 2022 12:41:47 by
1.7.2
