Kenji Arai / Si5351A

Dependents:   clockGenerator Check_Si5351A_Clock_generator t2d Thing2Do ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers si5351a.cpp Source File

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, &regval);
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