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.
Dependents: clockGenerator Check_Si5351A_Clock_generator t2d Thing2Do ... more
si5351a.cpp
00001 /* 00002 * mbed Library / Silicon Laboratories Inc. Si5351A-B-GT 00003 * I2C-PROGRAMMABLE ANY-FREQUENCY CMOS CLOCK GENERATOR 00004 * https://www.silabs.com/products/ 00005 * timing/clock-generator/si535x/pages/Si5351A-B-GM.aspx 00006 * 00007 * Checked on Nucleo-F411RE & F401RE mbed board 00008 * 00009 * Original & Reference program: 00010 * 1) 00011 * https://github.com/adafruit/Adafruit_Si5351_Library 00012 * see original source (bottom part of si5351a.cpp file) 00013 * Software License Agreement (BSD License) 00014 * Copyright (c) 2014, Adafruit Industries All rights reserved. 00015 * 2) 00016 * https://gist.github.com/edy555/f1ee7ef44fe4f5c6f7618ac4cbbe66fb 00017 * made by TT@Hokkaido-san (edy555) 00018 * http://ttrftech.tumblr.com/ 00019 * http://ttrftech.tumblr.com/post/150247113216/ 00020 * si5351a-configuration-how-to-and-signal-quality 00021 * 00022 * Modified by Kenji Arai / JH1PJL 00023 * http://www.page.sannet.ne.jp/kenjia/index.html 00024 * http://mbed.org/users/kenjiArai/ 00025 * 00026 * Started: December 24th, 2016 00027 * Revised: August 23rd, 2017 00028 * 00029 */ 00030 00031 #include "mbed.h" 00032 #include "si5351a.h" 00033 00034 #if 0 // Debug mode = 1 00035 #define DEBUG 00036 #endif 00037 00038 #if defined(DEBUG) 00039 #define DBG(...) printf(__VA_ARGS__) 00040 #else 00041 #define DBG(...) {;} 00042 #endif 00043 00044 #define PLL_N 32 00045 00046 SI5351A::SI5351A (PinName p_sda, PinName p_scl, 00047 uint32_t base_clk_freq, 00048 uint8_t xtal_cap, 00049 uint8_t drive_current 00050 ) 00051 : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p) 00052 { 00053 base_freq = base_clk_freq; 00054 x_cap = xtal_cap; 00055 drv_current = drive_current; 00056 si5351_init(); 00057 } 00058 00059 SI5351A::SI5351A (I2C& p_i2c, 00060 uint32_t base_clk_freq, 00061 uint8_t xtal_cap, 00062 uint8_t drive_current 00063 ) 00064 : _i2c(p_i2c) 00065 { 00066 base_freq = base_clk_freq; 00067 x_cap = xtal_cap; 00068 drv_current = drive_current; 00069 si5351_init(); 00070 } 00071 00072 /* 00073 * 1~110MHz fixed PLL (XTAL * PLL_N)MHz, fractional divider 00074 * 110~150MHz fractional PLL 600-900MHz, fixed divider 6 00075 * 150~200MHz fractional PLL 600-900MHz, fixed divider 4 00076 */ 00077 uint32_t SI5351A::set_frequency(uint8_t channel, uint32_t freq) 00078 { 00079 uint8_t pll; 00080 double f; 00081 uint8_t state; 00082 if (channel == SI5351_CLK0){ 00083 pll = SI5351_PLL_A; 00084 } else { // SI5351_CLK1 & SI5351_CLK2 00085 pll = SI5351_PLL_B; 00086 } 00087 si5351_disable_output(); 00088 if (freq <= FREQ_110MHZ){ 00089 if((channel == SI5351_CLK1) && (clk2_state == CLK_OUT_FIXEDDIV)){ 00090 DBG("DBG: Error CLK2 uses as over 110MHz!!\r\n"); 00091 return 0; 00092 } else if((channel == SI5351_CLK2) && (clk1_state == CLK_OUT_FIXEDDIV)){ 00093 DBG("DBG: Error CLK1 uses as over 110MHz!!\r\n"); 00094 return 0; 00095 } 00096 DBG("DBG: Passed condition\r\n"); 00097 if (freq > FREQ_450KHZ){ // over 450KHz to 110MHz 00098 si5351_set_PLL_input_condition(FREQ_900MHZ); 00099 si5351_setupPLL(pll, pll_n, 0, 1); 00100 f = si5351_set_frequency_fixedpll(channel, pll, pll_freq, freq, 0); 00101 } else if (freq > FREQ_75KHZ){ 00102 si5351_set_PLL_input_condition(FREQ_600MHZ); 00103 si5351_setupPLL(pll, pll_n, 0, 1); 00104 f = si5351_set_frequency_fixedpll( 00105 channel, pll, pll_freq, freq * 8, SI5351_R_DIV_8); 00106 f /= 8.0f; 00107 } else if (freq > FREQ_20KHZ){ 00108 si5351_set_PLL_input_condition(FREQ_600MHZ); 00109 si5351_setupPLL(pll, pll_n, 0, 1); 00110 f = si5351_set_frequency_fixedpll( 00111 channel, pll, pll_freq, freq * 32, SI5351_R_DIV_32); 00112 f /= 32.0f; 00113 } else { 00114 si5351_set_PLL_input_condition(FREQ_600MHZ); 00115 si5351_setupPLL(pll, pll_n, 0, 1); 00116 f = si5351_set_frequency_fixedpll( 00117 channel, pll, pll_freq, freq * 128, SI5351_R_DIV_128); 00118 #if defined(RANGE_EXTENDED) 00119 // CAUTION !!!!!! 00120 if (f == 0){ // This part is outside of specification!! 00121 DBG("DBG: Out of range but try again!\r\n"); 00122 pll_n = 15; // around 375MHz 00123 pll_freq = base_freq * pll_n; 00124 pll_freq = (uint32_t)((double)pll_freq / compensation); 00125 si5351_setupPLL(pll, pll_n, 0, 1); 00126 f = si5351_set_frequency_fixedpll( 00127 channel, pll, pll_freq, freq * 128, SI5351_R_DIV_128); 00128 } 00129 #endif 00130 f /= 128.0f; 00131 } 00132 state = CLK_OUT_FIXEDPLL; 00133 } else { 00134 DBG("DBG: Set over 110MHz clock\r\n"); 00135 if((channel == SI5351_CLK1) && (clk2_state == CLK_OUT_FIXEDPLL)){ 00136 DBG("DBG: Error CLK2 uses as under 110MHz!!\r\n"); 00137 return 0; 00138 } else if((channel == SI5351_CLK2) && (clk1_state == CLK_OUT_FIXEDPLL)){ 00139 DBG("DBG: Error CLK1 uses as under 110MHz!!\r\n"); 00140 return 0; 00141 } 00142 DBG("DBG: Passed condition\r\n"); 00143 if (freq < FREQ_150MHZ) { 00144 DBG("DBG: Set 110MHz to 150MHz clock\r\n"); 00145 f = si5351_set_frequency_fixeddiv(channel, pll, freq, 6); 00146 } else { 00147 #if defined(RANGE_EXTENDED) 00148 DBG("DBG: Set over 150MHz clock (RANGE_EXTENDED)\r\n"); 00149 f = si5351_set_frequency_fixeddiv(channel, pll, freq, 4); 00150 #else 00151 DBG("DBG: Set over 150MHz clock\r\n"); 00152 if (freq > FREQ_200MHZ) { 00153 DBG("DBG: Over 200MHz\r\n"); 00154 f = 0; 00155 } else { 00156 f = si5351_set_frequency_fixeddiv(channel, pll, freq, 4); 00157 } 00158 #endif 00159 } 00160 state = CLK_OUT_FIXEDDIV; 00161 } 00162 si5351_enable_output(); 00163 if (channel == SI5351_CLK0){ 00164 clk0_state = state; 00165 clk0_freq = f; 00166 } else if (channel == SI5351_CLK1){ 00167 clk1_state = state; 00168 clk1_freq = f; 00169 } else { 00170 clk2_state = state; 00171 clk2_freq = f; 00172 } 00173 DBG("DBG: freq./ Target=%u,Set=%0.1f,diff=%.0f\r\n", 00174 freq, f, (double)freq - f); 00175 return (uint32_t)f; 00176 } 00177 00178 uint32_t SI5351A::shift_freq(uint8_t channel, int32_t diff) 00179 { 00180 double f; 00181 uint32_t f_err; 00182 // Check current status 00183 if (channel == SI5351_CLK0){ 00184 f = clk0_freq; 00185 f_err = (uint32_t)f; 00186 if ((clk0_state == CLK_OUT_NOT_USED) 00187 || (clk0_state == CLK_OUT_FIXEDDIV)){ 00188 DBG("DBG: error over 110MHz\r\n"); 00189 return f_err; // return current frequency 00190 } 00191 } else if (channel == SI5351_CLK1){ 00192 f = clk1_freq; 00193 f_err = (uint32_t)f; 00194 if ((clk1_state == CLK_OUT_NOT_USED) 00195 || (clk1_state == CLK_OUT_FIXEDDIV)){ 00196 DBG("DBG: error over 110MHz\r\n"); 00197 return f_err; // return current frequency 00198 } 00199 } else if (channel == SI5351_CLK2){ 00200 f = clk2_freq; 00201 f_err = (uint32_t)f; 00202 if ((clk2_state == CLK_OUT_NOT_USED) 00203 || (clk2_state == CLK_OUT_FIXEDDIV)){ 00204 DBG("DBG: error over 110MHz\r\n"); 00205 return f_err; // return current frequency 00206 } 00207 } else { 00208 return 0; 00209 } 00210 // set new frequency 00211 double f_tatget = f + (double)diff; 00212 uint32_t freq = (uint32_t)f_tatget; 00213 DBG("DBG: Target F=%u\r\n", freq); 00214 // only range between 1MHz to 110MHz 00215 if ((freq > FREQ_110MHZ) || (freq < FREQ_450KHZ)){// between 450KHz-110MHz 00216 DBG("DBG: Out of range\r\n"); 00217 return f_err; // return current frequency 00218 } 00219 uint32_t div = (floor)((double)pll_freq / (double)freq); 00220 uint32_t num = pll_freq - freq * div; 00221 uint32_t denom = freq; 00222 uint32_t k = gcd(num, denom); 00223 num /= k; 00224 denom /= k; 00225 while (denom >= (1<<20)) { 00226 num >>= 1; 00227 denom >>= 1; 00228 } 00229 if (denom == 0){ // Avoid divide by zero 00230 DBG("DBG: error demon=0\r\n"); 00231 return f_err; // return current frequency 00232 } 00233 if (num >=0x100000){ // 20-bit limit 00234 DBG("DBG: error num over 20bit\r\n"); 00235 return f_err; // return current frequency 00236 } 00237 if (denom >=0x100000){ // 20-bit limit 00238 DBG("DBG: error denom over 20bit\r\n"); 00239 return f_err; // return current frequency 00240 } 00241 uint32_t P1, P2, P3; 00242 double multisynth_double; 00243 const uint8_t msreg_base[] = { 00244 SI5351_REG_42_MULTISYNTH0, 00245 SI5351_REG_50_MULTISYNTH1, 00246 SI5351_REG_58_MULTISYNTH2, 00247 }; 00248 uint8_t baseaddr = msreg_base[channel]; 00249 // Fractional mode 00250 P1 = (uint32_t)(128 * div + floor(128 * ((float)num/(float)denom)) - 512); 00251 P2 = (uint32_t)(128 * num - denom * floor(128 * ((float)num/(float)denom))); 00252 P3 = denom; 00253 multisynth_double = div + (double)num /(double)denom; 00254 // a + b/c between 6..1800 00255 if ((multisynth_double < 6.0f) || (multisynth_double > 1800.0f)){ 00256 DBG("DBG: error multisynth less 6 or over 1800\r\n"); 00257 return f_err; // return current frequency 00258 } 00259 DBG("DBG: CLK%u: PLL=%u,div=%u,num=%u,denom=%u\r\n", 00260 channel, pll_freq, div, num, denom); 00261 // Set the MSx config registers 00262 si5351_write(baseaddr, (P3 & 0x0000ff00) >> 8); 00263 si5351_write(baseaddr+1, (P3 & 0x000000ff)); 00264 si5351_write(baseaddr+2, (P1 & 0x00030000) >> 16); 00265 si5351_write(baseaddr+3, (P1 & 0x0000ff00) >> 8); 00266 si5351_write(baseaddr+4, (P1 & 0x000000ff)); 00267 si5351_write(baseaddr+5, 00268 ((P3 & 0x000f0000) >> 12) | ((P2 & 0x000f0000) >> 16)); 00269 si5351_write(baseaddr+6, (P2 & 0x0000ff00) >> 8); 00270 si5351_write(baseaddr+7, (P2 & 0x000000ff)); 00271 f = (double)pll_freq / multisynth_double; 00272 if (channel == SI5351_CLK0){ 00273 clk0_freq = f; 00274 } else if (channel == SI5351_CLK1){ 00275 clk1_freq = f; 00276 } else { // SI5351_CLK2 00277 clk2_freq = f; 00278 } 00279 return (uint32_t)f; 00280 } 00281 00282 uint32_t SI5351A::read_freq(uint8_t channel) 00283 { 00284 if (channel == SI5351_CLK0){ 00285 return (uint32_t)clk0_freq; 00286 } else if (channel == SI5351_CLK1){ 00287 return (uint32_t)clk1_freq; 00288 } else { // SI5351_CLK2 00289 return (uint32_t)clk2_freq; 00290 } 00291 } 00292 00293 void SI5351A::f_compensation(uint32_t target_f, uint32_t measured_f) 00294 { 00295 double new_comp_data; 00296 00297 if (compensation == 1.0f){ 00298 compensation = (double)target_f / (double)measured_f; 00299 pll_freq = (uint32_t)((double)pll_freq / compensation); 00300 } else { 00301 new_comp_data = (double)target_f / (double)measured_f; 00302 pll_freq = (uint32_t)((double)pll_freq / new_comp_data); 00303 compensation *= new_comp_data; 00304 } 00305 } 00306 00307 static const uint8_t reg_table[] = { 00308 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 00309 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 00310 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 00311 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 00312 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 00313 165, 166, 167, 168, 169, 170 00314 }; 00315 00316 void SI5351A::all_reset(void) 00317 { 00318 plla_freq = 0; 00319 pllb_freq = 0; 00320 clk0_freq = 0; 00321 clk1_freq = 0; 00322 clk2_freq = 0; 00323 clk0_state = 0; 00324 clk1_state = 0; 00325 clk2_state = 0; 00326 /* Disable all outputs setting CLKx_DIS high */ 00327 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff); 00328 for (uint16_t i = 0; i < sizeof(reg_table); i++){ 00329 si5351_write(reg_table[i], 0); 00330 } 00331 /* Apply soft reset */ 00332 si5351_write(SI5351_REG_177_PLL_RESET, 0xac); 00333 } 00334 00335 ////////////// Configration for Initialization ///////////////////////////////// 00336 // length, register addr, data, ... 00337 const uint8_t si5351_configs[] = { 00338 // 0xff = all outputs are disabled. 00339 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff, 00340 // CLK0,CLK1(REG_17),CLK2(REG_18) -> Power down mode 00341 4, SI5351_REG_16_CLK0_CONTROL, 00342 SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, 00343 // Dummy data for PLL 00344 9, SI5351_REG_26_PLL_A, /*P3*/0, 0, /*P1*/0, 0, 0, /*P3/P2*/0, 0, 0, 00345 // RESET PLL (Both PLLA & PLLB) 00346 2, SI5351_REG_177_PLL_RESET, (SI5351_PLL_RESET_A | SI5351_PLL_RESET_B), 00347 // Dummy data for MULTISYNTH 00348 9, SI5351_REG_58_MULTISYNTH2, /*P3*/0, 0, /*P1*/0, 0, 0, /*P2|P3*/0, 0, 0, 00349 // 0 = enable / CLK0,1,2 (bit 0,1,2 = 0) 00350 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xf8, 00351 0 // sentinel 00352 }; 00353 00354 void SI5351A::si5351_init(void) 00355 { 00356 addr = SI5351_I2C_ADDR; 00357 clk0_freq = 0; 00358 clk1_freq = 0; 00359 clk2_freq = 0; 00360 clk0_state = CLK_OUT_NOT_USED; 00361 clk1_state = CLK_OUT_NOT_USED; 00362 clk2_state = CLK_OUT_NOT_USED; 00363 compensation = 1.0f; 00364 si5351_set_PLL_input_condition(FREQ_900MHZ); 00365 si5351_reset_pll(); 00366 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff); 00367 // Total load capacitance less than or equal to 12 pF (See AN551) 00368 si5351_write(SI5351_REG_183_CRYSTAL_LOAD, x_cap); 00369 const uint8_t *p = si5351_configs; 00370 while (*p) { 00371 uint8_t len = *p++; 00372 si5351_bulk_write(p, len); 00373 p += len; 00374 } 00375 // CONTROL for CLK0,1,2 00376 uint8_t dt = (drv_current | \ 00377 SI5351_CLK_INPUT_MULTISYNTH_N | \ 00378 SI5351_CLK_INTEGER_MODE); 00379 si5351_write(SI5351_REG_16_CLK0_CONTROL, dt); 00380 si5351_write(SI5351_REG_17_CLK1_CONTROL, dt); 00381 si5351_write(SI5351_REG_18_CLK2_CONTROL, dt); 00382 si5351_disable_all_output(); // Disable all output 00383 } 00384 00385 void SI5351A::si5351_disable_output(void) 00386 { 00387 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff); 00388 } 00389 00390 void SI5351A::si5351_disable_all_output(void) 00391 { 00392 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff); 00393 si5351_write(SI5351_REG_16_CLK0_CONTROL, 0x80); 00394 si5351_write(SI5351_REG_17_CLK1_CONTROL, 0x80); 00395 si5351_write(SI5351_REG_18_CLK2_CONTROL, 0x80); 00396 } 00397 00398 void SI5351A::si5351_enable_output(void) 00399 { 00400 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xf8); 00401 } 00402 00403 void SI5351A::si5351_reset_pll(void) 00404 { 00405 si5351_write(SI5351_REG_177_PLL_RESET, 0xa0); 00406 } 00407 00408 void SI5351A::si5351_set_PLL_input_condition(uint32_t freq) 00409 { 00410 uint8_t n; 00411 uint32_t dt; 00412 00413 n = (uint8_t)(freq / base_freq); 00414 dt = base_freq * n; 00415 while (true){ 00416 if (dt > FREQ_900MHZ){ --n;} 00417 if (dt < FREQ_600MHZ){ ++n;} 00418 dt = base_freq * n; 00419 if ((dt <= FREQ_900MHZ) && (dt >= FREQ_600MHZ)){ break;} 00420 } 00421 pll_n = n; 00422 pll_freq = dt; 00423 pll_freq = (uint32_t)((double)pll_freq / compensation); 00424 DBG("DBG: Change PLL_N data / pll_n=%u, pll_freq=%u\r\n", pll_n, pll_freq); 00425 } 00426 00427 /******************************************************************************/ 00428 /*! 00429 @brief Sets the multiplier for the specified PLL 00430 00431 @param pll The PLL to configure, which must be one of the following: 00432 - SI5351_PLL_A 00433 - SI5351_PLL_B 00434 @param mult The PLL integer multiplier (must be between 15 and 90) 00435 @param num The 20-bit numerator for fractional output (0..1,048,575). 00436 Set this to '0' for integer output. 00437 @param denom The 20-bit denominator for fractional output (1..1,048,575). 00438 Set this to '1' or higher to avoid divider by zero errors. 00439 @section PLL Configuration 00440 fVCO is the PLL output, and must be between 600..900MHz, where: 00441 fVCO = fXTAL * (a+(b/c)) 00442 fXTAL = the crystal input frequency 00443 a = an integer between 15 and 90 00444 b = the fractional numerator (0..1,048,575) 00445 c = the fractional denominator (1..1,048,575) 00446 NOTE: Try to use integers whenever possible to avoid clock jitter 00447 (only use the a part, setting b to '0' and c to '1'). 00448 See: http://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf 00449 */ 00450 /******************************************************************************/ 00451 void SI5351A::si5351_setupPLL( 00452 uint8_t pll, 00453 uint8_t mult, 00454 uint32_t num, 00455 uint32_t denom) 00456 { 00457 uint32_t P1; /* PLL config register P1 */ 00458 uint32_t P2; /* PLL config register P2 */ 00459 uint32_t P3; /* PLL config register P3 */ 00460 00461 /* Basic validation */ 00462 DBG("DBG: Enter si5351_setupPLL\r\n"); 00463 DBG("DBG: pll=%u, mult=%u, num=%u, denom=%u\r\n", pll, mult, num, denom); 00464 bool err = false; 00465 if (mult <= 14){ /* mult = 15..90 */ 00466 DBG("DBG: mult lower value error\r\n"); 00467 err = true; 00468 } 00469 if (mult >= 91){ 00470 DBG("DBG: mult bigger value error\r\n"); 00471 err = true; 00472 } 00473 if (denom == 0){ /* Avoid divide by zero */ 00474 DBG("DBG: denom = 0 error\r\n"); 00475 err = true; 00476 } 00477 if (num >=0x100000){ /* 20-bit limit */ 00478 DBG("DBG: num value error\r\n"); 00479 err = true; 00480 } 00481 if (denom >=0x100000){ /* 20-bit limit */ 00482 DBG("DBG: denom value error\r\n"); 00483 err = true; 00484 } 00485 if (err == true){ 00486 if (pll == SI5351_PLL_A){ 00487 plla_freq = 0; 00488 } else { // SI5351_PLL_B 00489 pllb_freq = 0; 00490 } 00491 DBG("DBG: return by error\r\n"); 00492 return; 00493 } 00494 /* Feedback Multisynth Divider Equation 00495 * where: a = mult, b = num and c = denom 00496 * P1 register is an 18-bit value using following formula: 00497 * P1[17:0] = 128 * mult + floor(128*(num/denom)) - 512 00498 * P2 register is a 20-bit value using the following formula: 00499 * P2[19:0] = 128 * num - denom * floor(128*(num/denom)) 00500 * P3 register is a 20-bit value using the following formula: 00501 * P3[19:0] = denom 00502 */ 00503 /* Set the main PLL config registers */ 00504 if (num == 0) { 00505 DBG("DBG: num = 0\r\n"); 00506 /* Integer mode */ 00507 P1 = 128 * mult - 512; 00508 P2 = num; 00509 P3 = denom; 00510 } else { 00511 /* Fractional mode */ 00512 DBG("DBG: Fractional mode\r\n"); 00513 P1 = (uint32_t) 00514 (128 * mult + floor(128 * ((double)num/(double)denom)) - 512); 00515 P2 = (uint32_t) 00516 (128 * num - denom * floor(128 * ((double)num/(double)denom))); 00517 P3 = denom; 00518 } 00519 /* Get the appropriate starting point for the PLL registers */ 00520 const uint8_t pllreg_base[] = { 00521 SI5351_REG_26_PLL_A, 00522 SI5351_REG_34_PLL_B 00523 }; 00524 uint8_t baseaddr = pllreg_base[pll]; 00525 /* The datasheet is a nightmare of typos and inconsistencies here! */ 00526 si5351_write(baseaddr, (P3 & 0x0000ff00) >> 8); 00527 si5351_write(baseaddr+1, (P3 & 0x000000ff)); 00528 si5351_write(baseaddr+2, (P1 & 0x00030000) >> 16); 00529 si5351_write(baseaddr+3, (P1 & 0x0000ff00) >> 8); 00530 si5351_write(baseaddr+4, (P1 & 0x000000ff)); 00531 si5351_write(baseaddr+5, 00532 ((P3 & 0x000f0000) >> 12) | ((P2 & 0x000f0000) >> 16) ); 00533 si5351_write(baseaddr+6, (P2 & 0x0000ff00) >> 8); 00534 si5351_write(baseaddr+7, (P2 & 0x000000ff)); 00535 /* Reset both PLLs */ 00536 si5351_write(SI5351_REG_177_PLL_RESET, 00537 SI5351_PLL_RESET_B | SI5351_PLL_RESET_A); 00538 /* Store the frequency settings for use with the Multisynth helper */ 00539 DBG("DBG: Use 26(PLLA) or 34(PLLB)) ->%u and write data\r\n", baseaddr); 00540 double f = base_freq * (mult + ((double)num / (double)denom)); 00541 DBG("DBG: PLL f=%u\r\n", (uint32_t)f); 00542 DBG("DBG: PLL f(pll_freq)=%u\r\n", (uint32_t)pll_freq); 00543 if (pll == SI5351_PLL_A){ 00544 plla_freq = f; 00545 } else { // SI5351_PLL_B 00546 pllb_freq = f; 00547 } 00548 } 00549 00550 /******************************************************************************/ 00551 /*! 00552 @brief Configures the Multisynth divider, which determines the 00553 output clock frequency based on the specified PLL input. 00554 00555 @param output The output channel to use (0..2) 00556 @param pllSource The PLL input source to use, which must be one of: 00557 - SI5351_PLL_A 00558 - SI5351_PLL_B 00559 @param div The integer divider for the Multisynth output. 00560 If pure integer values are used, this value must 00561 be one of: 00562 - SI5351_MULTISYNTH_DIV_4 00563 - SI5351_MULTISYNTH_DIV_6 00564 - SI5351_MULTISYNTH_DIV_8 00565 If fractional output is used, this value must be 00566 between 8 and 900. 00567 @param num The 20-bit numerator for fractional output 00568 (0..1,048,575). Set this to '0' for integer output. 00569 @param denom The 20-bit denominator for fractional output 00570 (1..1,048,575). Set this to '1' or higher to 00571 avoid divide by zero errors. 00572 @section Output Clock Configuration 00573 00574 The multisynth dividers are applied to the specified PLL output, 00575 and are used to reduce the PLL output to a valid range (500kHz 00576 to 160MHz). The relationship can be seen in this formula, where 00577 fVCO is the PLL output frequency and MSx is the multisynth 00578 divider: 00579 fOUT = fVCO / MSx 00580 Valid multisynth dividers are 4, 6, or 8 when using integers, 00581 or any fractional values between 8 + 1/1,048,575 and 900 + 0/1 00582 00583 The following formula is used for the fractional mode divider: 00584 a + b / c 00585 a = The integer value, which must be 4, 6 or 8 in integer mode (MSx_INT=1) 00586 or 6..1800 in fractional mode (MSx_INT=0). 00587 b = The fractional numerator (0..1,048,575) 00588 c = The fractional denominator (1..1,048,575) 00589 00590 @note Try to use integers whenever possible to avoid clock jitter 00591 @note For output frequencies > 150MHz, you must set the divider 00592 to 4 and adjust to PLL to generate the frequency (for example 00593 a PLL of 640 to generate a 160MHz output clock). This is not 00594 yet supported in the driver, which limits frequencies to 00595 500kHz .. 150MHz. 00596 @note For frequencies below 500kHz (down to 8kHz) Rx_DIV must be 00597 used, but this isn't currently implemented in the driver. 00598 */ 00599 /******************************************************************************/ 00600 double SI5351A::si5351_setupMultisynth( 00601 uint8_t output, 00602 uint8_t pllSource, 00603 uint32_t div, 00604 uint32_t num, 00605 uint32_t denom, 00606 uint8_t factor) 00607 { 00608 uint32_t P1; /* Multisynth config register P1 */ 00609 uint32_t P2; /* Multisynth config register P2 */ 00610 uint32_t P3; /* Multisynth config register P3 */ 00611 uint32_t div4 = 0; 00612 double multisynth_double; 00613 00614 DBG("DBG: Enter si5351_setupMultisynth\r\n"); 00615 DBG("DBG: ch=%u, pll=%u, div=%u, num=%u, denom=%u, factor=%u\r\n", 00616 output, pllSource, div, num, denom, factor); 00617 if (output > 3){ 00618 return 0; 00619 } /* Channel range */ 00620 if ((div <= 3) || (div >= 1801)){ /* Divider integer 6..1800 */ 00621 DBG("DBG: div out of range error\r\n"); 00622 return 0; 00623 } 00624 if (denom == 0){ /* Avoid divide by zero */ 00625 DBG("DBG: denom=0 error\r\n"); 00626 return 0; 00627 } 00628 if (num >=0x100000){ /* 20-bit limit */ 00629 DBG("DBG: num bigger error\r\n"); 00630 return 0; 00631 } 00632 if (denom >=0x100000){ /* 20-bit limit */ 00633 DBG("DBG: denom bigger error\r\n"); 00634 return 0; 00635 } 00636 DBG("DBG: Passed range check\r\n"); 00637 /* Get the appropriate starting point for the PLL registers */ 00638 const uint8_t msreg_base[] = { 00639 SI5351_REG_42_MULTISYNTH0, 00640 SI5351_REG_50_MULTISYNTH1, 00641 SI5351_REG_58_MULTISYNTH2, 00642 }; 00643 uint8_t baseaddr = msreg_base[output]; 00644 /* Output Multisynth Divider Equations 00645 * where: a = div, b = num and c = denom 00646 * P1 register is an 18-bit value using following formula: 00647 * P1[17:0] = 128 * a + floor(128*(b/c)) - 512 00648 * P2 register is a 20-bit value using the following formula: 00649 * P2[19:0] = 128 * b - c * floor(128*(b/c)) 00650 * P3 register is a 20-bit value using the following formula: 00651 * P3[19:0] = c 00652 */ 00653 /* Set the main PLL config registers */ 00654 if (div == 4) { 00655 DBG("DBG: enter div==4\r\n"); 00656 div4 = SI5351_DIVBY4; 00657 P1 = P2 = 0; 00658 P3 = 1; 00659 multisynth_double = 4.0f; 00660 } else if (num == 0) { 00661 DBG("DBG: enter num==0\r\n"); 00662 /* Integer mode */ 00663 P1 = 128 * div - 512; 00664 P2 = 0; 00665 P3 = 1; 00666 multisynth_double = (double)div; 00667 } else { 00668 /* Fractional mode */ 00669 DBG("DBG: enter Fractional mode\r\n"); 00670 P1 = (uint32_t) 00671 (128 * div + floor(128 * ((float)num/(float)denom)) - 512); 00672 P2 = (uint32_t) 00673 (128 * num - denom * floor(128 * ((float)num/(float)denom))); 00674 P3 = denom; 00675 multisynth_double = div + (double)num /(double)denom; 00676 /* a + b/c between 6..1800 */ 00677 if ((multisynth_double < 6.0f) || (multisynth_double > 1800.0f)){ 00678 return 0; 00679 } 00680 } 00681 /* Set the MSx config registers */ 00682 si5351_write(baseaddr, (P3 & 0x0000ff00) >> 8); 00683 si5351_write(baseaddr+1, (P3 & 0x000000ff)); 00684 si5351_write(baseaddr+2, ((P1 & 0x00030000) >> 16) | div4 | factor); 00685 si5351_write(baseaddr+3, (P1 & 0x0000ff00) >> 8); 00686 si5351_write(baseaddr+4, (P1 & 0x000000ff)); 00687 si5351_write(baseaddr+5, 00688 ((P3 & 0x000f0000) >> 12) | ((P2 & 0x000f0000) >> 16)); 00689 si5351_write(baseaddr+6, (P2 & 0x0000ff00) >> 8); 00690 si5351_write(baseaddr+7, (P2 & 0x000000ff)); 00691 /* Configure the clk control and enable the output */ 00692 const uint8_t clkctrl[] = { 00693 SI5351_REG_16_CLK0_CONTROL, 00694 SI5351_REG_17_CLK1_CONTROL, 00695 SI5351_REG_18_CLK2_CONTROL 00696 }; 00697 uint8_t dat; 00698 dat = drv_current | SI5351_CLK_INPUT_MULTISYNTH_N; 00699 if (pllSource == SI5351_PLL_B){ 00700 dat |= SI5351_CLK_PLL_SELECT_B; 00701 } 00702 if (num == 0){ 00703 dat |= SI5351_CLK_INTEGER_MODE; 00704 } 00705 DBG("DBG: CLK%u: reg_%u=0x%02x\r\n", output, clkctrl[output], dat); 00706 si5351_write(clkctrl[output], dat); 00707 DBG("DBG: a+b/c=%8.2f\r\n", multisynth_double); 00708 return multisynth_double; 00709 } 00710 00711 uint32_t SI5351A::gcd(uint32_t x, uint32_t y) 00712 { 00713 int32_t z; 00714 while (y != 0) { 00715 z = x % y; 00716 x = y; 00717 y = z; 00718 } 00719 return x; 00720 } 00721 00722 double SI5351A::si5351_set_frequency_fixedpll( 00723 uint8_t channel, 00724 uint32_t pll, 00725 uint32_t pllfreq, 00726 uint32_t freq, 00727 uint8_t factor) 00728 { 00729 DBG("DBG: Enter si5351_set_frequency_fixedpll\r\n"); 00730 uint32_t div = (floor)((double)pllfreq / (double)freq); // range: 8 ~ 1800 00731 uint32_t num = pllfreq - freq * div; 00732 uint32_t denom = freq; 00733 //int32_t k = freq / (1<<20) + 1; 00734 uint32_t k = gcd(num, denom); 00735 num /= k; 00736 denom /= k; 00737 while (denom >= (1<<20)) { 00738 num >>= 1; 00739 denom >>= 1; 00740 } 00741 DBG("DBG: CLK%u: PLL=%u,div=%u,num=%u,denom=%u\r\n", 00742 channel, pll, div, num, denom); 00743 double x = si5351_setupMultisynth(channel, pll, div, num, denom, factor); 00744 if (x == 0.0f){ return 0;} 00745 x = (double)pll_freq / x; 00746 DBG("DBG: Freqency=%.0f[Hz]\r\n", x); 00747 return x; 00748 } 00749 00750 double SI5351A::si5351_set_frequency_fixeddiv( 00751 uint8_t channel, 00752 uint32_t pll, 00753 uint32_t freq, 00754 uint32_t div) 00755 { 00756 DBG("DBG: si5351_set_frequency_fixeddiv\r\n"); 00757 uint32_t pllfreq = freq * div; 00758 uint32_t multi = pllfreq / base_freq; 00759 uint32_t num = pllfreq - multi * base_freq; 00760 uint32_t denom = base_freq; 00761 uint32_t k = gcd(num, denom); 00762 num /= k; 00763 denom /= k; 00764 while (denom >= (1<<20)) { 00765 num >>= 1; 00766 denom >>= 1; 00767 } 00768 si5351_setupPLL(pll, multi, num, denom); 00769 num = 0; 00770 double x = si5351_setupMultisynth(channel, pll, div, num, denom, 0); 00771 if (x == 0.0f){ return 0.0f;} 00772 if (pll == SI5351_PLL_A){ 00773 x = plla_freq / x; 00774 } else { // SI5351_PLL_B 00775 x = pllb_freq / x; 00776 } 00777 DBG("DBG: Freqency=%.0f[Hz]\r\n", x); 00778 return x; 00779 } 00780 00781 void SI5351A::si5351_bulk_write(const uint8_t *buf, uint8_t len) 00782 { 00783 _i2c.write(addr, (const char*)buf, len, false); 00784 } 00785 00786 void SI5351A::si5351_write(uint8_t reg, uint8_t dat) 00787 { 00788 uint8_t buf[] = { reg, dat }; 00789 _i2c.write(addr,(const char *)buf, 2, false); 00790 } 00791 00792 void SI5351A::si5351_read(const uint8_t *buf) 00793 { 00794 int n = (int)buf[1]; 00795 _i2c.write(addr,(const char *)buf, 1, true); 00796 _i2c.read(addr, (char *)buf, n, false); 00797 } 00798 00799 //----------- DEBUG PURPOSE ---------------------------------------------------- 00800 // Print memory contents 00801 void SI5351A::put_dump (const uint8_t *buff, uint8_t ofs, uint8_t cnt) 00802 { 00803 printf("%03u ", ofs); 00804 for(int n = 0; n < cnt; n++) { // show hex 00805 printf(" %02x", buff[n]); 00806 } 00807 printf("\r\n"); 00808 } 00809 00810 void SI5351A::prnt_reg(uint8_t offset, uint8_t n) 00811 { 00812 uint8_t buf[16]; 00813 buf[0] = offset; 00814 buf[1] = n; 00815 si5351_read(buf); 00816 put_dump(buf, offset, n); 00817 } 00818 00819 void SI5351A::debug_reg_print(void) 00820 { 00821 printf("Show Si5351A registers\r\n"); 00822 printf("reg 0 1 2 3 4 5 6 7 8 9\r\n"); 00823 prnt_reg(0, 4); // reg0 to reg3 00824 prnt_reg(9, 1); // reg9 00825 prnt_reg(15, 4); // reg15 to reg18 00826 prnt_reg(24, 10); // reg24 to reg33 00827 prnt_reg(34, 10); // reg34 to reg43 00828 prnt_reg(44, 10); // reg44 to reg53 00829 prnt_reg(54, 10); // reg54 to reg63 00830 prnt_reg(64, 2); // reg64 to reg65 00831 prnt_reg(149, 10); // reg149 to reg158 00832 prnt_reg(159, 3); // reg159 to reg161 00833 prnt_reg(165, 3); // reg165 to reg167 00834 prnt_reg(177, 1); // reg177 00835 prnt_reg(183, 1); // reg183 00836 prnt_reg(187, 1); // reg187 00837 } 00838 00839 void SI5351A::debug_current_config(void) 00840 { 00841 uint8_t buf[16]; 00842 uint8_t dt0; 00843 uint8_t dt1; 00844 //Step1 00845 printf("[BASE CLOCK] --> "); 00846 buf[0] = 183; // register address 00847 buf[1] = 1; // # of reading bytes 00848 si5351_read(buf); 00849 printf("Xtal=%u[Hz] with internal cap=", base_freq); 00850 dt0 = buf[0] & 0xc0; 00851 switch (dt0){ 00852 case 0xc0: 00853 printf("10"); 00854 break; 00855 case 0x80: 00856 printf("8"); 00857 break; 00858 case 0x40: 00859 printf("6"); 00860 break; 00861 default: 00862 printf("?(bad config)"); 00863 break; 00864 } 00865 printf("[pF]\r\n"); 00866 printf("--> compensation=%f\r\n", compensation); 00867 printf("--> pll_freq=XTAL*PLL_N=%u\r\n", pll_freq); 00868 //Step2 00869 printf("[PLLn] --> "); 00870 buf[0] = 15; 00871 buf[1] = 1; 00872 si5351_read(buf); 00873 dt0 = buf[0]; 00874 dt1 = dt0 >> 6; 00875 printf("Clock in divide by %u", 1U << dt1); 00876 printf(" PLLA clock source is "); 00877 if (dt0 & 0x04){ 00878 printf("none XTAL(bad config)"); 00879 } else { 00880 printf("XTAL"); 00881 } 00882 printf(" & PLLB = "); 00883 if (dt0 & 0x08){ 00884 printf("none XTAL(bad config)"); 00885 } else { 00886 printf("XTAL"); 00887 } 00888 printf("\r\n"); 00889 //Step3 00890 printf("[CLK0,1,2] --> "); 00891 printf("CLKn output E:enable/D:disable * "); 00892 buf[0] = 9; // register address 00893 buf[1] = 1; // # of reading bytes 00894 si5351_read(buf); 00895 dt0 = buf[0] & 0x07; 00896 buf[0] = 3; // register address 00897 buf[1] = 1; // # of reading bytes 00898 si5351_read(buf); 00899 dt1 = buf[0] & 0x07; 00900 printf("CLK2:"); 00901 if ((dt0 & 0x04) && (dt1 & 0x04)){ 00902 printf("D"); 00903 } else { 00904 printf("E"); 00905 } 00906 printf(", CLK1:"); 00907 if ((dt0 & 0x02) && (dt1 & 0x02)){ 00908 printf("D"); 00909 } else { 00910 printf("E"); 00911 } 00912 printf(", CLK0:"); 00913 if ((dt0 & 0x01) && (dt1 & 0x01)){ 00914 printf("D"); 00915 } else { 00916 printf("E"); 00917 } 00918 printf("\r\n"); 00919 //Step4 00920 buf[0] = 16; 00921 buf[1] = 3; 00922 si5351_read(buf); 00923 printf("--> CLK0 * "); 00924 reg_16_17_18(buf[0]); 00925 printf("--> CLK1 * "); 00926 reg_16_17_18(buf[1]); 00927 printf("--> CLK2 * "); 00928 reg_16_17_18(buf[2]); 00929 //Step5 00930 printf("[PLLn P1,P2,P3]\r\n"); 00931 printf("--> PLLA * "); 00932 buf[0] = 26; // register address 00933 buf[1] = 8; // # of reading bytes 00934 si5351_read(buf); 00935 reg_pll_8bytes(buf); 00936 printf("--> PLLB * "); 00937 buf[0] = 34; // register address 00938 buf[1] = 8; // # of reading bytes 00939 si5351_read(buf); 00940 reg_pll_8bytes(buf); 00941 printf("[MultiSynth-n P1,P2,P3]\r\n"); 00942 printf("--> Mltsyn0 * "); 00943 buf[0] = 42; // register address 00944 buf[1] = 8; // # of reading bytes 00945 si5351_read(buf); 00946 reg_mltisyc_8bytes(buf); 00947 printf("--> Mltsyn1 * "); 00948 buf[0] = 50; // register address 00949 buf[1] = 8; // # of reading bytes 00950 si5351_read(buf); 00951 reg_mltisyc_8bytes(buf); 00952 printf("--> Mltsyn2 * "); 00953 buf[0] = 58; // register address 00954 buf[1] = 8; // # of reading bytes 00955 si5351_read(buf); 00956 reg_mltisyc_8bytes(buf); 00957 } 00958 00959 void SI5351A::reg_pll_8bytes(uint8_t *buf) 00960 { 00961 uint32_t dt = ((uint32_t)(buf[5] & 0xf0) << 12) + ((uint32_t)buf[0] << 8) 00962 + (uint32_t)buf[1]; 00963 printf("P3=%6u (0x%05x), ", dt, dt); 00964 dt = ((uint32_t)(buf[5] & 0x0f) << 16) + ((uint32_t)buf[6] << 8) 00965 + (uint32_t)buf[7]; 00966 printf("P2=%6u (0x%05x), ", dt, dt); 00967 dt = ((uint32_t)(buf[2] & 0x03) << 16) + ((uint32_t)buf[3] << 8) 00968 + (uint32_t)buf[4]; 00969 printf("P1=%6u (0x%05x)\r\n", dt, dt); 00970 } 00971 00972 void SI5351A::reg_mltisyc_8bytes(uint8_t *buf) 00973 { 00974 uint32_t dt = ((uint32_t)(buf[5] & 0xf0) << 12) + ((uint32_t)buf[0] << 8) 00975 + (uint32_t)buf[1]; 00976 printf("P3=%6u (0x%05x), ", dt, dt); 00977 dt = ((uint32_t)(buf[5] & 0x0f) << 16) + ((uint32_t)buf[6] << 8) 00978 + (uint32_t)buf[7]; 00979 printf("P2=%6u (0x%05x), ", dt, dt); 00980 dt = ((uint32_t)(buf[2] & 0x03) << 16) + ((uint32_t)buf[3] << 8) 00981 + (uint32_t)buf[4]; 00982 printf("P1=%6u (0x%05x), ", dt, dt); 00983 uint8_t d = buf[2]; 00984 if ((d & 0x0c) == 0x0c){ 00985 printf("Divided by"); 00986 } else { 00987 printf("Div >"); 00988 } 00989 printf(" 4 mode, "); 00990 dt >>= 4; 00991 dt &=0x07; 00992 printf("R-reg: Divided by %u\r\n", 1U << dt); 00993 } 00994 00995 void SI5351A::reg_16_17_18(uint8_t dt) 00996 { 00997 printf("Power "); 00998 if (dt & 0x80){ 00999 printf("down(not used)"); 01000 } else { 01001 printf("up(running)"); 01002 } 01003 printf(", MultiSynth-> "); 01004 if (dt & 0x40){ 01005 printf("Integer"); 01006 } else { 01007 printf("Fractional"); 01008 } 01009 printf(" mode, PLL-> "); 01010 if (dt & 0x20){ 01011 printf("PLLB"); 01012 } else { 01013 printf("PLLA"); 01014 } 01015 printf(", Clock-> "); 01016 if (dt & 0x20){ 01017 printf("inverted"); 01018 } else { 01019 printf("not inverted"); 01020 } 01021 printf(", Drive strength-> "); 01022 printf("%umA\r\n", 2 + 2 * (dt & 0x03)); 01023 } 01024 01025 /******************************************************************************/ 01026 /*! 01027 @brief Configures the Si5351 with config settings generated in 01028 ClockBuilder. You can use this function to make sure that 01029 your HW is properly configure and that there are no problems 01030 with the board itself. 01031 01032 Running this function should provide the following output: 01033 * Channel 0: 120.00 MHz 01034 * Channel 1: 12.00 MHz 01035 * Channel 2: 13.56 MHz 01036 @note This will overwrite all of the config registers! 01037 */ 01038 /******************************************************************************/ 01039 /* Test setup from SI5351 ClockBuilder 01040 * ----------------------------------- 01041 * XTAL: 25 MHz 01042 * Channel 0: 120.00 MHz 01043 * Channel 1: 12.00 MHz 01044 * Channel 2: 13.56 MHz 01045 */ 01046 static const uint8_t m_si5351_regs_15to92_149to170[100][2] = 01047 { 01048 { 15, 0x00 }, /* Input source = crystal for PLLA and PLLB */ 01049 /* CLK0 Control: 8mA drive, Multisynth 0 as CLK0 source, Clock not inverted, 01050 Source = PLLA, Multisynth 0 in integer mode, clock powered up */ 01051 { 16, 0x4F }, 01052 /* CLK1 Control: 8mA drive, Multisynth 1 as CLK1 source, Clock not inverted, 01053 Source = PLLA, Multisynth 1 in integer mode, clock powered up */ 01054 { 17, 0x4F }, 01055 /* CLK2 Control: 8mA drive, Multisynth 2 as CLK2 source, Clock not inverted, 01056 Source = PLLB, Multisynth 2 in integer mode, clock powered up */ 01057 { 18, 0x6F }, 01058 { 19, 0x80 }, /* CLK3 Control: Not used ... clock powered down */ 01059 { 20, 0x80 }, /* CLK4 Control: Not used ... clock powered down */ 01060 { 21, 0x80 }, /* CLK5 Control: Not used ... clock powered down */ 01061 { 22, 0x80 }, /* CLK6 Control: Not used ... clock powered down */ 01062 { 23, 0x80 }, /* CLK7 Control: Not used ... clock powered down */ 01063 { 24, 0x00 }, /* Clock disable state 0..3 (low when disabled) */ 01064 { 25, 0x00 }, /* Clock disable state 4..7 (low when disabled) */ 01065 /* PLL_A Setup */ 01066 { 26, 0x00 }, { 27, 0x05 }, { 28, 0x00 }, { 29, 0x0C }, 01067 { 30, 0x66 }, { 31, 0x00 }, { 32, 0x00 }, { 33, 0x02 }, 01068 /* PLL_B Setup */ 01069 { 34, 0x02 }, { 35, 0x71 }, { 36, 0x00 }, { 37, 0x0C }, 01070 { 38, 0x1A }, { 39, 0x00 }, { 40, 0x00 }, { 41, 0x86 }, 01071 /* Multisynth Setup */ 01072 { 42, 0x00 }, { 43, 0x01 }, { 44, 0x00 }, { 45, 0x01 }, 01073 { 46, 0x00 }, { 47, 0x00 }, { 48, 0x00 }, { 49, 0x00 }, 01074 { 50, 0x00 }, { 51, 0x01 }, { 52, 0x00 }, { 53, 0x1C }, 01075 { 54, 0x00 }, { 55, 0x00 }, { 56, 0x00 }, { 57, 0x00 }, 01076 { 58, 0x00 }, { 59, 0x01 }, { 60, 0x00 }, { 61, 0x18 }, 01077 { 62, 0x00 }, { 63, 0x00 }, { 64, 0x00 }, { 65, 0x00 }, 01078 { 66, 0x00 }, { 67, 0x00 }, { 68, 0x00 }, { 69, 0x00 }, 01079 { 70, 0x00 }, { 71, 0x00 }, { 72, 0x00 }, { 73, 0x00 }, 01080 { 74, 0x00 }, { 75, 0x00 }, { 76, 0x00 }, { 77, 0x00 }, 01081 { 78, 0x00 }, { 79, 0x00 }, { 80, 0x00 }, { 81, 0x00 }, 01082 { 82, 0x00 }, { 83, 0x00 }, { 84, 0x00 }, { 85, 0x00 }, 01083 { 86, 0x00 }, { 87, 0x00 }, { 88, 0x00 }, { 89, 0x00 }, 01084 { 90, 0x00 }, { 91, 0x00 }, { 92, 0x00 }, 01085 /* Misc Config Register */ 01086 { 149, 0x00 }, { 150, 0x00 }, { 151, 0x00 }, { 152, 0x00 }, 01087 { 153, 0x00 }, { 154, 0x00 }, { 155, 0x00 }, { 156, 0x00 }, 01088 { 157, 0x00 }, { 158, 0x00 }, { 159, 0x00 }, { 160, 0x00 }, 01089 { 161, 0x00 }, { 162, 0x00 }, { 163, 0x00 }, { 164, 0x00 }, 01090 { 165, 0x00 }, { 166, 0x00 }, { 167, 0x00 }, { 168, 0x00 }, 01091 { 169, 0x00 }, { 170, 0x00 } 01092 }; 01093 01094 void SI5351A::debug_example_clock(void) 01095 { 01096 /* Disable all outputs setting CLKx_DIS high */ 01097 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff); 01098 /* Writes configuration data to device using the register map contents 01099 generated by ClockBuilder Desktop (registers 15-92 + 149-170) */ 01100 for (uint16_t i = 0; i < sizeof(m_si5351_regs_15to92_149to170)/2; i++){ 01101 si5351_write(m_si5351_regs_15to92_149to170[i][0], 01102 m_si5351_regs_15to92_149to170[i][1]); 01103 } 01104 /* Apply soft reset */ 01105 si5351_write(SI5351_REG_177_PLL_RESET, 0xac); 01106 /* Enabled desired outputs (see Register 3) */ 01107 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0x00); 01108 printf("Please check following output\r\n"); 01109 printf("CLK0: 120.00MHz, CLK1: 12.00MHz, CLK2: 13.56MHz\r\n"); 01110 } 01111 01112 //--------------------------------------------------------------------------------------------------------------------- 01113 // Original & reference files 01114 //--------------------------------------------------------------------------------------------------------------------- 01115 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 01116 // Adafruit_SI5351.cpp 01117 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 01118 #if 0 01119 /**************************************************************************/ 01120 /*! 01121 @file Adafruit_SI5351.cpp 01122 @author K. Townsend (Adafruit Industries) 01123 01124 @brief Driver for the SI5351 160MHz Clock Gen 01125 01126 @section REFERENCES 01127 01128 Si5351A/B/C Datasheet: 01129 http://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf 01130 01131 Manually Generating an Si5351 Register Map: 01132 http://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf 01133 01134 @section LICENSE 01135 01136 Software License Agreement (BSD License) 01137 01138 Copyright (c) 2014, Adafruit Industries 01139 All rights reserved. 01140 01141 Redistribution and use in source and binary forms, with or without 01142 modification, are permitted provided that the following conditions are met: 01143 1. Redistributions of source code must retain the above copyright 01144 notice, this list of conditions and the following disclaimer. 01145 2. Redistributions in binary form must reproduce the above copyright 01146 notice, this list of conditions and the following disclaimer in the 01147 documentation and/or other materials provided with the distribution. 01148 3. Neither the name of the copyright holders nor the 01149 names of its contributors may be used to endorse or promote products 01150 derived from this software without specific prior written permission. 01151 01152 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 01153 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 01154 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 01155 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 01156 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 01157 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 01158 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 01159 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 01160 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 01161 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 01162 */ 01163 /**************************************************************************/ 01164 #if defined(__AVR__) 01165 #include <avr/pgmspace.h> 01166 #include <util/delay.h> 01167 #else 01168 #include "pgmspace.h" 01169 #endif 01170 #include <stdlib.h> 01171 01172 #include <Adafruit_SI5351.h> 01173 01174 /**************************************************************************/ 01175 /*! 01176 Constructor 01177 */ 01178 /**************************************************************************/ 01179 Adafruit_SI5351::Adafruit_SI5351(void) 01180 { 01181 m_si5351Config.initialised = false; 01182 m_si5351Config.crystalFreq = SI5351_CRYSTAL_FREQ_25MHZ; 01183 m_si5351Config.crystalLoad = SI5351_CRYSTAL_LOAD_10PF; 01184 m_si5351Config.crystalPPM = 30; 01185 m_si5351Config.plla_configured = false; 01186 m_si5351Config.plla_freq = 0; 01187 m_si5351Config.pllb_configured = false; 01188 m_si5351Config.pllb_freq = 0; 01189 } 01190 01191 /**************************************************************************/ 01192 /*! 01193 Initializes I2C and configures the breakout (call this function before 01194 doing anything else) 01195 */ 01196 /**************************************************************************/ 01197 err_t Adafruit_SI5351::begin(void) 01198 { 01199 /* Initialise I2C */ 01200 Wire.begin(); 01201 01202 /* ToDo: Make sure we're actually connected */ 01203 01204 /* Disable all outputs setting CLKx_DIS high */ 01205 ASSERT_STATUS(write8(SI5351_REGISTER_3_OUTPUT_ENABLE_CONTROL, 0xFF)); 01206 01207 /* Power down all output drivers */ 01208 ASSERT_STATUS(write8(SI5351_REGISTER_16_CLK0_CONTROL, 0x80)); 01209 ASSERT_STATUS(write8(SI5351_REGISTER_17_CLK1_CONTROL, 0x80)); 01210 ASSERT_STATUS(write8(SI5351_REGISTER_18_CLK2_CONTROL, 0x80)); 01211 ASSERT_STATUS(write8(SI5351_REGISTER_19_CLK3_CONTROL, 0x80)); 01212 ASSERT_STATUS(write8(SI5351_REGISTER_20_CLK4_CONTROL, 0x80)); 01213 ASSERT_STATUS(write8(SI5351_REGISTER_21_CLK5_CONTROL, 0x80)); 01214 ASSERT_STATUS(write8(SI5351_REGISTER_22_CLK6_CONTROL, 0x80)); 01215 ASSERT_STATUS(write8(SI5351_REGISTER_23_CLK7_CONTROL, 0x80)); 01216 01217 /* Set the load capacitance for the XTAL */ 01218 ASSERT_STATUS(write8(SI5351_REGISTER_183_CRYSTAL_INTERNAL_LOAD_CAPACITANCE, 01219 m_si5351Config.crystalLoad)); 01220 01221 /* Set interrupt masks as required (see Register 2 description in AN619). 01222 By default, ClockBuilder Desktop sets this register to 0x18. 01223 Note that the least significant nibble must remain 0x8, but the most 01224 significant nibble may be modified to suit your needs. */ 01225 01226 /* Reset the PLL config fields just in case we call init again */ 01227 m_si5351Config.plla_configured = false; 01228 m_si5351Config.plla_freq = 0; 01229 m_si5351Config.pllb_configured = false; 01230 m_si5351Config.pllb_freq = 0; 01231 01232 /* All done! */ 01233 m_si5351Config.initialised = true; 01234 01235 return ERROR_NONE; 01236 } 01237 01238 /**************************************************************************/ 01239 /*! 01240 @brief Configures the Si5351 with config settings generated in 01241 ClockBuilder. You can use this function to make sure that 01242 your HW is properly configure and that there are no problems 01243 with the board itself. 01244 01245 Running this function should provide the following output: 01246 * Channel 0: 120.00 MHz 01247 * Channel 1: 12.00 MHz 01248 * Channel 2: 13.56 MHz 01249 01250 @note This will overwrite all of the config registers! 01251 */ 01252 /**************************************************************************/ 01253 err_t Adafruit_SI5351::setClockBuilderData(void) 01254 { 01255 uint16_t i = 0; 01256 01257 /* Make sure we've called init first */ 01258 ASSERT(m_si5351Config.initialised, ERROR_DEVICENOTINITIALISED); 01259 01260 /* Disable all outputs setting CLKx_DIS high */ 01261 ASSERT_STATUS(write8(SI5351_REGISTER_3_OUTPUT_ENABLE_CONTROL, 0xFF)); 01262 01263 /* Writes configuration data to device using the register map contents 01264 generated by ClockBuilder Desktop (registers 15-92 + 149-170) */ 01265 for (i=0; i<sizeof(m_si5351_regs_15to92_149to170)/2; i++) 01266 { 01267 ASSERT_STATUS(write8( m_si5351_regs_15to92_149to170[i][0], 01268 m_si5351_regs_15to92_149to170[i][1] )); 01269 } 01270 01271 /* Apply soft reset */ 01272 ASSERT_STATUS(write8(SI5351_REGISTER_177_PLL_RESET, 0xAC)); 01273 01274 /* Enabled desired outputs (see Register 3) */ 01275 ASSERT_STATUS(write8(SI5351_REGISTER_3_OUTPUT_ENABLE_CONTROL, 0x00)); 01276 01277 return ERROR_NONE; 01278 } 01279 01280 /**************************************************************************/ 01281 /*! 01282 @brief Sets the multiplier for the specified PLL using integer values 01283 01284 @param pll The PLL to configure, which must be one of the following: 01285 - SI5351_PLL_A 01286 - SI5351_PLL_B 01287 @param mult The PLL integer multiplier (must be between 15 and 90) 01288 */ 01289 /**************************************************************************/ 01290 err_t Adafruit_SI5351::setupPLLInt(si5351PLL_t pll, uint8_t mult) 01291 { 01292 return setupPLL(pll, mult, 0, 1); 01293 } 01294 01295 /**************************************************************************/ 01296 /*! 01297 @brief Sets the multiplier for the specified PLL 01298 01299 @param pll The PLL to configure, which must be one of the following: 01300 - SI5351_PLL_A 01301 - SI5351_PLL_B 01302 @param mult The PLL integer multiplier (must be between 15 and 90) 01303 @param num The 20-bit numerator for fractional output (0..1,048,575). 01304 Set this to '0' for integer output. 01305 @param denom The 20-bit denominator for fractional output (1..1,048,575). 01306 Set this to '1' or higher to avoid divider by zero errors. 01307 01308 @section PLL Configuration 01309 01310 fVCO is the PLL output, and must be between 600..900MHz, where: 01311 01312 fVCO = fXTAL * (a+(b/c)) 01313 01314 fXTAL = the crystal input frequency 01315 a = an integer between 15 and 90 01316 b = the fractional numerator (0..1,048,575) 01317 c = the fractional denominator (1..1,048,575) 01318 01319 NOTE: Try to use integers whenever possible to avoid clock jitter 01320 (only use the a part, setting b to '0' and c to '1'). 01321 01322 See: http://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf 01323 */ 01324 /**************************************************************************/ 01325 err_t Adafruit_SI5351::setupPLL(si5351PLL_t pll, 01326 uint8_t mult, 01327 uint32_t num, 01328 uint32_t denom) 01329 { 01330 uint32_t P1; /* PLL config register P1 */ 01331 uint32_t P2; /* PLL config register P2 */ 01332 uint32_t P3; /* PLL config register P3 */ 01333 01334 /* Basic validation */ 01335 ASSERT( m_si5351Config.initialised, ERROR_DEVICENOTINITIALISED ); 01336 ASSERT( (mult > 14) && (mult < 91), ERROR_INVALIDPARAMETER ); /* mult = 15..90 */ 01337 ASSERT( denom > 0, ERROR_INVALIDPARAMETER ); /* Avoid divide by zero */ 01338 ASSERT( num <= 0xFFFFF, ERROR_INVALIDPARAMETER ); /* 20-bit limit */ 01339 ASSERT( denom <= 0xFFFFF, ERROR_INVALIDPARAMETER ); /* 20-bit limit */ 01340 01341 /* Feedback Multisynth Divider Equation 01342 * 01343 * where: a = mult, b = num and c = denom 01344 * 01345 * P1 register is an 18-bit value using following formula: 01346 * 01347 * P1[17:0] = 128 * mult + floor(128*(num/denom)) - 512 01348 * 01349 * P2 register is a 20-bit value using the following formula: 01350 * 01351 * P2[19:0] = 128 * num - denom * floor(128*(num/denom)) 01352 * 01353 * P3 register is a 20-bit value using the following formula: 01354 * 01355 * P3[19:0] = denom 01356 */ 01357 01358 /* Set the main PLL config registers */ 01359 if (num == 0) 01360 { 01361 /* Integer mode */ 01362 P1 = 128 * mult - 512; 01363 P2 = num; 01364 P3 = denom; 01365 } 01366 else 01367 { 01368 /* Fractional mode */ 01369 P1 = (uint32_t)(128 * mult + floor(128 * ((float)num/(float)denom)) - 512); 01370 P2 = (uint32_t)(128 * num - denom * floor(128 * ((float)num/(float)denom))); 01371 P3 = denom; 01372 } 01373 01374 /* Get the appropriate starting point for the PLL registers */ 01375 uint8_t baseaddr = (pll == SI5351_PLL_A ? 26 : 34); 01376 01377 /* The datasheet is a nightmare of typos and inconsistencies here! */ 01378 ASSERT_STATUS( write8( baseaddr, (P3 & 0x0000FF00) >> 8)); 01379 ASSERT_STATUS( write8( baseaddr+1, (P3 & 0x000000FF))); 01380 ASSERT_STATUS( write8( baseaddr+2, (P1 & 0x00030000) >> 16)); 01381 ASSERT_STATUS( write8( baseaddr+3, (P1 & 0x0000FF00) >> 8)); 01382 ASSERT_STATUS( write8( baseaddr+4, (P1 & 0x000000FF))); 01383 ASSERT_STATUS( write8( baseaddr+5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16) )); 01384 ASSERT_STATUS( write8( baseaddr+6, (P2 & 0x0000FF00) >> 8)); 01385 ASSERT_STATUS( write8( baseaddr+7, (P2 & 0x000000FF))); 01386 01387 /* Reset both PLLs */ 01388 ASSERT_STATUS( write8(SI5351_REGISTER_177_PLL_RESET, (1<<7) | (1<<5) )); 01389 01390 /* Store the frequency settings for use with the Multisynth helper */ 01391 if (pll == SI5351_PLL_A) 01392 { 01393 float fvco = m_si5351Config.crystalFreq * (mult + ( (float)num / (float)denom )); 01394 m_si5351Config.plla_configured = true; 01395 m_si5351Config.plla_freq = (uint32_t)floor(fvco); 01396 } 01397 else 01398 { 01399 float fvco = m_si5351Config.crystalFreq * (mult + ( (float)num / (float)denom )); 01400 m_si5351Config.pllb_configured = true; 01401 m_si5351Config.pllb_freq = (uint32_t)floor(fvco); 01402 } 01403 01404 return ERROR_NONE; 01405 } 01406 01407 /**************************************************************************/ 01408 /*! 01409 @brief Configures the Multisynth divider using integer output. 01410 01411 @param output The output channel to use (0..2) 01412 @param pllSource The PLL input source to use, which must be one of: 01413 - SI5351_PLL_A 01414 - SI5351_PLL_B 01415 @param div The integer divider for the Multisynth output, 01416 which must be one of the following values: 01417 - SI5351_MULTISYNTH_DIV_4 01418 - SI5351_MULTISYNTH_DIV_6 01419 - SI5351_MULTISYNTH_DIV_8 01420 */ 01421 /**************************************************************************/ 01422 err_t Adafruit_SI5351::setupMultisynthInt(uint8_t output, 01423 si5351PLL_t pllSource, 01424 si5351MultisynthDiv_t div) 01425 { 01426 return setupMultisynth(output, pllSource, div, 0, 1); 01427 } 01428 01429 01430 err_t Adafruit_SI5351::setupRdiv(uint8_t output, si5351RDiv_t div) { 01431 ASSERT( output < 3, ERROR_INVALIDPARAMETER); /* Channel range */ 01432 01433 uint8_t Rreg, regval; 01434 01435 if (output == 0) Rreg = SI5351_REGISTER_44_MULTISYNTH0_PARAMETERS_3; 01436 if (output == 1) Rreg = SI5351_REGISTER_52_MULTISYNTH1_PARAMETERS_3; 01437 if (output == 2) Rreg = SI5351_REGISTER_60_MULTISYNTH2_PARAMETERS_3; 01438 01439 read8(Rreg, ®val); 01440 01441 regval &= 0x0F; 01442 uint8_t divider = div; 01443 divider &= 0x07; 01444 divider <<= 4; 01445 regval |= divider; 01446 return write8(Rreg, regval); 01447 } 01448 01449 /**************************************************************************/ 01450 /*! 01451 @brief Configures the Multisynth divider, which determines the 01452 output clock frequency based on the specified PLL input. 01453 01454 @param output The output channel to use (0..2) 01455 @param pllSource The PLL input source to use, which must be one of: 01456 - SI5351_PLL_A 01457 - SI5351_PLL_B 01458 @param div The integer divider for the Multisynth output. 01459 If pure integer values are used, this value must 01460 be one of: 01461 - SI5351_MULTISYNTH_DIV_4 01462 - SI5351_MULTISYNTH_DIV_6 01463 - SI5351_MULTISYNTH_DIV_8 01464 If fractional output is used, this value must be 01465 between 8 and 900. 01466 @param num The 20-bit numerator for fractional output 01467 (0..1,048,575). Set this to '0' for integer output. 01468 @param denom The 20-bit denominator for fractional output 01469 (1..1,048,575). Set this to '1' or higher to 01470 avoid divide by zero errors. 01471 01472 @section Output Clock Configuration 01473 01474 The multisynth dividers are applied to the specified PLL output, 01475 and are used to reduce the PLL output to a valid range (500kHz 01476 to 160MHz). The relationship can be seen in this formula, where 01477 fVCO is the PLL output frequency and MSx is the multisynth 01478 divider: 01479 01480 fOUT = fVCO / MSx 01481 01482 Valid multisynth dividers are 4, 6, or 8 when using integers, 01483 or any fractional values between 8 + 1/1,048,575 and 900 + 0/1 01484 01485 The following formula is used for the fractional mode divider: 01486 01487 a + b / c 01488 01489 a = The integer value, which must be 4, 6 or 8 in integer mode (MSx_INT=1) 01490 or 8..900 in fractional mode (MSx_INT=0). 01491 b = The fractional numerator (0..1,048,575) 01492 c = The fractional denominator (1..1,048,575) 01493 01494 @note Try to use integers whenever possible to avoid clock jitter 01495 01496 @note For output frequencies > 150MHz, you must set the divider 01497 to 4 and adjust to PLL to generate the frequency (for example 01498 a PLL of 640 to generate a 160MHz output clock). This is not 01499 yet supported in the driver, which limits frequencies to 01500 500kHz .. 150MHz. 01501 01502 @note For frequencies below 500kHz (down to 8kHz) Rx_DIV must be 01503 used, but this isn't currently implemented in the driver. 01504 */ 01505 /**************************************************************************/ 01506 err_t Adafruit_SI5351::setupMultisynth(uint8_t output, 01507 si5351PLL_t pllSource, 01508 uint32_t div, 01509 uint32_t num, 01510 uint32_t denom) 01511 { 01512 uint32_t P1; /* Multisynth config register P1 */ 01513 uint32_t P2; /* Multisynth config register P2 */ 01514 uint32_t P3; /* Multisynth config register P3 */ 01515 01516 /* Basic validation */ 01517 ASSERT( m_si5351Config.initialised, ERROR_DEVICENOTINITIALISED); 01518 ASSERT( output < 3, ERROR_INVALIDPARAMETER); /* Channel range */ 01519 ASSERT( div > 3, ERROR_INVALIDPARAMETER); /* Divider integer value */ 01520 ASSERT( div < 901, ERROR_INVALIDPARAMETER); /* Divider integer value */ 01521 ASSERT( denom > 0, ERROR_INVALIDPARAMETER ); /* Avoid divide by zero */ 01522 ASSERT( num <= 0xFFFFF, ERROR_INVALIDPARAMETER ); /* 20-bit limit */ 01523 ASSERT( denom <= 0xFFFFF, ERROR_INVALIDPARAMETER ); /* 20-bit limit */ 01524 01525 /* Make sure the requested PLL has been initialised */ 01526 if (pllSource == SI5351_PLL_A) 01527 { 01528 ASSERT(m_si5351Config.plla_configured = true, ERROR_INVALIDPARAMETER); 01529 } 01530 else 01531 { 01532 ASSERT(m_si5351Config.pllb_configured = true, ERROR_INVALIDPARAMETER); 01533 } 01534 01535 /* Output Multisynth Divider Equations 01536 * 01537 * where: a = div, b = num and c = denom 01538 * 01539 * P1 register is an 18-bit value using following formula: 01540 * 01541 * P1[17:0] = 128 * a + floor(128*(b/c)) - 512 01542 * 01543 * P2 register is a 20-bit value using the following formula: 01544 * 01545 * P2[19:0] = 128 * b - c * floor(128*(b/c)) 01546 * 01547 * P3 register is a 20-bit value using the following formula: 01548 * 01549 * P3[19:0] = c 01550 */ 01551 01552 /* Set the main PLL config registers */ 01553 if (num == 0) 01554 { 01555 /* Integer mode */ 01556 P1 = 128 * div - 512; 01557 P2 = num; 01558 P3 = denom; 01559 } 01560 else 01561 { 01562 /* Fractional mode */ 01563 P1 = (uint32_t)(128 * div + floor(128 * ((float)num/(float)denom)) - 512); 01564 P2 = (uint32_t)(128 * num - denom * floor(128 * ((float)num/(float)denom))); 01565 P3 = denom; 01566 } 01567 01568 /* Get the appropriate starting point for the PLL registers */ 01569 uint8_t baseaddr = 0; 01570 switch (output) 01571 { 01572 case 0: 01573 baseaddr = SI5351_REGISTER_42_MULTISYNTH0_PARAMETERS_1; 01574 break; 01575 case 1: 01576 baseaddr = SI5351_REGISTER_50_MULTISYNTH1_PARAMETERS_1; 01577 break; 01578 case 2: 01579 baseaddr = SI5351_REGISTER_58_MULTISYNTH2_PARAMETERS_1; 01580 break; 01581 } 01582 01583 /* Set the MSx config registers */ 01584 ASSERT_STATUS( write8( baseaddr, (P3 & 0x0000FF00) >> 8)); 01585 ASSERT_STATUS( write8( baseaddr+1, (P3 & 0x000000FF))); 01586 ASSERT_STATUS( write8( baseaddr+2, (P1 & 0x00030000) >> 16)); /* ToDo: Add DIVBY4 (>150MHz) and R0 support (<500kHz) later */ 01587 ASSERT_STATUS( write8( baseaddr+3, (P1 & 0x0000FF00) >> 8)); 01588 ASSERT_STATUS( write8( baseaddr+4, (P1 & 0x000000FF))); 01589 ASSERT_STATUS( write8( baseaddr+5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16) )); 01590 ASSERT_STATUS( write8( baseaddr+6, (P2 & 0x0000FF00) >> 8)); 01591 ASSERT_STATUS( write8( baseaddr+7, (P2 & 0x000000FF))); 01592 01593 /* Configure the clk control and enable the output */ 01594 uint8_t clkControlReg = 0x0F; /* 8mA drive strength, MS0 as CLK0 source, Clock not inverted, powered up */ 01595 if (pllSource == SI5351_PLL_B) clkControlReg |= (1 << 5); /* Uses PLLB */ 01596 if (num == 0) clkControlReg |= (1 << 6); /* Integer mode */ 01597 switch (output) 01598 { 01599 case 0: 01600 ASSERT_STATUS(write8(SI5351_REGISTER_16_CLK0_CONTROL, clkControlReg)); 01601 break; 01602 case 1: 01603 ASSERT_STATUS(write8(SI5351_REGISTER_17_CLK1_CONTROL, clkControlReg)); 01604 break; 01605 case 2: 01606 ASSERT_STATUS(write8(SI5351_REGISTER_18_CLK2_CONTROL, clkControlReg)); 01607 break; 01608 } 01609 01610 return ERROR_NONE; 01611 } 01612 01613 /**************************************************************************/ 01614 /*! 01615 @brief Enables or disables all clock outputs 01616 */ 01617 /**************************************************************************/ 01618 err_t Adafruit_SI5351::enableOutputs(bool enabled) 01619 { 01620 /* Make sure we've called init first */ 01621 ASSERT(m_si5351Config.initialised, ERROR_DEVICENOTINITIALISED); 01622 01623 /* Enabled desired outputs (see Register 3) */ 01624 ASSERT_STATUS(write8(SI5351_REGISTER_3_OUTPUT_ENABLE_CONTROL, enabled ? 0x00: 0xFF)); 01625 01626 return ERROR_NONE; 01627 } 01628 01629 /* ---------------------------------------------------------------------- */ 01630 /* PRUVATE FUNCTIONS */ 01631 /* ---------------------------------------------------------------------- */ 01632 01633 /**************************************************************************/ 01634 /*! 01635 @brief Writes a register and an 8 bit value over I2C 01636 */ 01637 /**************************************************************************/ 01638 err_t Adafruit_SI5351::write8 (uint8_t reg, uint8_t value) 01639 { 01640 Wire.beginTransmission(SI5351_ADDRESS); 01641 #if ARDUINO >= 100 01642 Wire.write(reg); 01643 Wire.write(value & 0xFF); 01644 #else 01645 Wire.send(reg); 01646 Wire.send(value & 0xFF); 01647 #endif 01648 Wire.endTransmission(); 01649 01650 // ToDo: Check for I2C errors 01651 01652 return ERROR_NONE; 01653 } 01654 01655 /**************************************************************************/ 01656 /*! 01657 @brief Reads an 8 bit value over I2C 01658 */ 01659 /**************************************************************************/ 01660 err_t Adafruit_SI5351::read8(uint8_t reg, uint8_t *value) 01661 { 01662 Wire.beginTransmission(SI5351_ADDRESS); 01663 #if ARDUINO >= 100 01664 Wire.write(reg); 01665 #else 01666 Wire.send(reg); 01667 #endif 01668 Wire.endTransmission(); 01669 01670 Wire.requestFrom(SI5351_ADDRESS, 1); 01671 #if ARDUINO >= 100 01672 *value = Wire.read(); 01673 #else 01674 *value = Wire.read(); 01675 #endif 01676 01677 // ToDo: Check for I2C errors 01678 01679 return ERROR_NONE; 01680 } 01681 01682 #endif 01683 01684 //////////////////////////////////////////////////////////////////////////////// 01685 // Adafruit_SI5351.h 01686 //////////////////////////////////////////////////////////////////////////////// 01687 #if 0 01688 /**************************************************************************/ 01689 /*! 01690 @file Adafruit_SI5351.h 01691 @author K. Townsend (Adafruit Industries) 01692 01693 @section LICENSE 01694 01695 Software License Agreement (BSD License) 01696 01697 Copyright (c) 2014, Adafruit Industries 01698 All rights reserved. 01699 01700 Redistribution and use in source and binary forms, with or without 01701 modification, are permitted provided that the following conditions are met: 01702 1. Redistributions of source code must retain the above copyright 01703 notice, this list of conditions and the following disclaimer. 01704 2. Redistributions in binary form must reproduce the above copyright 01705 notice, this list of conditions and the following disclaimer in the 01706 documentation and/or other materials provided with the distribution. 01707 3. Neither the name of the copyright holders nor the 01708 names of its contributors may be used to endorse or promote products 01709 derived from this software without specific prior written permission. 01710 01711 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 01712 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 01713 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 01714 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 01715 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 01716 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 01717 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 01718 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 01719 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 01720 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 01721 */ 01722 /**************************************************************************/ 01723 #ifndef _SI5351_H_ 01724 #define _SI5351_H_ 01725 01726 #if ARDUINO >= 100 01727 #include <Arduino.h> 01728 #else 01729 #include <WProgram.h> 01730 #endif 01731 //#include <Adafruit_Sensor.h> 01732 #include <Wire.h> 01733 01734 #include "errors.h" 01735 #include "asserts.h" 01736 01737 #define SI5351_ADDRESS (0x60) // Assumes ADDR pin = low 01738 #define SI5351_READBIT (0x01) 01739 01740 /* Test setup from SI5351 ClockBuilder 01741 * ----------------------------------- 01742 * XTAL: 25 MHz 01743 * Channel 0: 120.00 MHz 01744 * Channel 1: 12.00 MHz 01745 * Channel 2: 13.56 MHz 01746 */ 01747 static const uint8_t m_si5351_regs_15to92_149to170[100][2] = 01748 { 01749 { 15, 0x00 }, /* Input source = crystal for PLLA and PLLB */ 01750 { 16, 0x4F }, /* CLK0 Control: 8mA drive, Multisynth 0 as CLK0 source, Clock not inverted, Source = PLLA, Multisynth 0 in integer mode, clock powered up */ 01751 { 17, 0x4F }, /* CLK1 Control: 8mA drive, Multisynth 1 as CLK1 source, Clock not inverted, Source = PLLA, Multisynth 1 in integer mode, clock powered up */ 01752 { 18, 0x6F }, /* CLK2 Control: 8mA drive, Multisynth 2 as CLK2 source, Clock not inverted, Source = PLLB, Multisynth 2 in integer mode, clock powered up */ 01753 { 19, 0x80 }, /* CLK3 Control: Not used ... clock powered down */ 01754 { 20, 0x80 }, /* CLK4 Control: Not used ... clock powered down */ 01755 { 21, 0x80 }, /* CLK5 Control: Not used ... clock powered down */ 01756 { 22, 0x80 }, /* CLK6 Control: Not used ... clock powered down */ 01757 { 23, 0x80 }, /* CLK7 Control: Not used ... clock powered down */ 01758 { 24, 0x00 }, /* Clock disable state 0..3 (low when disabled) */ 01759 { 25, 0x00 }, /* Clock disable state 4..7 (low when disabled) */ 01760 /* PLL_A Setup */ 01761 { 26, 0x00 }, 01762 { 27, 0x05 }, 01763 { 28, 0x00 }, 01764 { 29, 0x0C }, 01765 { 30, 0x66 }, 01766 { 31, 0x00 }, 01767 { 32, 0x00 }, 01768 { 33, 0x02 }, 01769 /* PLL_B Setup */ 01770 { 34, 0x02 }, 01771 { 35, 0x71 }, 01772 { 36, 0x00 }, 01773 { 37, 0x0C }, 01774 { 38, 0x1A }, 01775 { 39, 0x00 }, 01776 { 40, 0x00 }, 01777 { 41, 0x86 }, 01778 /* Multisynth Setup */ 01779 { 42, 0x00 }, 01780 { 43, 0x01 }, 01781 { 44, 0x00 }, 01782 { 45, 0x01 }, 01783 { 46, 0x00 }, 01784 { 47, 0x00 }, 01785 { 48, 0x00 }, 01786 { 49, 0x00 }, 01787 { 50, 0x00 }, 01788 { 51, 0x01 }, 01789 { 52, 0x00 }, 01790 { 53, 0x1C }, 01791 { 54, 0x00 }, 01792 { 55, 0x00 }, 01793 { 56, 0x00 }, 01794 { 57, 0x00 }, 01795 { 58, 0x00 }, 01796 { 59, 0x01 }, 01797 { 60, 0x00 }, 01798 { 61, 0x18 }, 01799 { 62, 0x00 }, 01800 { 63, 0x00 }, 01801 { 64, 0x00 }, 01802 { 65, 0x00 }, 01803 { 66, 0x00 }, 01804 { 67, 0x00 }, 01805 { 68, 0x00 }, 01806 { 69, 0x00 }, 01807 { 70, 0x00 }, 01808 { 71, 0x00 }, 01809 { 72, 0x00 }, 01810 { 73, 0x00 }, 01811 { 74, 0x00 }, 01812 { 75, 0x00 }, 01813 { 76, 0x00 }, 01814 { 77, 0x00 }, 01815 { 78, 0x00 }, 01816 { 79, 0x00 }, 01817 { 80, 0x00 }, 01818 { 81, 0x00 }, 01819 { 82, 0x00 }, 01820 { 83, 0x00 }, 01821 { 84, 0x00 }, 01822 { 85, 0x00 }, 01823 { 86, 0x00 }, 01824 { 87, 0x00 }, 01825 { 88, 0x00 }, 01826 { 89, 0x00 }, 01827 { 90, 0x00 }, 01828 { 91, 0x00 }, 01829 { 92, 0x00 }, 01830 /* Misc Config Register */ 01831 { 149, 0x00 }, 01832 { 150, 0x00 }, 01833 { 151, 0x00 }, 01834 { 152, 0x00 }, 01835 { 153, 0x00 }, 01836 { 154, 0x00 }, 01837 { 155, 0x00 }, 01838 { 156, 0x00 }, 01839 { 157, 0x00 }, 01840 { 158, 0x00 }, 01841 { 159, 0x00 }, 01842 { 160, 0x00 }, 01843 { 161, 0x00 }, 01844 { 162, 0x00 }, 01845 { 163, 0x00 }, 01846 { 164, 0x00 }, 01847 { 165, 0x00 }, 01848 { 166, 0x00 }, 01849 { 167, 0x00 }, 01850 { 168, 0x00 }, 01851 { 169, 0x00 }, 01852 { 170, 0x00 } 01853 }; 01854 01855 /* See http://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf for registers 26..41 */ 01856 enum 01857 { 01858 SI5351_REGISTER_0_DEVICE_STATUS = 0, 01859 SI5351_REGISTER_1_INTERRUPT_STATUS_STICKY = 1, 01860 SI5351_REGISTER_2_INTERRUPT_STATUS_MASK = 2, 01861 SI5351_REGISTER_3_OUTPUT_ENABLE_CONTROL = 3, 01862 SI5351_REGISTER_9_OEB_PIN_ENABLE_CONTROL = 9, 01863 SI5351_REGISTER_15_PLL_INPUT_SOURCE = 15, 01864 SI5351_REGISTER_16_CLK0_CONTROL = 16, 01865 SI5351_REGISTER_17_CLK1_CONTROL = 17, 01866 SI5351_REGISTER_18_CLK2_CONTROL = 18, 01867 SI5351_REGISTER_19_CLK3_CONTROL = 19, 01868 SI5351_REGISTER_20_CLK4_CONTROL = 20, 01869 SI5351_REGISTER_21_CLK5_CONTROL = 21, 01870 SI5351_REGISTER_22_CLK6_CONTROL = 22, 01871 SI5351_REGISTER_23_CLK7_CONTROL = 23, 01872 SI5351_REGISTER_24_CLK3_0_DISABLE_STATE = 24, 01873 SI5351_REGISTER_25_CLK7_4_DISABLE_STATE = 25, 01874 SI5351_REGISTER_42_MULTISYNTH0_PARAMETERS_1 = 42, 01875 SI5351_REGISTER_43_MULTISYNTH0_PARAMETERS_2 = 43, 01876 SI5351_REGISTER_44_MULTISYNTH0_PARAMETERS_3 = 44, 01877 SI5351_REGISTER_45_MULTISYNTH0_PARAMETERS_4 = 45, 01878 SI5351_REGISTER_46_MULTISYNTH0_PARAMETERS_5 = 46, 01879 SI5351_REGISTER_47_MULTISYNTH0_PARAMETERS_6 = 47, 01880 SI5351_REGISTER_48_MULTISYNTH0_PARAMETERS_7 = 48, 01881 SI5351_REGISTER_49_MULTISYNTH0_PARAMETERS_8 = 49, 01882 SI5351_REGISTER_50_MULTISYNTH1_PARAMETERS_1 = 50, 01883 SI5351_REGISTER_51_MULTISYNTH1_PARAMETERS_2 = 51, 01884 SI5351_REGISTER_52_MULTISYNTH1_PARAMETERS_3 = 52, 01885 SI5351_REGISTER_53_MULTISYNTH1_PARAMETERS_4 = 53, 01886 SI5351_REGISTER_54_MULTISYNTH1_PARAMETERS_5 = 54, 01887 SI5351_REGISTER_55_MULTISYNTH1_PARAMETERS_6 = 55, 01888 SI5351_REGISTER_56_MULTISYNTH1_PARAMETERS_7 = 56, 01889 SI5351_REGISTER_57_MULTISYNTH1_PARAMETERS_8 = 57, 01890 SI5351_REGISTER_58_MULTISYNTH2_PARAMETERS_1 = 58, 01891 SI5351_REGISTER_59_MULTISYNTH2_PARAMETERS_2 = 59, 01892 SI5351_REGISTER_60_MULTISYNTH2_PARAMETERS_3 = 60, 01893 SI5351_REGISTER_61_MULTISYNTH2_PARAMETERS_4 = 61, 01894 SI5351_REGISTER_62_MULTISYNTH2_PARAMETERS_5 = 62, 01895 SI5351_REGISTER_63_MULTISYNTH2_PARAMETERS_6 = 63, 01896 SI5351_REGISTER_64_MULTISYNTH2_PARAMETERS_7 = 64, 01897 SI5351_REGISTER_65_MULTISYNTH2_PARAMETERS_8 = 65, 01898 SI5351_REGISTER_66_MULTISYNTH3_PARAMETERS_1 = 66, 01899 SI5351_REGISTER_67_MULTISYNTH3_PARAMETERS_2 = 67, 01900 SI5351_REGISTER_68_MULTISYNTH3_PARAMETERS_3 = 68, 01901 SI5351_REGISTER_69_MULTISYNTH3_PARAMETERS_4 = 69, 01902 SI5351_REGISTER_70_MULTISYNTH3_PARAMETERS_5 = 70, 01903 SI5351_REGISTER_71_MULTISYNTH3_PARAMETERS_6 = 71, 01904 SI5351_REGISTER_72_MULTISYNTH3_PARAMETERS_7 = 72, 01905 SI5351_REGISTER_73_MULTISYNTH3_PARAMETERS_8 = 73, 01906 SI5351_REGISTER_74_MULTISYNTH4_PARAMETERS_1 = 74, 01907 SI5351_REGISTER_75_MULTISYNTH4_PARAMETERS_2 = 75, 01908 SI5351_REGISTER_76_MULTISYNTH4_PARAMETERS_3 = 76, 01909 SI5351_REGISTER_77_MULTISYNTH4_PARAMETERS_4 = 77, 01910 SI5351_REGISTER_78_MULTISYNTH4_PARAMETERS_5 = 78, 01911 SI5351_REGISTER_79_MULTISYNTH4_PARAMETERS_6 = 79, 01912 SI5351_REGISTER_80_MULTISYNTH4_PARAMETERS_7 = 80, 01913 SI5351_REGISTER_81_MULTISYNTH4_PARAMETERS_8 = 81, 01914 SI5351_REGISTER_82_MULTISYNTH5_PARAMETERS_1 = 82, 01915 SI5351_REGISTER_83_MULTISYNTH5_PARAMETERS_2 = 83, 01916 SI5351_REGISTER_84_MULTISYNTH5_PARAMETERS_3 = 84, 01917 SI5351_REGISTER_85_MULTISYNTH5_PARAMETERS_4 = 85, 01918 SI5351_REGISTER_86_MULTISYNTH5_PARAMETERS_5 = 86, 01919 SI5351_REGISTER_87_MULTISYNTH5_PARAMETERS_6 = 87, 01920 SI5351_REGISTER_88_MULTISYNTH5_PARAMETERS_7 = 88, 01921 SI5351_REGISTER_89_MULTISYNTH5_PARAMETERS_8 = 89, 01922 SI5351_REGISTER_90_MULTISYNTH6_PARAMETERS = 90, 01923 SI5351_REGISTER_91_MULTISYNTH7_PARAMETERS = 91, 01924 SI5351_REGISTER_092_CLOCK_6_7_OUTPUT_DIVIDER = 92, 01925 SI5351_REGISTER_165_CLK0_INITIAL_PHASE_OFFSET = 165, 01926 SI5351_REGISTER_166_CLK1_INITIAL_PHASE_OFFSET = 166, 01927 SI5351_REGISTER_167_CLK2_INITIAL_PHASE_OFFSET = 167, 01928 SI5351_REGISTER_168_CLK3_INITIAL_PHASE_OFFSET = 168, 01929 SI5351_REGISTER_169_CLK4_INITIAL_PHASE_OFFSET = 169, 01930 SI5351_REGISTER_170_CLK5_INITIAL_PHASE_OFFSET = 170, 01931 SI5351_REGISTER_177_PLL_RESET = 177, 01932 SI5351_REGISTER_183_CRYSTAL_INTERNAL_LOAD_CAPACITANCE = 183 01933 }; 01934 01935 typedef enum 01936 { 01937 SI5351_PLL_A = 0, 01938 SI5351_PLL_B, 01939 } si5351PLL_t; 01940 01941 typedef enum 01942 { 01943 SI5351_CRYSTAL_LOAD_6PF = (1<<6), 01944 SI5351_CRYSTAL_LOAD_8PF = (2<<6), 01945 SI5351_CRYSTAL_LOAD_10PF = (3<<6) 01946 } si5351CrystalLoad_t; 01947 01948 typedef enum 01949 { 01950 SI5351_CRYSTAL_FREQ_25MHZ = (25000000), 01951 SI5351_CRYSTAL_FREQ_27MHZ = (27000000) 01952 } si5351CrystalFreq_t; 01953 01954 typedef enum 01955 { 01956 SI5351_MULTISYNTH_DIV_4 = 4, 01957 SI5351_MULTISYNTH_DIV_6 = 6, 01958 SI5351_MULTISYNTH_DIV_8 = 8 01959 } si5351MultisynthDiv_t; 01960 01961 typedef enum 01962 { 01963 SI5351_R_DIV_1 = 0, 01964 SI5351_R_DIV_2 = 1, 01965 SI5351_R_DIV_4 = 2, 01966 SI5351_R_DIV_8 = 3, 01967 SI5351_R_DIV_16 = 4, 01968 SI5351_R_DIV_32 = 5, 01969 SI5351_R_DIV_64 = 6, 01970 SI5351_R_DIV_128 = 7, 01971 } si5351RDiv_t; 01972 01973 typedef struct 01974 { 01975 bool initialised; 01976 si5351CrystalFreq_t crystalFreq; 01977 si5351CrystalLoad_t crystalLoad; 01978 uint32_t crystalPPM; 01979 bool plla_configured; 01980 uint32_t plla_freq; 01981 bool pllb_configured; 01982 uint32_t pllb_freq; 01983 } si5351Config_t; 01984 01985 class Adafruit_SI5351 01986 { 01987 public: 01988 Adafruit_SI5351(void); 01989 01990 err_t begin(void); 01991 err_t setClockBuilderData(void); 01992 err_t setupPLL(si5351PLL_t pll, uint8_t mult, uint32_t num, uint32_t denom); 01993 err_t setupPLLInt(si5351PLL_t pll, uint8_t mult); 01994 err_t setupMultisynth(uint8_t output, si5351PLL_t pllSource, uint32_t div, uint32_t num, uint32_t denom); 01995 err_t setupMultisynthInt(uint8_t output, si5351PLL_t pllSource, si5351MultisynthDiv_t div); 01996 err_t enableOutputs(bool enabled); 01997 err_t setupRdiv(uint8_t output, si5351RDiv_t div); 01998 01999 private: 02000 si5351Config_t m_si5351Config; 02001 02002 err_t write8(uint8_t reg, uint8_t value); 02003 err_t read8(uint8_t reg, uint8_t *value); 02004 }; 02005 02006 #endif 02007 02008 #endif 02009 // 02010
Generated on Fri Jul 15 2022 10:58:14 by
