Silicon Laboratories Inc. Si5351A-B-GT I2C-PROGRAMMABLE ANY-FREQUENCY CMOS CLOCK GENERATOR

Dependents:   clockGenerator Check_Si5351A_Clock_generator t2d Thing2Do ... more

Test program:
/users/kenjiArai/code/Check_Si5351A_Clock_generator/

Committer:
kenjiArai
Date:
Wed Aug 23 09:53:16 2017 +0000
Revision:
4:8c63d15c8c2e
Parent:
3:af2d99cfb3f0
countermeasure for  NonCopyable

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 0:47b9bfa03730 1 /*
kenjiArai 0:47b9bfa03730 2 * mbed Library / Silicon Laboratories Inc. Si5351A-B-GT
kenjiArai 0:47b9bfa03730 3 * I2C-PROGRAMMABLE ANY-FREQUENCY CMOS CLOCK GENERATOR
kenjiArai 0:47b9bfa03730 4 * https://www.silabs.com/products/
kenjiArai 0:47b9bfa03730 5 * timing/clock-generator/si535x/pages/Si5351A-B-GM.aspx
kenjiArai 0:47b9bfa03730 6 *
kenjiArai 0:47b9bfa03730 7 * Checked on Nucleo-F411RE & F401RE mbed board
kenjiArai 0:47b9bfa03730 8 *
kenjiArai 0:47b9bfa03730 9 * Original & Reference program:
kenjiArai 0:47b9bfa03730 10 * 1)
kenjiArai 0:47b9bfa03730 11 * https://github.com/adafruit/Adafruit_Si5351_Library
kenjiArai 0:47b9bfa03730 12 * see original source (bottom part of si5351a.cpp file)
kenjiArai 0:47b9bfa03730 13 * Software License Agreement (BSD License)
kenjiArai 0:47b9bfa03730 14 * Copyright (c) 2014, Adafruit Industries All rights reserved.
kenjiArai 0:47b9bfa03730 15 * 2)
kenjiArai 0:47b9bfa03730 16 * https://gist.github.com/edy555/f1ee7ef44fe4f5c6f7618ac4cbbe66fb
kenjiArai 0:47b9bfa03730 17 * made by TT@Hokkaido-san (edy555)
kenjiArai 0:47b9bfa03730 18 * http://ttrftech.tumblr.com/
kenjiArai 0:47b9bfa03730 19 * http://ttrftech.tumblr.com/post/150247113216/
kenjiArai 0:47b9bfa03730 20 * si5351a-configuration-how-to-and-signal-quality
kenjiArai 0:47b9bfa03730 21 *
kenjiArai 0:47b9bfa03730 22 * Modified by Kenji Arai / JH1PJL
kenjiArai 0:47b9bfa03730 23 * http://www.page.sannet.ne.jp/kenjia/index.html
kenjiArai 0:47b9bfa03730 24 * http://mbed.org/users/kenjiArai/
kenjiArai 0:47b9bfa03730 25 *
kenjiArai 0:47b9bfa03730 26 * Started: December 24th, 2016
kenjiArai 4:8c63d15c8c2e 27 * Revised: August 23rd, 2017
kenjiArai 0:47b9bfa03730 28 *
kenjiArai 0:47b9bfa03730 29 */
kenjiArai 0:47b9bfa03730 30
kenjiArai 0:47b9bfa03730 31 #include "mbed.h"
kenjiArai 0:47b9bfa03730 32 #include "si5351a.h"
kenjiArai 0:47b9bfa03730 33
kenjiArai 0:47b9bfa03730 34 #if 0 // Debug mode = 1
kenjiArai 0:47b9bfa03730 35 #define DEBUG
kenjiArai 0:47b9bfa03730 36 #endif
kenjiArai 0:47b9bfa03730 37
kenjiArai 0:47b9bfa03730 38 #if defined(DEBUG)
kenjiArai 0:47b9bfa03730 39 #define DBG(...) printf(__VA_ARGS__)
kenjiArai 0:47b9bfa03730 40 #else
kenjiArai 0:47b9bfa03730 41 #define DBG(...) {;}
kenjiArai 0:47b9bfa03730 42 #endif
kenjiArai 0:47b9bfa03730 43
kenjiArai 0:47b9bfa03730 44 #define PLL_N 32
kenjiArai 0:47b9bfa03730 45
kenjiArai 0:47b9bfa03730 46 SI5351A::SI5351A (PinName p_sda, PinName p_scl,
kenjiArai 0:47b9bfa03730 47 uint32_t base_clk_freq,
kenjiArai 0:47b9bfa03730 48 uint8_t xtal_cap,
kenjiArai 0:47b9bfa03730 49 uint8_t drive_current
kenjiArai 0:47b9bfa03730 50 )
kenjiArai 4:8c63d15c8c2e 51 : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
kenjiArai 0:47b9bfa03730 52 {
kenjiArai 0:47b9bfa03730 53 base_freq = base_clk_freq;
kenjiArai 0:47b9bfa03730 54 x_cap = xtal_cap;
kenjiArai 0:47b9bfa03730 55 drv_current = drive_current;
kenjiArai 0:47b9bfa03730 56 si5351_init();
kenjiArai 0:47b9bfa03730 57 }
kenjiArai 0:47b9bfa03730 58
kenjiArai 0:47b9bfa03730 59 SI5351A::SI5351A (I2C& p_i2c,
kenjiArai 0:47b9bfa03730 60 uint32_t base_clk_freq,
kenjiArai 0:47b9bfa03730 61 uint8_t xtal_cap,
kenjiArai 0:47b9bfa03730 62 uint8_t drive_current
kenjiArai 0:47b9bfa03730 63 )
kenjiArai 0:47b9bfa03730 64 : _i2c(p_i2c)
kenjiArai 0:47b9bfa03730 65 {
kenjiArai 0:47b9bfa03730 66 base_freq = base_clk_freq;
kenjiArai 0:47b9bfa03730 67 x_cap = xtal_cap;
kenjiArai 3:af2d99cfb3f0 68 drv_current = drive_current;
kenjiArai 0:47b9bfa03730 69 si5351_init();
kenjiArai 0:47b9bfa03730 70 }
kenjiArai 0:47b9bfa03730 71
kenjiArai 0:47b9bfa03730 72 /*
kenjiArai 3:af2d99cfb3f0 73 * 1~110MHz fixed PLL (XTAL * PLL_N)MHz, fractional divider
kenjiArai 3:af2d99cfb3f0 74 * 110~150MHz fractional PLL 600-900MHz, fixed divider 6
kenjiArai 0:47b9bfa03730 75 * 150~200MHz fractional PLL 600-900MHz, fixed divider 4
kenjiArai 0:47b9bfa03730 76 */
kenjiArai 0:47b9bfa03730 77 uint32_t SI5351A::set_frequency(uint8_t channel, uint32_t freq)
kenjiArai 0:47b9bfa03730 78 {
kenjiArai 0:47b9bfa03730 79 uint8_t pll;
kenjiArai 0:47b9bfa03730 80 double f;
kenjiArai 0:47b9bfa03730 81 uint8_t state;
kenjiArai 0:47b9bfa03730 82 if (channel == SI5351_CLK0){
kenjiArai 0:47b9bfa03730 83 pll = SI5351_PLL_A;
kenjiArai 0:47b9bfa03730 84 } else { // SI5351_CLK1 & SI5351_CLK2
kenjiArai 0:47b9bfa03730 85 pll = SI5351_PLL_B;
kenjiArai 0:47b9bfa03730 86 }
kenjiArai 0:47b9bfa03730 87 si5351_disable_output();
kenjiArai 3:af2d99cfb3f0 88 if (freq <= FREQ_110MHZ){
kenjiArai 0:47b9bfa03730 89 if((channel == SI5351_CLK1) && (clk2_state == CLK_OUT_FIXEDDIV)){
kenjiArai 3:af2d99cfb3f0 90 DBG("DBG: Error CLK2 uses as over 110MHz!!\r\n");
kenjiArai 0:47b9bfa03730 91 return 0;
kenjiArai 0:47b9bfa03730 92 } else if((channel == SI5351_CLK2) && (clk1_state == CLK_OUT_FIXEDDIV)){
kenjiArai 3:af2d99cfb3f0 93 DBG("DBG: Error CLK1 uses as over 110MHz!!\r\n");
kenjiArai 0:47b9bfa03730 94 return 0;
kenjiArai 0:47b9bfa03730 95 }
kenjiArai 0:47b9bfa03730 96 DBG("DBG: Passed condition\r\n");
kenjiArai 3:af2d99cfb3f0 97 if (freq > FREQ_450KHZ){ // over 450KHz to 110MHz
kenjiArai 3:af2d99cfb3f0 98 si5351_set_PLL_input_condition(FREQ_900MHZ);
kenjiArai 3:af2d99cfb3f0 99 si5351_setupPLL(pll, pll_n, 0, 1);
kenjiArai 0:47b9bfa03730 100 f = si5351_set_frequency_fixedpll(channel, pll, pll_freq, freq, 0);
kenjiArai 0:47b9bfa03730 101 } else if (freq > FREQ_75KHZ){
kenjiArai 3:af2d99cfb3f0 102 si5351_set_PLL_input_condition(FREQ_600MHZ);
kenjiArai 3:af2d99cfb3f0 103 si5351_setupPLL(pll, pll_n, 0, 1);
kenjiArai 0:47b9bfa03730 104 f = si5351_set_frequency_fixedpll(
kenjiArai 0:47b9bfa03730 105 channel, pll, pll_freq, freq * 8, SI5351_R_DIV_8);
kenjiArai 0:47b9bfa03730 106 f /= 8.0f;
kenjiArai 0:47b9bfa03730 107 } else if (freq > FREQ_20KHZ){
kenjiArai 3:af2d99cfb3f0 108 si5351_set_PLL_input_condition(FREQ_600MHZ);
kenjiArai 3:af2d99cfb3f0 109 si5351_setupPLL(pll, pll_n, 0, 1);
kenjiArai 0:47b9bfa03730 110 f = si5351_set_frequency_fixedpll(
kenjiArai 0:47b9bfa03730 111 channel, pll, pll_freq, freq * 32, SI5351_R_DIV_32);
kenjiArai 0:47b9bfa03730 112 f /= 32.0f;
kenjiArai 0:47b9bfa03730 113 } else {
kenjiArai 3:af2d99cfb3f0 114 si5351_set_PLL_input_condition(FREQ_600MHZ);
kenjiArai 3:af2d99cfb3f0 115 si5351_setupPLL(pll, pll_n, 0, 1);
kenjiArai 0:47b9bfa03730 116 f = si5351_set_frequency_fixedpll(
kenjiArai 0:47b9bfa03730 117 channel, pll, pll_freq, freq * 128, SI5351_R_DIV_128);
kenjiArai 3:af2d99cfb3f0 118 #if defined(RANGE_EXTENDED)
kenjiArai 3:af2d99cfb3f0 119 // CAUTION !!!!!!
kenjiArai 3:af2d99cfb3f0 120 if (f == 0){ // This part is outside of specification!!
kenjiArai 3:af2d99cfb3f0 121 DBG("DBG: Out of range but try again!\r\n");
kenjiArai 3:af2d99cfb3f0 122 pll_n = 15; // around 375MHz
kenjiArai 3:af2d99cfb3f0 123 pll_freq = base_freq * pll_n;
kenjiArai 3:af2d99cfb3f0 124 pll_freq = (uint32_t)((double)pll_freq / compensation);
kenjiArai 3:af2d99cfb3f0 125 si5351_setupPLL(pll, pll_n, 0, 1);
kenjiArai 3:af2d99cfb3f0 126 f = si5351_set_frequency_fixedpll(
kenjiArai 3:af2d99cfb3f0 127 channel, pll, pll_freq, freq * 128, SI5351_R_DIV_128);
kenjiArai 3:af2d99cfb3f0 128 }
kenjiArai 3:af2d99cfb3f0 129 #endif
kenjiArai 0:47b9bfa03730 130 f /= 128.0f;
kenjiArai 0:47b9bfa03730 131 }
kenjiArai 0:47b9bfa03730 132 state = CLK_OUT_FIXEDPLL;
kenjiArai 0:47b9bfa03730 133 } else {
kenjiArai 3:af2d99cfb3f0 134 DBG("DBG: Set over 110MHz clock\r\n");
kenjiArai 0:47b9bfa03730 135 if((channel == SI5351_CLK1) && (clk2_state == CLK_OUT_FIXEDPLL)){
kenjiArai 3:af2d99cfb3f0 136 DBG("DBG: Error CLK2 uses as under 110MHz!!\r\n");
kenjiArai 0:47b9bfa03730 137 return 0;
kenjiArai 0:47b9bfa03730 138 } else if((channel == SI5351_CLK2) && (clk1_state == CLK_OUT_FIXEDPLL)){
kenjiArai 3:af2d99cfb3f0 139 DBG("DBG: Error CLK1 uses as under 110MHz!!\r\n");
kenjiArai 0:47b9bfa03730 140 return 0;
kenjiArai 0:47b9bfa03730 141 }
kenjiArai 0:47b9bfa03730 142 DBG("DBG: Passed condition\r\n");
kenjiArai 0:47b9bfa03730 143 if (freq < FREQ_150MHZ) {
kenjiArai 3:af2d99cfb3f0 144 DBG("DBG: Set 110MHz to 150MHz clock\r\n");
kenjiArai 0:47b9bfa03730 145 f = si5351_set_frequency_fixeddiv(channel, pll, freq, 6);
kenjiArai 0:47b9bfa03730 146 } else {
kenjiArai 3:af2d99cfb3f0 147 #if defined(RANGE_EXTENDED)
kenjiArai 3:af2d99cfb3f0 148 DBG("DBG: Set over 150MHz clock (RANGE_EXTENDED)\r\n");
kenjiArai 3:af2d99cfb3f0 149 f = si5351_set_frequency_fixeddiv(channel, pll, freq, 4);
kenjiArai 3:af2d99cfb3f0 150 #else
kenjiArai 0:47b9bfa03730 151 DBG("DBG: Set over 150MHz clock\r\n");
kenjiArai 3:af2d99cfb3f0 152 if (freq > FREQ_200MHZ) {
kenjiArai 3:af2d99cfb3f0 153 DBG("DBG: Over 200MHz\r\n");
kenjiArai 3:af2d99cfb3f0 154 f = 0;
kenjiArai 3:af2d99cfb3f0 155 } else {
kenjiArai 3:af2d99cfb3f0 156 f = si5351_set_frequency_fixeddiv(channel, pll, freq, 4);
kenjiArai 3:af2d99cfb3f0 157 }
kenjiArai 3:af2d99cfb3f0 158 #endif
kenjiArai 0:47b9bfa03730 159 }
kenjiArai 0:47b9bfa03730 160 state = CLK_OUT_FIXEDDIV;
kenjiArai 0:47b9bfa03730 161 }
kenjiArai 0:47b9bfa03730 162 si5351_enable_output();
kenjiArai 0:47b9bfa03730 163 if (channel == SI5351_CLK0){
kenjiArai 0:47b9bfa03730 164 clk0_state = state;
kenjiArai 0:47b9bfa03730 165 clk0_freq = f;
kenjiArai 0:47b9bfa03730 166 } else if (channel == SI5351_CLK1){
kenjiArai 0:47b9bfa03730 167 clk1_state = state;
kenjiArai 0:47b9bfa03730 168 clk1_freq = f;
kenjiArai 0:47b9bfa03730 169 } else {
kenjiArai 0:47b9bfa03730 170 clk2_state = state;
kenjiArai 0:47b9bfa03730 171 clk2_freq = f;
kenjiArai 0:47b9bfa03730 172 }
kenjiArai 0:47b9bfa03730 173 DBG("DBG: freq./ Target=%u,Set=%0.1f,diff=%.0f\r\n",
kenjiArai 0:47b9bfa03730 174 freq, f, (double)freq - f);
kenjiArai 0:47b9bfa03730 175 return (uint32_t)f;
kenjiArai 0:47b9bfa03730 176 }
kenjiArai 0:47b9bfa03730 177
kenjiArai 0:47b9bfa03730 178 uint32_t SI5351A::shift_freq(uint8_t channel, int32_t diff)
kenjiArai 0:47b9bfa03730 179 {
kenjiArai 0:47b9bfa03730 180 double f;
kenjiArai 0:47b9bfa03730 181 uint32_t f_err;
kenjiArai 0:47b9bfa03730 182 // Check current status
kenjiArai 0:47b9bfa03730 183 if (channel == SI5351_CLK0){
kenjiArai 0:47b9bfa03730 184 f = clk0_freq;
kenjiArai 0:47b9bfa03730 185 f_err = (uint32_t)f;
kenjiArai 0:47b9bfa03730 186 if ((clk0_state == CLK_OUT_NOT_USED)
kenjiArai 0:47b9bfa03730 187 || (clk0_state == CLK_OUT_FIXEDDIV)){
kenjiArai 3:af2d99cfb3f0 188 DBG("DBG: error over 110MHz\r\n");
kenjiArai 0:47b9bfa03730 189 return f_err; // return current frequency
kenjiArai 0:47b9bfa03730 190 }
kenjiArai 0:47b9bfa03730 191 } else if (channel == SI5351_CLK1){
kenjiArai 0:47b9bfa03730 192 f = clk1_freq;
kenjiArai 0:47b9bfa03730 193 f_err = (uint32_t)f;
kenjiArai 0:47b9bfa03730 194 if ((clk1_state == CLK_OUT_NOT_USED)
kenjiArai 0:47b9bfa03730 195 || (clk1_state == CLK_OUT_FIXEDDIV)){
kenjiArai 3:af2d99cfb3f0 196 DBG("DBG: error over 110MHz\r\n");
kenjiArai 0:47b9bfa03730 197 return f_err; // return current frequency
kenjiArai 0:47b9bfa03730 198 }
kenjiArai 0:47b9bfa03730 199 } else if (channel == SI5351_CLK2){
kenjiArai 0:47b9bfa03730 200 f = clk2_freq;
kenjiArai 0:47b9bfa03730 201 f_err = (uint32_t)f;
kenjiArai 0:47b9bfa03730 202 if ((clk2_state == CLK_OUT_NOT_USED)
kenjiArai 0:47b9bfa03730 203 || (clk2_state == CLK_OUT_FIXEDDIV)){
kenjiArai 3:af2d99cfb3f0 204 DBG("DBG: error over 110MHz\r\n");
kenjiArai 0:47b9bfa03730 205 return f_err; // return current frequency
kenjiArai 0:47b9bfa03730 206 }
kenjiArai 0:47b9bfa03730 207 } else {
kenjiArai 0:47b9bfa03730 208 return 0;
kenjiArai 0:47b9bfa03730 209 }
kenjiArai 0:47b9bfa03730 210 // set new frequency
kenjiArai 0:47b9bfa03730 211 double f_tatget = f + (double)diff;
kenjiArai 0:47b9bfa03730 212 uint32_t freq = (uint32_t)f_tatget;
kenjiArai 0:47b9bfa03730 213 DBG("DBG: Target F=%u\r\n", freq);
kenjiArai 3:af2d99cfb3f0 214 // only range between 1MHz to 110MHz
kenjiArai 3:af2d99cfb3f0 215 if ((freq > FREQ_110MHZ) || (freq < FREQ_450KHZ)){// between 450KHz-110MHz
kenjiArai 0:47b9bfa03730 216 DBG("DBG: Out of range\r\n");
kenjiArai 0:47b9bfa03730 217 return f_err; // return current frequency
kenjiArai 0:47b9bfa03730 218 }
kenjiArai 0:47b9bfa03730 219 uint32_t div = (floor)((double)pll_freq / (double)freq);
kenjiArai 0:47b9bfa03730 220 uint32_t num = pll_freq - freq * div;
kenjiArai 0:47b9bfa03730 221 uint32_t denom = freq;
kenjiArai 0:47b9bfa03730 222 uint32_t k = gcd(num, denom);
kenjiArai 0:47b9bfa03730 223 num /= k;
kenjiArai 0:47b9bfa03730 224 denom /= k;
kenjiArai 0:47b9bfa03730 225 while (denom >= (1<<20)) {
kenjiArai 0:47b9bfa03730 226 num >>= 1;
kenjiArai 0:47b9bfa03730 227 denom >>= 1;
kenjiArai 0:47b9bfa03730 228 }
kenjiArai 0:47b9bfa03730 229 if (denom == 0){ // Avoid divide by zero
kenjiArai 0:47b9bfa03730 230 DBG("DBG: error demon=0\r\n");
kenjiArai 0:47b9bfa03730 231 return f_err; // return current frequency
kenjiArai 0:47b9bfa03730 232 }
kenjiArai 0:47b9bfa03730 233 if (num >=0x100000){ // 20-bit limit
kenjiArai 0:47b9bfa03730 234 DBG("DBG: error num over 20bit\r\n");
kenjiArai 0:47b9bfa03730 235 return f_err; // return current frequency
kenjiArai 3:af2d99cfb3f0 236 }
kenjiArai 0:47b9bfa03730 237 if (denom >=0x100000){ // 20-bit limit
kenjiArai 0:47b9bfa03730 238 DBG("DBG: error denom over 20bit\r\n");
kenjiArai 0:47b9bfa03730 239 return f_err; // return current frequency
kenjiArai 0:47b9bfa03730 240 }
kenjiArai 0:47b9bfa03730 241 uint32_t P1, P2, P3;
kenjiArai 0:47b9bfa03730 242 double multisynth_double;
kenjiArai 0:47b9bfa03730 243 const uint8_t msreg_base[] = {
kenjiArai 0:47b9bfa03730 244 SI5351_REG_42_MULTISYNTH0,
kenjiArai 0:47b9bfa03730 245 SI5351_REG_50_MULTISYNTH1,
kenjiArai 0:47b9bfa03730 246 SI5351_REG_58_MULTISYNTH2,
kenjiArai 0:47b9bfa03730 247 };
kenjiArai 0:47b9bfa03730 248 uint8_t baseaddr = msreg_base[channel];
kenjiArai 0:47b9bfa03730 249 // Fractional mode
kenjiArai 1:a2309757c450 250 P1 = (uint32_t)(128 * div + floor(128 * ((float)num/(float)denom)) - 512);
kenjiArai 1:a2309757c450 251 P2 = (uint32_t)(128 * num - denom * floor(128 * ((float)num/(float)denom)));
kenjiArai 0:47b9bfa03730 252 P3 = denom;
kenjiArai 0:47b9bfa03730 253 multisynth_double = div + (double)num /(double)denom;
kenjiArai 0:47b9bfa03730 254 // a + b/c between 6..1800
kenjiArai 0:47b9bfa03730 255 if ((multisynth_double < 6.0f) || (multisynth_double > 1800.0f)){
kenjiArai 0:47b9bfa03730 256 DBG("DBG: error multisynth less 6 or over 1800\r\n");
kenjiArai 0:47b9bfa03730 257 return f_err; // return current frequency
kenjiArai 0:47b9bfa03730 258 }
kenjiArai 0:47b9bfa03730 259 DBG("DBG: CLK%u: PLL=%u,div=%u,num=%u,denom=%u\r\n",
kenjiArai 0:47b9bfa03730 260 channel, pll_freq, div, num, denom);
kenjiArai 0:47b9bfa03730 261 // Set the MSx config registers
kenjiArai 0:47b9bfa03730 262 si5351_write(baseaddr, (P3 & 0x0000ff00) >> 8);
kenjiArai 0:47b9bfa03730 263 si5351_write(baseaddr+1, (P3 & 0x000000ff));
kenjiArai 0:47b9bfa03730 264 si5351_write(baseaddr+2, (P1 & 0x00030000) >> 16);
kenjiArai 0:47b9bfa03730 265 si5351_write(baseaddr+3, (P1 & 0x0000ff00) >> 8);
kenjiArai 0:47b9bfa03730 266 si5351_write(baseaddr+4, (P1 & 0x000000ff));
kenjiArai 0:47b9bfa03730 267 si5351_write(baseaddr+5,
kenjiArai 0:47b9bfa03730 268 ((P3 & 0x000f0000) >> 12) | ((P2 & 0x000f0000) >> 16));
kenjiArai 0:47b9bfa03730 269 si5351_write(baseaddr+6, (P2 & 0x0000ff00) >> 8);
kenjiArai 0:47b9bfa03730 270 si5351_write(baseaddr+7, (P2 & 0x000000ff));
kenjiArai 0:47b9bfa03730 271 f = (double)pll_freq / multisynth_double;
kenjiArai 0:47b9bfa03730 272 if (channel == SI5351_CLK0){
kenjiArai 0:47b9bfa03730 273 clk0_freq = f;
kenjiArai 0:47b9bfa03730 274 } else if (channel == SI5351_CLK1){
kenjiArai 0:47b9bfa03730 275 clk1_freq = f;
kenjiArai 0:47b9bfa03730 276 } else { // SI5351_CLK2
kenjiArai 0:47b9bfa03730 277 clk2_freq = f;
kenjiArai 0:47b9bfa03730 278 }
kenjiArai 0:47b9bfa03730 279 return (uint32_t)f;
kenjiArai 0:47b9bfa03730 280 }
kenjiArai 0:47b9bfa03730 281
kenjiArai 0:47b9bfa03730 282 uint32_t SI5351A::read_freq(uint8_t channel)
kenjiArai 0:47b9bfa03730 283 {
kenjiArai 0:47b9bfa03730 284 if (channel == SI5351_CLK0){
kenjiArai 0:47b9bfa03730 285 return (uint32_t)clk0_freq;
kenjiArai 0:47b9bfa03730 286 } else if (channel == SI5351_CLK1){
kenjiArai 0:47b9bfa03730 287 return (uint32_t)clk1_freq;
kenjiArai 0:47b9bfa03730 288 } else { // SI5351_CLK2
kenjiArai 0:47b9bfa03730 289 return (uint32_t)clk2_freq;
kenjiArai 0:47b9bfa03730 290 }
kenjiArai 0:47b9bfa03730 291 }
kenjiArai 0:47b9bfa03730 292
kenjiArai 2:8fe745836ea6 293 void SI5351A::f_compensation(uint32_t target_f, uint32_t measured_f)
kenjiArai 2:8fe745836ea6 294 {
kenjiArai 3:af2d99cfb3f0 295 double new_comp_data;
kenjiArai 3:af2d99cfb3f0 296
kenjiArai 3:af2d99cfb3f0 297 if (compensation == 1.0f){
kenjiArai 3:af2d99cfb3f0 298 compensation = (double)target_f / (double)measured_f;
kenjiArai 3:af2d99cfb3f0 299 pll_freq = (uint32_t)((double)pll_freq / compensation);
kenjiArai 3:af2d99cfb3f0 300 } else {
kenjiArai 3:af2d99cfb3f0 301 new_comp_data = (double)target_f / (double)measured_f;
kenjiArai 3:af2d99cfb3f0 302 pll_freq = (uint32_t)((double)pll_freq / new_comp_data);
kenjiArai 3:af2d99cfb3f0 303 compensation *= new_comp_data;
kenjiArai 3:af2d99cfb3f0 304 }
kenjiArai 2:8fe745836ea6 305 }
kenjiArai 2:8fe745836ea6 306
kenjiArai 0:47b9bfa03730 307 static const uint8_t reg_table[] = {
kenjiArai 0:47b9bfa03730 308 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
kenjiArai 0:47b9bfa03730 309 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
kenjiArai 0:47b9bfa03730 310 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
kenjiArai 0:47b9bfa03730 311 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
kenjiArai 0:47b9bfa03730 312 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
kenjiArai 0:47b9bfa03730 313 165, 166, 167, 168, 169, 170
kenjiArai 0:47b9bfa03730 314 };
kenjiArai 0:47b9bfa03730 315
kenjiArai 0:47b9bfa03730 316 void SI5351A::all_reset(void)
kenjiArai 0:47b9bfa03730 317 {
kenjiArai 0:47b9bfa03730 318 plla_freq = 0;
kenjiArai 0:47b9bfa03730 319 pllb_freq = 0;
kenjiArai 0:47b9bfa03730 320 clk0_freq = 0;
kenjiArai 0:47b9bfa03730 321 clk1_freq = 0;
kenjiArai 0:47b9bfa03730 322 clk2_freq = 0;
kenjiArai 0:47b9bfa03730 323 clk0_state = 0;
kenjiArai 0:47b9bfa03730 324 clk1_state = 0;
kenjiArai 0:47b9bfa03730 325 clk2_state = 0;
kenjiArai 0:47b9bfa03730 326 /* Disable all outputs setting CLKx_DIS high */
kenjiArai 0:47b9bfa03730 327 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff);
kenjiArai 0:47b9bfa03730 328 for (uint16_t i = 0; i < sizeof(reg_table); i++){
kenjiArai 0:47b9bfa03730 329 si5351_write(reg_table[i], 0);
kenjiArai 0:47b9bfa03730 330 }
kenjiArai 0:47b9bfa03730 331 /* Apply soft reset */
kenjiArai 0:47b9bfa03730 332 si5351_write(SI5351_REG_177_PLL_RESET, 0xac);
kenjiArai 0:47b9bfa03730 333 }
kenjiArai 0:47b9bfa03730 334
kenjiArai 0:47b9bfa03730 335 ////////////// Configration for Initialization /////////////////////////////////
kenjiArai 0:47b9bfa03730 336 // length, register addr, data, ...
kenjiArai 0:47b9bfa03730 337 const uint8_t si5351_configs[] = {
kenjiArai 0:47b9bfa03730 338 // 0xff = all outputs are disabled.
kenjiArai 0:47b9bfa03730 339 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff,
kenjiArai 0:47b9bfa03730 340 // CLK0,CLK1(REG_17),CLK2(REG_18) -> Power down mode
kenjiArai 0:47b9bfa03730 341 4, SI5351_REG_16_CLK0_CONTROL,
kenjiArai 0:47b9bfa03730 342 SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN,
kenjiArai 0:47b9bfa03730 343 // Dummy data for PLL
kenjiArai 0:47b9bfa03730 344 9, SI5351_REG_26_PLL_A, /*P3*/0, 0, /*P1*/0, 0, 0, /*P3/P2*/0, 0, 0,
kenjiArai 0:47b9bfa03730 345 // RESET PLL (Both PLLA & PLLB)
kenjiArai 0:47b9bfa03730 346 2, SI5351_REG_177_PLL_RESET, (SI5351_PLL_RESET_A | SI5351_PLL_RESET_B),
kenjiArai 0:47b9bfa03730 347 // Dummy data for MULTISYNTH
kenjiArai 0:47b9bfa03730 348 9, SI5351_REG_58_MULTISYNTH2, /*P3*/0, 0, /*P1*/0, 0, 0, /*P2|P3*/0, 0, 0,
kenjiArai 0:47b9bfa03730 349 // 0 = enable / CLK0,1,2 (bit 0,1,2 = 0)
kenjiArai 0:47b9bfa03730 350 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xf8,
kenjiArai 0:47b9bfa03730 351 0 // sentinel
kenjiArai 0:47b9bfa03730 352 };
kenjiArai 0:47b9bfa03730 353
kenjiArai 0:47b9bfa03730 354 void SI5351A::si5351_init(void)
kenjiArai 0:47b9bfa03730 355 {
kenjiArai 0:47b9bfa03730 356 addr = SI5351_I2C_ADDR;
kenjiArai 0:47b9bfa03730 357 clk0_freq = 0;
kenjiArai 0:47b9bfa03730 358 clk1_freq = 0;
kenjiArai 0:47b9bfa03730 359 clk2_freq = 0;
kenjiArai 0:47b9bfa03730 360 clk0_state = CLK_OUT_NOT_USED;
kenjiArai 0:47b9bfa03730 361 clk1_state = CLK_OUT_NOT_USED;
kenjiArai 0:47b9bfa03730 362 clk2_state = CLK_OUT_NOT_USED;
kenjiArai 2:8fe745836ea6 363 compensation = 1.0f;
kenjiArai 3:af2d99cfb3f0 364 si5351_set_PLL_input_condition(FREQ_900MHZ);
kenjiArai 0:47b9bfa03730 365 si5351_reset_pll();
kenjiArai 0:47b9bfa03730 366 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff);
kenjiArai 0:47b9bfa03730 367 // Total load capacitance less than or equal to 12 pF (See AN551)
kenjiArai 0:47b9bfa03730 368 si5351_write(SI5351_REG_183_CRYSTAL_LOAD, x_cap);
kenjiArai 0:47b9bfa03730 369 const uint8_t *p = si5351_configs;
kenjiArai 0:47b9bfa03730 370 while (*p) {
kenjiArai 0:47b9bfa03730 371 uint8_t len = *p++;
kenjiArai 0:47b9bfa03730 372 si5351_bulk_write(p, len);
kenjiArai 0:47b9bfa03730 373 p += len;
kenjiArai 0:47b9bfa03730 374 }
kenjiArai 0:47b9bfa03730 375 // CONTROL for CLK0,1,2
kenjiArai 0:47b9bfa03730 376 uint8_t dt = (drv_current | \
kenjiArai 0:47b9bfa03730 377 SI5351_CLK_INPUT_MULTISYNTH_N | \
kenjiArai 0:47b9bfa03730 378 SI5351_CLK_INTEGER_MODE);
kenjiArai 0:47b9bfa03730 379 si5351_write(SI5351_REG_16_CLK0_CONTROL, dt);
kenjiArai 0:47b9bfa03730 380 si5351_write(SI5351_REG_17_CLK1_CONTROL, dt);
kenjiArai 0:47b9bfa03730 381 si5351_write(SI5351_REG_18_CLK2_CONTROL, dt);
kenjiArai 0:47b9bfa03730 382 si5351_disable_all_output(); // Disable all output
kenjiArai 0:47b9bfa03730 383 }
kenjiArai 0:47b9bfa03730 384
kenjiArai 0:47b9bfa03730 385 void SI5351A::si5351_disable_output(void)
kenjiArai 0:47b9bfa03730 386 {
kenjiArai 0:47b9bfa03730 387 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff);
kenjiArai 0:47b9bfa03730 388 }
kenjiArai 0:47b9bfa03730 389
kenjiArai 0:47b9bfa03730 390 void SI5351A::si5351_disable_all_output(void)
kenjiArai 0:47b9bfa03730 391 {
kenjiArai 0:47b9bfa03730 392 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff);
kenjiArai 0:47b9bfa03730 393 si5351_write(SI5351_REG_16_CLK0_CONTROL, 0x80);
kenjiArai 0:47b9bfa03730 394 si5351_write(SI5351_REG_17_CLK1_CONTROL, 0x80);
kenjiArai 0:47b9bfa03730 395 si5351_write(SI5351_REG_18_CLK2_CONTROL, 0x80);
kenjiArai 0:47b9bfa03730 396 }
kenjiArai 0:47b9bfa03730 397
kenjiArai 0:47b9bfa03730 398 void SI5351A::si5351_enable_output(void)
kenjiArai 0:47b9bfa03730 399 {
kenjiArai 0:47b9bfa03730 400 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xf8);
kenjiArai 0:47b9bfa03730 401 }
kenjiArai 0:47b9bfa03730 402
kenjiArai 0:47b9bfa03730 403 void SI5351A::si5351_reset_pll(void)
kenjiArai 0:47b9bfa03730 404 {
kenjiArai 0:47b9bfa03730 405 si5351_write(SI5351_REG_177_PLL_RESET, 0xa0);
kenjiArai 0:47b9bfa03730 406 }
kenjiArai 0:47b9bfa03730 407
kenjiArai 3:af2d99cfb3f0 408 void SI5351A::si5351_set_PLL_input_condition(uint32_t freq)
kenjiArai 3:af2d99cfb3f0 409 {
kenjiArai 3:af2d99cfb3f0 410 uint8_t n;
kenjiArai 3:af2d99cfb3f0 411 uint32_t dt;
kenjiArai 3:af2d99cfb3f0 412
kenjiArai 3:af2d99cfb3f0 413 n = (uint8_t)(freq / base_freq);
kenjiArai 3:af2d99cfb3f0 414 dt = base_freq * n;
kenjiArai 3:af2d99cfb3f0 415 while (true){
kenjiArai 3:af2d99cfb3f0 416 if (dt > FREQ_900MHZ){ --n;}
kenjiArai 3:af2d99cfb3f0 417 if (dt < FREQ_600MHZ){ ++n;}
kenjiArai 3:af2d99cfb3f0 418 dt = base_freq * n;
kenjiArai 3:af2d99cfb3f0 419 if ((dt <= FREQ_900MHZ) && (dt >= FREQ_600MHZ)){ break;}
kenjiArai 3:af2d99cfb3f0 420 }
kenjiArai 3:af2d99cfb3f0 421 pll_n = n;
kenjiArai 3:af2d99cfb3f0 422 pll_freq = dt;
kenjiArai 3:af2d99cfb3f0 423 pll_freq = (uint32_t)((double)pll_freq / compensation);
kenjiArai 3:af2d99cfb3f0 424 DBG("DBG: Change PLL_N data / pll_n=%u, pll_freq=%u\r\n", pll_n, pll_freq);
kenjiArai 3:af2d99cfb3f0 425 }
kenjiArai 3:af2d99cfb3f0 426
kenjiArai 1:a2309757c450 427 /******************************************************************************/
kenjiArai 0:47b9bfa03730 428 /*!
kenjiArai 0:47b9bfa03730 429 @brief Sets the multiplier for the specified PLL
kenjiArai 0:47b9bfa03730 430
kenjiArai 0:47b9bfa03730 431 @param pll The PLL to configure, which must be one of the following:
kenjiArai 0:47b9bfa03730 432 - SI5351_PLL_A
kenjiArai 0:47b9bfa03730 433 - SI5351_PLL_B
kenjiArai 0:47b9bfa03730 434 @param mult The PLL integer multiplier (must be between 15 and 90)
kenjiArai 0:47b9bfa03730 435 @param num The 20-bit numerator for fractional output (0..1,048,575).
kenjiArai 0:47b9bfa03730 436 Set this to '0' for integer output.
kenjiArai 0:47b9bfa03730 437 @param denom The 20-bit denominator for fractional output (1..1,048,575).
kenjiArai 0:47b9bfa03730 438 Set this to '1' or higher to avoid divider by zero errors.
kenjiArai 0:47b9bfa03730 439 @section PLL Configuration
kenjiArai 0:47b9bfa03730 440 fVCO is the PLL output, and must be between 600..900MHz, where:
kenjiArai 0:47b9bfa03730 441 fVCO = fXTAL * (a+(b/c))
kenjiArai 0:47b9bfa03730 442 fXTAL = the crystal input frequency
kenjiArai 0:47b9bfa03730 443 a = an integer between 15 and 90
kenjiArai 0:47b9bfa03730 444 b = the fractional numerator (0..1,048,575)
kenjiArai 0:47b9bfa03730 445 c = the fractional denominator (1..1,048,575)
kenjiArai 0:47b9bfa03730 446 NOTE: Try to use integers whenever possible to avoid clock jitter
kenjiArai 0:47b9bfa03730 447 (only use the a part, setting b to '0' and c to '1').
kenjiArai 0:47b9bfa03730 448 See: http://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf
kenjiArai 0:47b9bfa03730 449 */
kenjiArai 1:a2309757c450 450 /******************************************************************************/
kenjiArai 0:47b9bfa03730 451 void SI5351A::si5351_setupPLL(
kenjiArai 0:47b9bfa03730 452 uint8_t pll,
kenjiArai 0:47b9bfa03730 453 uint8_t mult,
kenjiArai 0:47b9bfa03730 454 uint32_t num,
kenjiArai 0:47b9bfa03730 455 uint32_t denom)
kenjiArai 0:47b9bfa03730 456 {
kenjiArai 0:47b9bfa03730 457 uint32_t P1; /* PLL config register P1 */
kenjiArai 0:47b9bfa03730 458 uint32_t P2; /* PLL config register P2 */
kenjiArai 0:47b9bfa03730 459 uint32_t P3; /* PLL config register P3 */
kenjiArai 0:47b9bfa03730 460
kenjiArai 0:47b9bfa03730 461 /* Basic validation */
kenjiArai 0:47b9bfa03730 462 DBG("DBG: Enter si5351_setupPLL\r\n");
kenjiArai 0:47b9bfa03730 463 DBG("DBG: pll=%u, mult=%u, num=%u, denom=%u\r\n", pll, mult, num, denom);
kenjiArai 0:47b9bfa03730 464 bool err = false;
kenjiArai 0:47b9bfa03730 465 if (mult <= 14){ /* mult = 15..90 */
kenjiArai 0:47b9bfa03730 466 DBG("DBG: mult lower value error\r\n");
kenjiArai 0:47b9bfa03730 467 err = true;
kenjiArai 0:47b9bfa03730 468 }
kenjiArai 0:47b9bfa03730 469 if (mult >= 91){
kenjiArai 0:47b9bfa03730 470 DBG("DBG: mult bigger value error\r\n");
kenjiArai 0:47b9bfa03730 471 err = true;
kenjiArai 0:47b9bfa03730 472 }
kenjiArai 0:47b9bfa03730 473 if (denom == 0){ /* Avoid divide by zero */
kenjiArai 0:47b9bfa03730 474 DBG("DBG: denom = 0 error\r\n");
kenjiArai 0:47b9bfa03730 475 err = true;
kenjiArai 0:47b9bfa03730 476 }
kenjiArai 0:47b9bfa03730 477 if (num >=0x100000){ /* 20-bit limit */
kenjiArai 0:47b9bfa03730 478 DBG("DBG: num value error\r\n");
kenjiArai 0:47b9bfa03730 479 err = true;
kenjiArai 0:47b9bfa03730 480 }
kenjiArai 0:47b9bfa03730 481 if (denom >=0x100000){ /* 20-bit limit */
kenjiArai 0:47b9bfa03730 482 DBG("DBG: denom value error\r\n");
kenjiArai 0:47b9bfa03730 483 err = true;
kenjiArai 0:47b9bfa03730 484 }
kenjiArai 0:47b9bfa03730 485 if (err == true){
kenjiArai 0:47b9bfa03730 486 if (pll == SI5351_PLL_A){
kenjiArai 0:47b9bfa03730 487 plla_freq = 0;
kenjiArai 0:47b9bfa03730 488 } else { // SI5351_PLL_B
kenjiArai 0:47b9bfa03730 489 pllb_freq = 0;
kenjiArai 0:47b9bfa03730 490 }
kenjiArai 0:47b9bfa03730 491 DBG("DBG: return by error\r\n");
kenjiArai 0:47b9bfa03730 492 return;
kenjiArai 0:47b9bfa03730 493 }
kenjiArai 0:47b9bfa03730 494 /* Feedback Multisynth Divider Equation
kenjiArai 0:47b9bfa03730 495 * where: a = mult, b = num and c = denom
kenjiArai 0:47b9bfa03730 496 * P1 register is an 18-bit value using following formula:
kenjiArai 0:47b9bfa03730 497 * P1[17:0] = 128 * mult + floor(128*(num/denom)) - 512
kenjiArai 0:47b9bfa03730 498 * P2 register is a 20-bit value using the following formula:
kenjiArai 0:47b9bfa03730 499 * P2[19:0] = 128 * num - denom * floor(128*(num/denom))
kenjiArai 0:47b9bfa03730 500 * P3 register is a 20-bit value using the following formula:
kenjiArai 0:47b9bfa03730 501 * P3[19:0] = denom
kenjiArai 0:47b9bfa03730 502 */
kenjiArai 0:47b9bfa03730 503 /* Set the main PLL config registers */
kenjiArai 0:47b9bfa03730 504 if (num == 0) {
kenjiArai 0:47b9bfa03730 505 DBG("DBG: num = 0\r\n");
kenjiArai 0:47b9bfa03730 506 /* Integer mode */
kenjiArai 0:47b9bfa03730 507 P1 = 128 * mult - 512;
kenjiArai 0:47b9bfa03730 508 P2 = num;
kenjiArai 0:47b9bfa03730 509 P3 = denom;
kenjiArai 0:47b9bfa03730 510 } else {
kenjiArai 0:47b9bfa03730 511 /* Fractional mode */
kenjiArai 0:47b9bfa03730 512 DBG("DBG: Fractional mode\r\n");
kenjiArai 0:47b9bfa03730 513 P1 = (uint32_t)
kenjiArai 0:47b9bfa03730 514 (128 * mult + floor(128 * ((double)num/(double)denom)) - 512);
kenjiArai 0:47b9bfa03730 515 P2 = (uint32_t)
kenjiArai 0:47b9bfa03730 516 (128 * num - denom * floor(128 * ((double)num/(double)denom)));
kenjiArai 0:47b9bfa03730 517 P3 = denom;
kenjiArai 0:47b9bfa03730 518 }
kenjiArai 0:47b9bfa03730 519 /* Get the appropriate starting point for the PLL registers */
kenjiArai 0:47b9bfa03730 520 const uint8_t pllreg_base[] = {
kenjiArai 0:47b9bfa03730 521 SI5351_REG_26_PLL_A,
kenjiArai 0:47b9bfa03730 522 SI5351_REG_34_PLL_B
kenjiArai 0:47b9bfa03730 523 };
kenjiArai 0:47b9bfa03730 524 uint8_t baseaddr = pllreg_base[pll];
kenjiArai 0:47b9bfa03730 525 /* The datasheet is a nightmare of typos and inconsistencies here! */
kenjiArai 0:47b9bfa03730 526 si5351_write(baseaddr, (P3 & 0x0000ff00) >> 8);
kenjiArai 0:47b9bfa03730 527 si5351_write(baseaddr+1, (P3 & 0x000000ff));
kenjiArai 0:47b9bfa03730 528 si5351_write(baseaddr+2, (P1 & 0x00030000) >> 16);
kenjiArai 0:47b9bfa03730 529 si5351_write(baseaddr+3, (P1 & 0x0000ff00) >> 8);
kenjiArai 0:47b9bfa03730 530 si5351_write(baseaddr+4, (P1 & 0x000000ff));
kenjiArai 0:47b9bfa03730 531 si5351_write(baseaddr+5,
kenjiArai 0:47b9bfa03730 532 ((P3 & 0x000f0000) >> 12) | ((P2 & 0x000f0000) >> 16) );
kenjiArai 0:47b9bfa03730 533 si5351_write(baseaddr+6, (P2 & 0x0000ff00) >> 8);
kenjiArai 0:47b9bfa03730 534 si5351_write(baseaddr+7, (P2 & 0x000000ff));
kenjiArai 0:47b9bfa03730 535 /* Reset both PLLs */
kenjiArai 0:47b9bfa03730 536 si5351_write(SI5351_REG_177_PLL_RESET,
kenjiArai 0:47b9bfa03730 537 SI5351_PLL_RESET_B | SI5351_PLL_RESET_A);
kenjiArai 0:47b9bfa03730 538 /* Store the frequency settings for use with the Multisynth helper */
kenjiArai 0:47b9bfa03730 539 DBG("DBG: Use 26(PLLA) or 34(PLLB)) ->%u and write data\r\n", baseaddr);
kenjiArai 0:47b9bfa03730 540 double f = base_freq * (mult + ((double)num / (double)denom));
kenjiArai 0:47b9bfa03730 541 DBG("DBG: PLL f=%u\r\n", (uint32_t)f);
kenjiArai 1:a2309757c450 542 DBG("DBG: PLL f(pll_freq)=%u\r\n", (uint32_t)pll_freq);
kenjiArai 0:47b9bfa03730 543 if (pll == SI5351_PLL_A){
kenjiArai 0:47b9bfa03730 544 plla_freq = f;
kenjiArai 0:47b9bfa03730 545 } else { // SI5351_PLL_B
kenjiArai 0:47b9bfa03730 546 pllb_freq = f;
kenjiArai 0:47b9bfa03730 547 }
kenjiArai 0:47b9bfa03730 548 }
kenjiArai 0:47b9bfa03730 549
kenjiArai 1:a2309757c450 550 /******************************************************************************/
kenjiArai 0:47b9bfa03730 551 /*!
kenjiArai 0:47b9bfa03730 552 @brief Configures the Multisynth divider, which determines the
kenjiArai 0:47b9bfa03730 553 output clock frequency based on the specified PLL input.
kenjiArai 0:47b9bfa03730 554
kenjiArai 0:47b9bfa03730 555 @param output The output channel to use (0..2)
kenjiArai 0:47b9bfa03730 556 @param pllSource The PLL input source to use, which must be one of:
kenjiArai 0:47b9bfa03730 557 - SI5351_PLL_A
kenjiArai 0:47b9bfa03730 558 - SI5351_PLL_B
kenjiArai 0:47b9bfa03730 559 @param div The integer divider for the Multisynth output.
kenjiArai 0:47b9bfa03730 560 If pure integer values are used, this value must
kenjiArai 0:47b9bfa03730 561 be one of:
kenjiArai 0:47b9bfa03730 562 - SI5351_MULTISYNTH_DIV_4
kenjiArai 0:47b9bfa03730 563 - SI5351_MULTISYNTH_DIV_6
kenjiArai 0:47b9bfa03730 564 - SI5351_MULTISYNTH_DIV_8
kenjiArai 0:47b9bfa03730 565 If fractional output is used, this value must be
kenjiArai 0:47b9bfa03730 566 between 8 and 900.
kenjiArai 0:47b9bfa03730 567 @param num The 20-bit numerator for fractional output
kenjiArai 0:47b9bfa03730 568 (0..1,048,575). Set this to '0' for integer output.
kenjiArai 0:47b9bfa03730 569 @param denom The 20-bit denominator for fractional output
kenjiArai 0:47b9bfa03730 570 (1..1,048,575). Set this to '1' or higher to
kenjiArai 0:47b9bfa03730 571 avoid divide by zero errors.
kenjiArai 0:47b9bfa03730 572 @section Output Clock Configuration
kenjiArai 0:47b9bfa03730 573
kenjiArai 0:47b9bfa03730 574 The multisynth dividers are applied to the specified PLL output,
kenjiArai 0:47b9bfa03730 575 and are used to reduce the PLL output to a valid range (500kHz
kenjiArai 0:47b9bfa03730 576 to 160MHz). The relationship can be seen in this formula, where
kenjiArai 0:47b9bfa03730 577 fVCO is the PLL output frequency and MSx is the multisynth
kenjiArai 0:47b9bfa03730 578 divider:
kenjiArai 0:47b9bfa03730 579 fOUT = fVCO / MSx
kenjiArai 0:47b9bfa03730 580 Valid multisynth dividers are 4, 6, or 8 when using integers,
kenjiArai 0:47b9bfa03730 581 or any fractional values between 8 + 1/1,048,575 and 900 + 0/1
kenjiArai 0:47b9bfa03730 582
kenjiArai 0:47b9bfa03730 583 The following formula is used for the fractional mode divider:
kenjiArai 0:47b9bfa03730 584 a + b / c
kenjiArai 0:47b9bfa03730 585 a = The integer value, which must be 4, 6 or 8 in integer mode (MSx_INT=1)
kenjiArai 0:47b9bfa03730 586 or 6..1800 in fractional mode (MSx_INT=0).
kenjiArai 0:47b9bfa03730 587 b = The fractional numerator (0..1,048,575)
kenjiArai 0:47b9bfa03730 588 c = The fractional denominator (1..1,048,575)
kenjiArai 0:47b9bfa03730 589
kenjiArai 0:47b9bfa03730 590 @note Try to use integers whenever possible to avoid clock jitter
kenjiArai 0:47b9bfa03730 591 @note For output frequencies > 150MHz, you must set the divider
kenjiArai 0:47b9bfa03730 592 to 4 and adjust to PLL to generate the frequency (for example
kenjiArai 0:47b9bfa03730 593 a PLL of 640 to generate a 160MHz output clock). This is not
kenjiArai 0:47b9bfa03730 594 yet supported in the driver, which limits frequencies to
kenjiArai 0:47b9bfa03730 595 500kHz .. 150MHz.
kenjiArai 0:47b9bfa03730 596 @note For frequencies below 500kHz (down to 8kHz) Rx_DIV must be
kenjiArai 0:47b9bfa03730 597 used, but this isn't currently implemented in the driver.
kenjiArai 0:47b9bfa03730 598 */
kenjiArai 1:a2309757c450 599 /******************************************************************************/
kenjiArai 0:47b9bfa03730 600 double SI5351A::si5351_setupMultisynth(
kenjiArai 0:47b9bfa03730 601 uint8_t output,
kenjiArai 0:47b9bfa03730 602 uint8_t pllSource,
kenjiArai 0:47b9bfa03730 603 uint32_t div,
kenjiArai 0:47b9bfa03730 604 uint32_t num,
kenjiArai 0:47b9bfa03730 605 uint32_t denom,
kenjiArai 0:47b9bfa03730 606 uint8_t factor)
kenjiArai 0:47b9bfa03730 607 {
kenjiArai 0:47b9bfa03730 608 uint32_t P1; /* Multisynth config register P1 */
kenjiArai 0:47b9bfa03730 609 uint32_t P2; /* Multisynth config register P2 */
kenjiArai 0:47b9bfa03730 610 uint32_t P3; /* Multisynth config register P3 */
kenjiArai 0:47b9bfa03730 611 uint32_t div4 = 0;
kenjiArai 0:47b9bfa03730 612 double multisynth_double;
kenjiArai 0:47b9bfa03730 613
kenjiArai 0:47b9bfa03730 614 DBG("DBG: Enter si5351_setupMultisynth\r\n");
kenjiArai 0:47b9bfa03730 615 DBG("DBG: ch=%u, pll=%u, div=%u, num=%u, denom=%u, factor=%u\r\n",
kenjiArai 0:47b9bfa03730 616 output, pllSource, div, num, denom, factor);
kenjiArai 0:47b9bfa03730 617 if (output > 3){
kenjiArai 0:47b9bfa03730 618 return 0;
kenjiArai 0:47b9bfa03730 619 } /* Channel range */
kenjiArai 0:47b9bfa03730 620 if ((div <= 3) || (div >= 1801)){ /* Divider integer 6..1800 */
kenjiArai 0:47b9bfa03730 621 DBG("DBG: div out of range error\r\n");
kenjiArai 0:47b9bfa03730 622 return 0;
kenjiArai 0:47b9bfa03730 623 }
kenjiArai 0:47b9bfa03730 624 if (denom == 0){ /* Avoid divide by zero */
kenjiArai 0:47b9bfa03730 625 DBG("DBG: denom=0 error\r\n");
kenjiArai 0:47b9bfa03730 626 return 0;
kenjiArai 0:47b9bfa03730 627 }
kenjiArai 0:47b9bfa03730 628 if (num >=0x100000){ /* 20-bit limit */
kenjiArai 0:47b9bfa03730 629 DBG("DBG: num bigger error\r\n");
kenjiArai 0:47b9bfa03730 630 return 0;
kenjiArai 0:47b9bfa03730 631 }
kenjiArai 0:47b9bfa03730 632 if (denom >=0x100000){ /* 20-bit limit */
kenjiArai 0:47b9bfa03730 633 DBG("DBG: denom bigger error\r\n");
kenjiArai 0:47b9bfa03730 634 return 0;
kenjiArai 0:47b9bfa03730 635 }
kenjiArai 0:47b9bfa03730 636 DBG("DBG: Passed range check\r\n");
kenjiArai 0:47b9bfa03730 637 /* Get the appropriate starting point for the PLL registers */
kenjiArai 0:47b9bfa03730 638 const uint8_t msreg_base[] = {
kenjiArai 0:47b9bfa03730 639 SI5351_REG_42_MULTISYNTH0,
kenjiArai 0:47b9bfa03730 640 SI5351_REG_50_MULTISYNTH1,
kenjiArai 0:47b9bfa03730 641 SI5351_REG_58_MULTISYNTH2,
kenjiArai 0:47b9bfa03730 642 };
kenjiArai 0:47b9bfa03730 643 uint8_t baseaddr = msreg_base[output];
kenjiArai 0:47b9bfa03730 644 /* Output Multisynth Divider Equations
kenjiArai 0:47b9bfa03730 645 * where: a = div, b = num and c = denom
kenjiArai 0:47b9bfa03730 646 * P1 register is an 18-bit value using following formula:
kenjiArai 0:47b9bfa03730 647 * P1[17:0] = 128 * a + floor(128*(b/c)) - 512
kenjiArai 0:47b9bfa03730 648 * P2 register is a 20-bit value using the following formula:
kenjiArai 0:47b9bfa03730 649 * P2[19:0] = 128 * b - c * floor(128*(b/c))
kenjiArai 0:47b9bfa03730 650 * P3 register is a 20-bit value using the following formula:
kenjiArai 0:47b9bfa03730 651 * P3[19:0] = c
kenjiArai 0:47b9bfa03730 652 */
kenjiArai 0:47b9bfa03730 653 /* Set the main PLL config registers */
kenjiArai 0:47b9bfa03730 654 if (div == 4) {
kenjiArai 0:47b9bfa03730 655 DBG("DBG: enter div==4\r\n");
kenjiArai 0:47b9bfa03730 656 div4 = SI5351_DIVBY4;
kenjiArai 0:47b9bfa03730 657 P1 = P2 = 0;
kenjiArai 0:47b9bfa03730 658 P3 = 1;
kenjiArai 3:af2d99cfb3f0 659 multisynth_double = 4.0f;
kenjiArai 0:47b9bfa03730 660 } else if (num == 0) {
kenjiArai 0:47b9bfa03730 661 DBG("DBG: enter num==0\r\n");
kenjiArai 0:47b9bfa03730 662 /* Integer mode */
kenjiArai 0:47b9bfa03730 663 P1 = 128 * div - 512;
kenjiArai 0:47b9bfa03730 664 P2 = 0;
kenjiArai 0:47b9bfa03730 665 P3 = 1;
kenjiArai 0:47b9bfa03730 666 multisynth_double = (double)div;
kenjiArai 0:47b9bfa03730 667 } else {
kenjiArai 0:47b9bfa03730 668 /* Fractional mode */
kenjiArai 0:47b9bfa03730 669 DBG("DBG: enter Fractional mode\r\n");
kenjiArai 1:a2309757c450 670 P1 = (uint32_t)
kenjiArai 1:a2309757c450 671 (128 * div + floor(128 * ((float)num/(float)denom)) - 512);
kenjiArai 1:a2309757c450 672 P2 = (uint32_t)
kenjiArai 1:a2309757c450 673 (128 * num - denom * floor(128 * ((float)num/(float)denom)));
kenjiArai 0:47b9bfa03730 674 P3 = denom;
kenjiArai 0:47b9bfa03730 675 multisynth_double = div + (double)num /(double)denom;
kenjiArai 0:47b9bfa03730 676 /* a + b/c between 6..1800 */
kenjiArai 0:47b9bfa03730 677 if ((multisynth_double < 6.0f) || (multisynth_double > 1800.0f)){
kenjiArai 0:47b9bfa03730 678 return 0;
kenjiArai 0:47b9bfa03730 679 }
kenjiArai 0:47b9bfa03730 680 }
kenjiArai 0:47b9bfa03730 681 /* Set the MSx config registers */
kenjiArai 0:47b9bfa03730 682 si5351_write(baseaddr, (P3 & 0x0000ff00) >> 8);
kenjiArai 0:47b9bfa03730 683 si5351_write(baseaddr+1, (P3 & 0x000000ff));
kenjiArai 0:47b9bfa03730 684 si5351_write(baseaddr+2, ((P1 & 0x00030000) >> 16) | div4 | factor);
kenjiArai 0:47b9bfa03730 685 si5351_write(baseaddr+3, (P1 & 0x0000ff00) >> 8);
kenjiArai 0:47b9bfa03730 686 si5351_write(baseaddr+4, (P1 & 0x000000ff));
kenjiArai 0:47b9bfa03730 687 si5351_write(baseaddr+5,
kenjiArai 0:47b9bfa03730 688 ((P3 & 0x000f0000) >> 12) | ((P2 & 0x000f0000) >> 16));
kenjiArai 0:47b9bfa03730 689 si5351_write(baseaddr+6, (P2 & 0x0000ff00) >> 8);
kenjiArai 0:47b9bfa03730 690 si5351_write(baseaddr+7, (P2 & 0x000000ff));
kenjiArai 0:47b9bfa03730 691 /* Configure the clk control and enable the output */
kenjiArai 0:47b9bfa03730 692 const uint8_t clkctrl[] = {
kenjiArai 0:47b9bfa03730 693 SI5351_REG_16_CLK0_CONTROL,
kenjiArai 0:47b9bfa03730 694 SI5351_REG_17_CLK1_CONTROL,
kenjiArai 0:47b9bfa03730 695 SI5351_REG_18_CLK2_CONTROL
kenjiArai 0:47b9bfa03730 696 };
kenjiArai 0:47b9bfa03730 697 uint8_t dat;
kenjiArai 0:47b9bfa03730 698 dat = drv_current | SI5351_CLK_INPUT_MULTISYNTH_N;
kenjiArai 0:47b9bfa03730 699 if (pllSource == SI5351_PLL_B){
kenjiArai 0:47b9bfa03730 700 dat |= SI5351_CLK_PLL_SELECT_B;
kenjiArai 0:47b9bfa03730 701 }
kenjiArai 0:47b9bfa03730 702 if (num == 0){
kenjiArai 0:47b9bfa03730 703 dat |= SI5351_CLK_INTEGER_MODE;
kenjiArai 0:47b9bfa03730 704 }
kenjiArai 0:47b9bfa03730 705 DBG("DBG: CLK%u: reg_%u=0x%02x\r\n", output, clkctrl[output], dat);
kenjiArai 0:47b9bfa03730 706 si5351_write(clkctrl[output], dat);
kenjiArai 0:47b9bfa03730 707 DBG("DBG: a+b/c=%8.2f\r\n", multisynth_double);
kenjiArai 0:47b9bfa03730 708 return multisynth_double;
kenjiArai 0:47b9bfa03730 709 }
kenjiArai 0:47b9bfa03730 710
kenjiArai 0:47b9bfa03730 711 uint32_t SI5351A::gcd(uint32_t x, uint32_t y)
kenjiArai 0:47b9bfa03730 712 {
kenjiArai 0:47b9bfa03730 713 int32_t z;
kenjiArai 0:47b9bfa03730 714 while (y != 0) {
kenjiArai 0:47b9bfa03730 715 z = x % y;
kenjiArai 0:47b9bfa03730 716 x = y;
kenjiArai 0:47b9bfa03730 717 y = z;
kenjiArai 0:47b9bfa03730 718 }
kenjiArai 0:47b9bfa03730 719 return x;
kenjiArai 0:47b9bfa03730 720 }
kenjiArai 0:47b9bfa03730 721
kenjiArai 0:47b9bfa03730 722 double SI5351A::si5351_set_frequency_fixedpll(
kenjiArai 0:47b9bfa03730 723 uint8_t channel,
kenjiArai 0:47b9bfa03730 724 uint32_t pll,
kenjiArai 0:47b9bfa03730 725 uint32_t pllfreq,
kenjiArai 0:47b9bfa03730 726 uint32_t freq,
kenjiArai 0:47b9bfa03730 727 uint8_t factor)
kenjiArai 0:47b9bfa03730 728 {
kenjiArai 0:47b9bfa03730 729 DBG("DBG: Enter si5351_set_frequency_fixedpll\r\n");
kenjiArai 0:47b9bfa03730 730 uint32_t div = (floor)((double)pllfreq / (double)freq); // range: 8 ~ 1800
kenjiArai 0:47b9bfa03730 731 uint32_t num = pllfreq - freq * div;
kenjiArai 0:47b9bfa03730 732 uint32_t denom = freq;
kenjiArai 0:47b9bfa03730 733 //int32_t k = freq / (1<<20) + 1;
kenjiArai 0:47b9bfa03730 734 uint32_t k = gcd(num, denom);
kenjiArai 0:47b9bfa03730 735 num /= k;
kenjiArai 0:47b9bfa03730 736 denom /= k;
kenjiArai 0:47b9bfa03730 737 while (denom >= (1<<20)) {
kenjiArai 0:47b9bfa03730 738 num >>= 1;
kenjiArai 0:47b9bfa03730 739 denom >>= 1;
kenjiArai 0:47b9bfa03730 740 }
kenjiArai 0:47b9bfa03730 741 DBG("DBG: CLK%u: PLL=%u,div=%u,num=%u,denom=%u\r\n",
kenjiArai 0:47b9bfa03730 742 channel, pll, div, num, denom);
kenjiArai 0:47b9bfa03730 743 double x = si5351_setupMultisynth(channel, pll, div, num, denom, factor);
kenjiArai 0:47b9bfa03730 744 if (x == 0.0f){ return 0;}
kenjiArai 0:47b9bfa03730 745 x = (double)pll_freq / x;
kenjiArai 0:47b9bfa03730 746 DBG("DBG: Freqency=%.0f[Hz]\r\n", x);
kenjiArai 0:47b9bfa03730 747 return x;
kenjiArai 0:47b9bfa03730 748 }
kenjiArai 0:47b9bfa03730 749
kenjiArai 0:47b9bfa03730 750 double SI5351A::si5351_set_frequency_fixeddiv(
kenjiArai 0:47b9bfa03730 751 uint8_t channel,
kenjiArai 0:47b9bfa03730 752 uint32_t pll,
kenjiArai 0:47b9bfa03730 753 uint32_t freq,
kenjiArai 0:47b9bfa03730 754 uint32_t div)
kenjiArai 0:47b9bfa03730 755 {
kenjiArai 0:47b9bfa03730 756 DBG("DBG: si5351_set_frequency_fixeddiv\r\n");
kenjiArai 0:47b9bfa03730 757 uint32_t pllfreq = freq * div;
kenjiArai 0:47b9bfa03730 758 uint32_t multi = pllfreq / base_freq;
kenjiArai 0:47b9bfa03730 759 uint32_t num = pllfreq - multi * base_freq;
kenjiArai 0:47b9bfa03730 760 uint32_t denom = base_freq;
kenjiArai 0:47b9bfa03730 761 uint32_t k = gcd(num, denom);
kenjiArai 0:47b9bfa03730 762 num /= k;
kenjiArai 0:47b9bfa03730 763 denom /= k;
kenjiArai 0:47b9bfa03730 764 while (denom >= (1<<20)) {
kenjiArai 0:47b9bfa03730 765 num >>= 1;
kenjiArai 0:47b9bfa03730 766 denom >>= 1;
kenjiArai 0:47b9bfa03730 767 }
kenjiArai 0:47b9bfa03730 768 si5351_setupPLL(pll, multi, num, denom);
kenjiArai 0:47b9bfa03730 769 num = 0;
kenjiArai 0:47b9bfa03730 770 double x = si5351_setupMultisynth(channel, pll, div, num, denom, 0);
kenjiArai 0:47b9bfa03730 771 if (x == 0.0f){ return 0.0f;}
kenjiArai 0:47b9bfa03730 772 if (pll == SI5351_PLL_A){
kenjiArai 0:47b9bfa03730 773 x = plla_freq / x;
kenjiArai 0:47b9bfa03730 774 } else { // SI5351_PLL_B
kenjiArai 0:47b9bfa03730 775 x = pllb_freq / x;
kenjiArai 0:47b9bfa03730 776 }
kenjiArai 0:47b9bfa03730 777 DBG("DBG: Freqency=%.0f[Hz]\r\n", x);
kenjiArai 0:47b9bfa03730 778 return x;
kenjiArai 0:47b9bfa03730 779 }
kenjiArai 0:47b9bfa03730 780
kenjiArai 0:47b9bfa03730 781 void SI5351A::si5351_bulk_write(const uint8_t *buf, uint8_t len)
kenjiArai 0:47b9bfa03730 782 {
kenjiArai 0:47b9bfa03730 783 _i2c.write(addr, (const char*)buf, len, false);
kenjiArai 0:47b9bfa03730 784 }
kenjiArai 0:47b9bfa03730 785
kenjiArai 0:47b9bfa03730 786 void SI5351A::si5351_write(uint8_t reg, uint8_t dat)
kenjiArai 0:47b9bfa03730 787 {
kenjiArai 0:47b9bfa03730 788 uint8_t buf[] = { reg, dat };
kenjiArai 0:47b9bfa03730 789 _i2c.write(addr,(const char *)buf, 2, false);
kenjiArai 0:47b9bfa03730 790 }
kenjiArai 0:47b9bfa03730 791
kenjiArai 0:47b9bfa03730 792 void SI5351A::si5351_read(const uint8_t *buf)
kenjiArai 0:47b9bfa03730 793 {
kenjiArai 0:47b9bfa03730 794 int n = (int)buf[1];
kenjiArai 0:47b9bfa03730 795 _i2c.write(addr,(const char *)buf, 1, true);
kenjiArai 0:47b9bfa03730 796 _i2c.read(addr, (char *)buf, n, false);
kenjiArai 0:47b9bfa03730 797 }
kenjiArai 0:47b9bfa03730 798
kenjiArai 0:47b9bfa03730 799 //----------- DEBUG PURPOSE ----------------------------------------------------
kenjiArai 0:47b9bfa03730 800 // Print memory contents
kenjiArai 0:47b9bfa03730 801 void SI5351A::put_dump (const uint8_t *buff, uint8_t ofs, uint8_t cnt)
kenjiArai 0:47b9bfa03730 802 {
kenjiArai 0:47b9bfa03730 803 printf("%03u ", ofs);
kenjiArai 0:47b9bfa03730 804 for(int n = 0; n < cnt; n++) { // show hex
kenjiArai 0:47b9bfa03730 805 printf(" %02x", buff[n]);
kenjiArai 0:47b9bfa03730 806 }
kenjiArai 0:47b9bfa03730 807 printf("\r\n");
kenjiArai 0:47b9bfa03730 808 }
kenjiArai 0:47b9bfa03730 809
kenjiArai 0:47b9bfa03730 810 void SI5351A::prnt_reg(uint8_t offset, uint8_t n)
kenjiArai 0:47b9bfa03730 811 {
kenjiArai 0:47b9bfa03730 812 uint8_t buf[16];
kenjiArai 0:47b9bfa03730 813 buf[0] = offset;
kenjiArai 0:47b9bfa03730 814 buf[1] = n;
kenjiArai 0:47b9bfa03730 815 si5351_read(buf);
kenjiArai 0:47b9bfa03730 816 put_dump(buf, offset, n);
kenjiArai 0:47b9bfa03730 817 }
kenjiArai 0:47b9bfa03730 818
kenjiArai 0:47b9bfa03730 819 void SI5351A::debug_reg_print(void)
kenjiArai 0:47b9bfa03730 820 {
kenjiArai 0:47b9bfa03730 821 printf("Show Si5351A registers\r\n");
kenjiArai 0:47b9bfa03730 822 printf("reg 0 1 2 3 4 5 6 7 8 9\r\n");
kenjiArai 0:47b9bfa03730 823 prnt_reg(0, 4); // reg0 to reg3
kenjiArai 0:47b9bfa03730 824 prnt_reg(9, 1); // reg9
kenjiArai 0:47b9bfa03730 825 prnt_reg(15, 4); // reg15 to reg18
kenjiArai 0:47b9bfa03730 826 prnt_reg(24, 10); // reg24 to reg33
kenjiArai 0:47b9bfa03730 827 prnt_reg(34, 10); // reg34 to reg43
kenjiArai 0:47b9bfa03730 828 prnt_reg(44, 10); // reg44 to reg53
kenjiArai 0:47b9bfa03730 829 prnt_reg(54, 10); // reg54 to reg63
kenjiArai 0:47b9bfa03730 830 prnt_reg(64, 2); // reg64 to reg65
kenjiArai 0:47b9bfa03730 831 prnt_reg(149, 10); // reg149 to reg158
kenjiArai 0:47b9bfa03730 832 prnt_reg(159, 3); // reg159 to reg161
kenjiArai 0:47b9bfa03730 833 prnt_reg(165, 3); // reg165 to reg167
kenjiArai 0:47b9bfa03730 834 prnt_reg(177, 1); // reg177
kenjiArai 0:47b9bfa03730 835 prnt_reg(183, 1); // reg183
kenjiArai 0:47b9bfa03730 836 prnt_reg(187, 1); // reg187
kenjiArai 0:47b9bfa03730 837 }
kenjiArai 0:47b9bfa03730 838
kenjiArai 0:47b9bfa03730 839 void SI5351A::debug_current_config(void)
kenjiArai 0:47b9bfa03730 840 {
kenjiArai 0:47b9bfa03730 841 uint8_t buf[16];
kenjiArai 0:47b9bfa03730 842 uint8_t dt0;
kenjiArai 0:47b9bfa03730 843 uint8_t dt1;
kenjiArai 0:47b9bfa03730 844 //Step1
kenjiArai 0:47b9bfa03730 845 printf("[BASE CLOCK] --> ");
kenjiArai 0:47b9bfa03730 846 buf[0] = 183; // register address
kenjiArai 0:47b9bfa03730 847 buf[1] = 1; // # of reading bytes
kenjiArai 0:47b9bfa03730 848 si5351_read(buf);
kenjiArai 0:47b9bfa03730 849 printf("Xtal=%u[Hz] with internal cap=", base_freq);
kenjiArai 0:47b9bfa03730 850 dt0 = buf[0] & 0xc0;
kenjiArai 0:47b9bfa03730 851 switch (dt0){
kenjiArai 0:47b9bfa03730 852 case 0xc0:
kenjiArai 0:47b9bfa03730 853 printf("10");
kenjiArai 0:47b9bfa03730 854 break;
kenjiArai 0:47b9bfa03730 855 case 0x80:
kenjiArai 0:47b9bfa03730 856 printf("8");
kenjiArai 0:47b9bfa03730 857 break;
kenjiArai 0:47b9bfa03730 858 case 0x40:
kenjiArai 0:47b9bfa03730 859 printf("6");
kenjiArai 0:47b9bfa03730 860 break;
kenjiArai 0:47b9bfa03730 861 default:
kenjiArai 0:47b9bfa03730 862 printf("?(bad config)");
kenjiArai 0:47b9bfa03730 863 break;
kenjiArai 0:47b9bfa03730 864 }
kenjiArai 0:47b9bfa03730 865 printf("[pF]\r\n");
kenjiArai 2:8fe745836ea6 866 printf("--> compensation=%f\r\n", compensation);
kenjiArai 2:8fe745836ea6 867 printf("--> pll_freq=XTAL*PLL_N=%u\r\n", pll_freq);
kenjiArai 0:47b9bfa03730 868 //Step2
kenjiArai 0:47b9bfa03730 869 printf("[PLLn] --> ");
kenjiArai 0:47b9bfa03730 870 buf[0] = 15;
kenjiArai 0:47b9bfa03730 871 buf[1] = 1;
kenjiArai 0:47b9bfa03730 872 si5351_read(buf);
kenjiArai 0:47b9bfa03730 873 dt0 = buf[0];
kenjiArai 0:47b9bfa03730 874 dt1 = dt0 >> 6;
kenjiArai 0:47b9bfa03730 875 printf("Clock in divide by %u", 1U << dt1);
kenjiArai 0:47b9bfa03730 876 printf(" PLLA clock source is ");
kenjiArai 0:47b9bfa03730 877 if (dt0 & 0x04){
kenjiArai 0:47b9bfa03730 878 printf("none XTAL(bad config)");
kenjiArai 0:47b9bfa03730 879 } else {
kenjiArai 0:47b9bfa03730 880 printf("XTAL");
kenjiArai 0:47b9bfa03730 881 }
kenjiArai 0:47b9bfa03730 882 printf(" & PLLB = ");
kenjiArai 0:47b9bfa03730 883 if (dt0 & 0x08){
kenjiArai 0:47b9bfa03730 884 printf("none XTAL(bad config)");
kenjiArai 0:47b9bfa03730 885 } else {
kenjiArai 0:47b9bfa03730 886 printf("XTAL");
kenjiArai 0:47b9bfa03730 887 }
kenjiArai 0:47b9bfa03730 888 printf("\r\n");
kenjiArai 0:47b9bfa03730 889 //Step3
kenjiArai 0:47b9bfa03730 890 printf("[CLK0,1,2] --> ");
kenjiArai 0:47b9bfa03730 891 printf("CLKn output E:enable/D:disable * ");
kenjiArai 0:47b9bfa03730 892 buf[0] = 9; // register address
kenjiArai 0:47b9bfa03730 893 buf[1] = 1; // # of reading bytes
kenjiArai 0:47b9bfa03730 894 si5351_read(buf);
kenjiArai 0:47b9bfa03730 895 dt0 = buf[0] & 0x07;
kenjiArai 0:47b9bfa03730 896 buf[0] = 3; // register address
kenjiArai 0:47b9bfa03730 897 buf[1] = 1; // # of reading bytes
kenjiArai 0:47b9bfa03730 898 si5351_read(buf);
kenjiArai 0:47b9bfa03730 899 dt1 = buf[0] & 0x07;
kenjiArai 0:47b9bfa03730 900 printf("CLK2:");
kenjiArai 0:47b9bfa03730 901 if ((dt0 & 0x04) && (dt1 & 0x04)){
kenjiArai 0:47b9bfa03730 902 printf("D");
kenjiArai 0:47b9bfa03730 903 } else {
kenjiArai 0:47b9bfa03730 904 printf("E");
kenjiArai 0:47b9bfa03730 905 }
kenjiArai 0:47b9bfa03730 906 printf(", CLK1:");
kenjiArai 0:47b9bfa03730 907 if ((dt0 & 0x02) && (dt1 & 0x02)){
kenjiArai 0:47b9bfa03730 908 printf("D");
kenjiArai 0:47b9bfa03730 909 } else {
kenjiArai 0:47b9bfa03730 910 printf("E");
kenjiArai 0:47b9bfa03730 911 }
kenjiArai 0:47b9bfa03730 912 printf(", CLK0:");
kenjiArai 0:47b9bfa03730 913 if ((dt0 & 0x01) && (dt1 & 0x01)){
kenjiArai 0:47b9bfa03730 914 printf("D");
kenjiArai 0:47b9bfa03730 915 } else {
kenjiArai 0:47b9bfa03730 916 printf("E");
kenjiArai 0:47b9bfa03730 917 }
kenjiArai 0:47b9bfa03730 918 printf("\r\n");
kenjiArai 0:47b9bfa03730 919 //Step4
kenjiArai 0:47b9bfa03730 920 buf[0] = 16;
kenjiArai 0:47b9bfa03730 921 buf[1] = 3;
kenjiArai 0:47b9bfa03730 922 si5351_read(buf);
kenjiArai 0:47b9bfa03730 923 printf("--> CLK0 * ");
kenjiArai 0:47b9bfa03730 924 reg_16_17_18(buf[0]);
kenjiArai 0:47b9bfa03730 925 printf("--> CLK1 * ");
kenjiArai 0:47b9bfa03730 926 reg_16_17_18(buf[1]);
kenjiArai 0:47b9bfa03730 927 printf("--> CLK2 * ");
kenjiArai 0:47b9bfa03730 928 reg_16_17_18(buf[2]);
kenjiArai 0:47b9bfa03730 929 //Step5
kenjiArai 0:47b9bfa03730 930 printf("[PLLn P1,P2,P3]\r\n");
kenjiArai 0:47b9bfa03730 931 printf("--> PLLA * ");
kenjiArai 0:47b9bfa03730 932 buf[0] = 26; // register address
kenjiArai 0:47b9bfa03730 933 buf[1] = 8; // # of reading bytes
kenjiArai 0:47b9bfa03730 934 si5351_read(buf);
kenjiArai 0:47b9bfa03730 935 reg_pll_8bytes(buf);
kenjiArai 0:47b9bfa03730 936 printf("--> PLLB * ");
kenjiArai 0:47b9bfa03730 937 buf[0] = 34; // register address
kenjiArai 0:47b9bfa03730 938 buf[1] = 8; // # of reading bytes
kenjiArai 0:47b9bfa03730 939 si5351_read(buf);
kenjiArai 0:47b9bfa03730 940 reg_pll_8bytes(buf);
kenjiArai 3:af2d99cfb3f0 941 printf("[MultiSynth-n P1,P2,P3]\r\n");
kenjiArai 0:47b9bfa03730 942 printf("--> Mltsyn0 * ");
kenjiArai 0:47b9bfa03730 943 buf[0] = 42; // register address
kenjiArai 0:47b9bfa03730 944 buf[1] = 8; // # of reading bytes
kenjiArai 0:47b9bfa03730 945 si5351_read(buf);
kenjiArai 0:47b9bfa03730 946 reg_mltisyc_8bytes(buf);
kenjiArai 0:47b9bfa03730 947 printf("--> Mltsyn1 * ");
kenjiArai 0:47b9bfa03730 948 buf[0] = 50; // register address
kenjiArai 0:47b9bfa03730 949 buf[1] = 8; // # of reading bytes
kenjiArai 0:47b9bfa03730 950 si5351_read(buf);
kenjiArai 0:47b9bfa03730 951 reg_mltisyc_8bytes(buf);
kenjiArai 0:47b9bfa03730 952 printf("--> Mltsyn2 * ");
kenjiArai 0:47b9bfa03730 953 buf[0] = 58; // register address
kenjiArai 0:47b9bfa03730 954 buf[1] = 8; // # of reading bytes
kenjiArai 0:47b9bfa03730 955 si5351_read(buf);
kenjiArai 0:47b9bfa03730 956 reg_mltisyc_8bytes(buf);
kenjiArai 0:47b9bfa03730 957 }
kenjiArai 0:47b9bfa03730 958
kenjiArai 0:47b9bfa03730 959 void SI5351A::reg_pll_8bytes(uint8_t *buf)
kenjiArai 0:47b9bfa03730 960 {
kenjiArai 0:47b9bfa03730 961 uint32_t dt = ((uint32_t)(buf[5] & 0xf0) << 12) + ((uint32_t)buf[0] << 8)
kenjiArai 0:47b9bfa03730 962 + (uint32_t)buf[1];
kenjiArai 0:47b9bfa03730 963 printf("P3=%6u (0x%05x), ", dt, dt);
kenjiArai 0:47b9bfa03730 964 dt = ((uint32_t)(buf[5] & 0x0f) << 16) + ((uint32_t)buf[6] << 8)
kenjiArai 0:47b9bfa03730 965 + (uint32_t)buf[7];
kenjiArai 0:47b9bfa03730 966 printf("P2=%6u (0x%05x), ", dt, dt);
kenjiArai 0:47b9bfa03730 967 dt = ((uint32_t)(buf[2] & 0x03) << 16) + ((uint32_t)buf[3] << 8)
kenjiArai 0:47b9bfa03730 968 + (uint32_t)buf[4];
kenjiArai 0:47b9bfa03730 969 printf("P1=%6u (0x%05x)\r\n", dt, dt);
kenjiArai 0:47b9bfa03730 970 }
kenjiArai 0:47b9bfa03730 971
kenjiArai 0:47b9bfa03730 972 void SI5351A::reg_mltisyc_8bytes(uint8_t *buf)
kenjiArai 0:47b9bfa03730 973 {
kenjiArai 0:47b9bfa03730 974 uint32_t dt = ((uint32_t)(buf[5] & 0xf0) << 12) + ((uint32_t)buf[0] << 8)
kenjiArai 0:47b9bfa03730 975 + (uint32_t)buf[1];
kenjiArai 0:47b9bfa03730 976 printf("P3=%6u (0x%05x), ", dt, dt);
kenjiArai 0:47b9bfa03730 977 dt = ((uint32_t)(buf[5] & 0x0f) << 16) + ((uint32_t)buf[6] << 8)
kenjiArai 0:47b9bfa03730 978 + (uint32_t)buf[7];
kenjiArai 0:47b9bfa03730 979 printf("P2=%6u (0x%05x), ", dt, dt);
kenjiArai 0:47b9bfa03730 980 dt = ((uint32_t)(buf[2] & 0x03) << 16) + ((uint32_t)buf[3] << 8)
kenjiArai 0:47b9bfa03730 981 + (uint32_t)buf[4];
kenjiArai 0:47b9bfa03730 982 printf("P1=%6u (0x%05x), ", dt, dt);
kenjiArai 0:47b9bfa03730 983 uint8_t d = buf[2];
kenjiArai 0:47b9bfa03730 984 if ((d & 0x0c) == 0x0c){
kenjiArai 0:47b9bfa03730 985 printf("Divided by");
kenjiArai 0:47b9bfa03730 986 } else {
kenjiArai 0:47b9bfa03730 987 printf("Div >");
kenjiArai 0:47b9bfa03730 988 }
kenjiArai 0:47b9bfa03730 989 printf(" 4 mode, ");
kenjiArai 0:47b9bfa03730 990 dt >>= 4;
kenjiArai 0:47b9bfa03730 991 dt &=0x07;
kenjiArai 0:47b9bfa03730 992 printf("R-reg: Divided by %u\r\n", 1U << dt);
kenjiArai 0:47b9bfa03730 993 }
kenjiArai 0:47b9bfa03730 994
kenjiArai 0:47b9bfa03730 995 void SI5351A::reg_16_17_18(uint8_t dt)
kenjiArai 0:47b9bfa03730 996 {
kenjiArai 0:47b9bfa03730 997 printf("Power ");
kenjiArai 0:47b9bfa03730 998 if (dt & 0x80){
kenjiArai 0:47b9bfa03730 999 printf("down(not used)");
kenjiArai 0:47b9bfa03730 1000 } else {
kenjiArai 0:47b9bfa03730 1001 printf("up(running)");
kenjiArai 0:47b9bfa03730 1002 }
kenjiArai 0:47b9bfa03730 1003 printf(", MultiSynth-> ");
kenjiArai 0:47b9bfa03730 1004 if (dt & 0x40){
kenjiArai 0:47b9bfa03730 1005 printf("Integer");
kenjiArai 0:47b9bfa03730 1006 } else {
kenjiArai 0:47b9bfa03730 1007 printf("Fractional");
kenjiArai 0:47b9bfa03730 1008 }
kenjiArai 0:47b9bfa03730 1009 printf(" mode, PLL-> ");
kenjiArai 0:47b9bfa03730 1010 if (dt & 0x20){
kenjiArai 0:47b9bfa03730 1011 printf("PLLB");
kenjiArai 0:47b9bfa03730 1012 } else {
kenjiArai 0:47b9bfa03730 1013 printf("PLLA");
kenjiArai 0:47b9bfa03730 1014 }
kenjiArai 0:47b9bfa03730 1015 printf(", Clock-> ");
kenjiArai 0:47b9bfa03730 1016 if (dt & 0x20){
kenjiArai 0:47b9bfa03730 1017 printf("inverted");
kenjiArai 0:47b9bfa03730 1018 } else {
kenjiArai 0:47b9bfa03730 1019 printf("not inverted");
kenjiArai 0:47b9bfa03730 1020 }
kenjiArai 0:47b9bfa03730 1021 printf(", Drive strength-> ");
kenjiArai 3:af2d99cfb3f0 1022 printf("%umA\r\n", 2 + 2 * (dt & 0x03));
kenjiArai 0:47b9bfa03730 1023 }
kenjiArai 0:47b9bfa03730 1024
kenjiArai 1:a2309757c450 1025 /******************************************************************************/
kenjiArai 0:47b9bfa03730 1026 /*!
kenjiArai 0:47b9bfa03730 1027 @brief Configures the Si5351 with config settings generated in
kenjiArai 0:47b9bfa03730 1028 ClockBuilder. You can use this function to make sure that
kenjiArai 0:47b9bfa03730 1029 your HW is properly configure and that there are no problems
kenjiArai 0:47b9bfa03730 1030 with the board itself.
kenjiArai 0:47b9bfa03730 1031
kenjiArai 0:47b9bfa03730 1032 Running this function should provide the following output:
kenjiArai 0:47b9bfa03730 1033 * Channel 0: 120.00 MHz
kenjiArai 0:47b9bfa03730 1034 * Channel 1: 12.00 MHz
kenjiArai 0:47b9bfa03730 1035 * Channel 2: 13.56 MHz
kenjiArai 0:47b9bfa03730 1036 @note This will overwrite all of the config registers!
kenjiArai 0:47b9bfa03730 1037 */
kenjiArai 1:a2309757c450 1038 /******************************************************************************/
kenjiArai 0:47b9bfa03730 1039 /* Test setup from SI5351 ClockBuilder
kenjiArai 0:47b9bfa03730 1040 * -----------------------------------
kenjiArai 0:47b9bfa03730 1041 * XTAL: 25 MHz
kenjiArai 0:47b9bfa03730 1042 * Channel 0: 120.00 MHz
kenjiArai 0:47b9bfa03730 1043 * Channel 1: 12.00 MHz
kenjiArai 0:47b9bfa03730 1044 * Channel 2: 13.56 MHz
kenjiArai 0:47b9bfa03730 1045 */
kenjiArai 0:47b9bfa03730 1046 static const uint8_t m_si5351_regs_15to92_149to170[100][2] =
kenjiArai 0:47b9bfa03730 1047 {
kenjiArai 0:47b9bfa03730 1048 { 15, 0x00 }, /* Input source = crystal for PLLA and PLLB */
kenjiArai 0:47b9bfa03730 1049 /* CLK0 Control: 8mA drive, Multisynth 0 as CLK0 source, Clock not inverted,
kenjiArai 0:47b9bfa03730 1050 Source = PLLA, Multisynth 0 in integer mode, clock powered up */
kenjiArai 0:47b9bfa03730 1051 { 16, 0x4F },
kenjiArai 0:47b9bfa03730 1052 /* CLK1 Control: 8mA drive, Multisynth 1 as CLK1 source, Clock not inverted,
kenjiArai 0:47b9bfa03730 1053 Source = PLLA, Multisynth 1 in integer mode, clock powered up */
kenjiArai 0:47b9bfa03730 1054 { 17, 0x4F },
kenjiArai 0:47b9bfa03730 1055 /* CLK2 Control: 8mA drive, Multisynth 2 as CLK2 source, Clock not inverted,
kenjiArai 0:47b9bfa03730 1056 Source = PLLB, Multisynth 2 in integer mode, clock powered up */
kenjiArai 0:47b9bfa03730 1057 { 18, 0x6F },
kenjiArai 0:47b9bfa03730 1058 { 19, 0x80 }, /* CLK3 Control: Not used ... clock powered down */
kenjiArai 0:47b9bfa03730 1059 { 20, 0x80 }, /* CLK4 Control: Not used ... clock powered down */
kenjiArai 0:47b9bfa03730 1060 { 21, 0x80 }, /* CLK5 Control: Not used ... clock powered down */
kenjiArai 0:47b9bfa03730 1061 { 22, 0x80 }, /* CLK6 Control: Not used ... clock powered down */
kenjiArai 0:47b9bfa03730 1062 { 23, 0x80 }, /* CLK7 Control: Not used ... clock powered down */
kenjiArai 0:47b9bfa03730 1063 { 24, 0x00 }, /* Clock disable state 0..3 (low when disabled) */
kenjiArai 0:47b9bfa03730 1064 { 25, 0x00 }, /* Clock disable state 4..7 (low when disabled) */
kenjiArai 0:47b9bfa03730 1065 /* PLL_A Setup */
kenjiArai 0:47b9bfa03730 1066 { 26, 0x00 }, { 27, 0x05 }, { 28, 0x00 }, { 29, 0x0C },
kenjiArai 0:47b9bfa03730 1067 { 30, 0x66 }, { 31, 0x00 }, { 32, 0x00 }, { 33, 0x02 },
kenjiArai 0:47b9bfa03730 1068 /* PLL_B Setup */
kenjiArai 0:47b9bfa03730 1069 { 34, 0x02 }, { 35, 0x71 }, { 36, 0x00 }, { 37, 0x0C },
kenjiArai 0:47b9bfa03730 1070 { 38, 0x1A }, { 39, 0x00 }, { 40, 0x00 }, { 41, 0x86 },
kenjiArai 0:47b9bfa03730 1071 /* Multisynth Setup */
kenjiArai 0:47b9bfa03730 1072 { 42, 0x00 }, { 43, 0x01 }, { 44, 0x00 }, { 45, 0x01 },
kenjiArai 0:47b9bfa03730 1073 { 46, 0x00 }, { 47, 0x00 }, { 48, 0x00 }, { 49, 0x00 },
kenjiArai 0:47b9bfa03730 1074 { 50, 0x00 }, { 51, 0x01 }, { 52, 0x00 }, { 53, 0x1C },
kenjiArai 0:47b9bfa03730 1075 { 54, 0x00 }, { 55, 0x00 }, { 56, 0x00 }, { 57, 0x00 },
kenjiArai 0:47b9bfa03730 1076 { 58, 0x00 }, { 59, 0x01 }, { 60, 0x00 }, { 61, 0x18 },
kenjiArai 0:47b9bfa03730 1077 { 62, 0x00 }, { 63, 0x00 }, { 64, 0x00 }, { 65, 0x00 },
kenjiArai 0:47b9bfa03730 1078 { 66, 0x00 }, { 67, 0x00 }, { 68, 0x00 }, { 69, 0x00 },
kenjiArai 0:47b9bfa03730 1079 { 70, 0x00 }, { 71, 0x00 }, { 72, 0x00 }, { 73, 0x00 },
kenjiArai 0:47b9bfa03730 1080 { 74, 0x00 }, { 75, 0x00 }, { 76, 0x00 }, { 77, 0x00 },
kenjiArai 0:47b9bfa03730 1081 { 78, 0x00 }, { 79, 0x00 }, { 80, 0x00 }, { 81, 0x00 },
kenjiArai 0:47b9bfa03730 1082 { 82, 0x00 }, { 83, 0x00 }, { 84, 0x00 }, { 85, 0x00 },
kenjiArai 0:47b9bfa03730 1083 { 86, 0x00 }, { 87, 0x00 }, { 88, 0x00 }, { 89, 0x00 },
kenjiArai 0:47b9bfa03730 1084 { 90, 0x00 }, { 91, 0x00 }, { 92, 0x00 },
kenjiArai 0:47b9bfa03730 1085 /* Misc Config Register */
kenjiArai 0:47b9bfa03730 1086 { 149, 0x00 }, { 150, 0x00 }, { 151, 0x00 }, { 152, 0x00 },
kenjiArai 0:47b9bfa03730 1087 { 153, 0x00 }, { 154, 0x00 }, { 155, 0x00 }, { 156, 0x00 },
kenjiArai 0:47b9bfa03730 1088 { 157, 0x00 }, { 158, 0x00 }, { 159, 0x00 }, { 160, 0x00 },
kenjiArai 0:47b9bfa03730 1089 { 161, 0x00 }, { 162, 0x00 }, { 163, 0x00 }, { 164, 0x00 },
kenjiArai 0:47b9bfa03730 1090 { 165, 0x00 }, { 166, 0x00 }, { 167, 0x00 }, { 168, 0x00 },
kenjiArai 0:47b9bfa03730 1091 { 169, 0x00 }, { 170, 0x00 }
kenjiArai 0:47b9bfa03730 1092 };
kenjiArai 0:47b9bfa03730 1093
kenjiArai 0:47b9bfa03730 1094 void SI5351A::debug_example_clock(void)
kenjiArai 0:47b9bfa03730 1095 {
kenjiArai 0:47b9bfa03730 1096 /* Disable all outputs setting CLKx_DIS high */
kenjiArai 0:47b9bfa03730 1097 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff);
kenjiArai 0:47b9bfa03730 1098 /* Writes configuration data to device using the register map contents
kenjiArai 0:47b9bfa03730 1099 generated by ClockBuilder Desktop (registers 15-92 + 149-170) */
kenjiArai 0:47b9bfa03730 1100 for (uint16_t i = 0; i < sizeof(m_si5351_regs_15to92_149to170)/2; i++){
kenjiArai 0:47b9bfa03730 1101 si5351_write(m_si5351_regs_15to92_149to170[i][0],
kenjiArai 0:47b9bfa03730 1102 m_si5351_regs_15to92_149to170[i][1]);
kenjiArai 0:47b9bfa03730 1103 }
kenjiArai 0:47b9bfa03730 1104 /* Apply soft reset */
kenjiArai 0:47b9bfa03730 1105 si5351_write(SI5351_REG_177_PLL_RESET, 0xac);
kenjiArai 0:47b9bfa03730 1106 /* Enabled desired outputs (see Register 3) */
kenjiArai 0:47b9bfa03730 1107 si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0x00);
kenjiArai 0:47b9bfa03730 1108 printf("Please check following output\r\n");
kenjiArai 0:47b9bfa03730 1109 printf("CLK0: 120.00MHz, CLK1: 12.00MHz, CLK2: 13.56MHz\r\n");
kenjiArai 0:47b9bfa03730 1110 }
kenjiArai 0:47b9bfa03730 1111
kenjiArai 0:47b9bfa03730 1112 //---------------------------------------------------------------------------------------------------------------------
kenjiArai 0:47b9bfa03730 1113 // Original & reference files
kenjiArai 0:47b9bfa03730 1114 //---------------------------------------------------------------------------------------------------------------------
kenjiArai 0:47b9bfa03730 1115 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
kenjiArai 0:47b9bfa03730 1116 // Adafruit_SI5351.cpp
kenjiArai 0:47b9bfa03730 1117 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
kenjiArai 0:47b9bfa03730 1118 #if 0
kenjiArai 0:47b9bfa03730 1119 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1120 /*!
kenjiArai 0:47b9bfa03730 1121 @file Adafruit_SI5351.cpp
kenjiArai 0:47b9bfa03730 1122 @author K. Townsend (Adafruit Industries)
kenjiArai 0:47b9bfa03730 1123
kenjiArai 0:47b9bfa03730 1124 @brief Driver for the SI5351 160MHz Clock Gen
kenjiArai 0:47b9bfa03730 1125
kenjiArai 0:47b9bfa03730 1126 @section REFERENCES
kenjiArai 0:47b9bfa03730 1127
kenjiArai 0:47b9bfa03730 1128 Si5351A/B/C Datasheet:
kenjiArai 0:47b9bfa03730 1129 http://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf
kenjiArai 0:47b9bfa03730 1130
kenjiArai 0:47b9bfa03730 1131 Manually Generating an Si5351 Register Map:
kenjiArai 0:47b9bfa03730 1132 http://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf
kenjiArai 0:47b9bfa03730 1133
kenjiArai 0:47b9bfa03730 1134 @section LICENSE
kenjiArai 0:47b9bfa03730 1135
kenjiArai 0:47b9bfa03730 1136 Software License Agreement (BSD License)
kenjiArai 0:47b9bfa03730 1137
kenjiArai 0:47b9bfa03730 1138 Copyright (c) 2014, Adafruit Industries
kenjiArai 0:47b9bfa03730 1139 All rights reserved.
kenjiArai 0:47b9bfa03730 1140
kenjiArai 0:47b9bfa03730 1141 Redistribution and use in source and binary forms, with or without
kenjiArai 0:47b9bfa03730 1142 modification, are permitted provided that the following conditions are met:
kenjiArai 0:47b9bfa03730 1143 1. Redistributions of source code must retain the above copyright
kenjiArai 0:47b9bfa03730 1144 notice, this list of conditions and the following disclaimer.
kenjiArai 0:47b9bfa03730 1145 2. Redistributions in binary form must reproduce the above copyright
kenjiArai 0:47b9bfa03730 1146 notice, this list of conditions and the following disclaimer in the
kenjiArai 0:47b9bfa03730 1147 documentation and/or other materials provided with the distribution.
kenjiArai 0:47b9bfa03730 1148 3. Neither the name of the copyright holders nor the
kenjiArai 0:47b9bfa03730 1149 names of its contributors may be used to endorse or promote products
kenjiArai 0:47b9bfa03730 1150 derived from this software without specific prior written permission.
kenjiArai 0:47b9bfa03730 1151
kenjiArai 0:47b9bfa03730 1152 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
kenjiArai 0:47b9bfa03730 1153 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
kenjiArai 0:47b9bfa03730 1154 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
kenjiArai 0:47b9bfa03730 1155 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
kenjiArai 0:47b9bfa03730 1156 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
kenjiArai 0:47b9bfa03730 1157 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
kenjiArai 0:47b9bfa03730 1158 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
kenjiArai 0:47b9bfa03730 1159 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
kenjiArai 0:47b9bfa03730 1160 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
kenjiArai 0:47b9bfa03730 1161 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
kenjiArai 0:47b9bfa03730 1162 */
kenjiArai 0:47b9bfa03730 1163 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1164 #if defined(__AVR__)
kenjiArai 0:47b9bfa03730 1165 #include <avr/pgmspace.h>
kenjiArai 0:47b9bfa03730 1166 #include <util/delay.h>
kenjiArai 0:47b9bfa03730 1167 #else
kenjiArai 0:47b9bfa03730 1168 #include "pgmspace.h"
kenjiArai 0:47b9bfa03730 1169 #endif
kenjiArai 0:47b9bfa03730 1170 #include <stdlib.h>
kenjiArai 0:47b9bfa03730 1171
kenjiArai 0:47b9bfa03730 1172 #include <Adafruit_SI5351.h>
kenjiArai 0:47b9bfa03730 1173
kenjiArai 0:47b9bfa03730 1174 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1175 /*!
kenjiArai 0:47b9bfa03730 1176 Constructor
kenjiArai 0:47b9bfa03730 1177 */
kenjiArai 0:47b9bfa03730 1178 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1179 Adafruit_SI5351::Adafruit_SI5351(void)
kenjiArai 0:47b9bfa03730 1180 {
kenjiArai 0:47b9bfa03730 1181 m_si5351Config.initialised = false;
kenjiArai 0:47b9bfa03730 1182 m_si5351Config.crystalFreq = SI5351_CRYSTAL_FREQ_25MHZ;
kenjiArai 0:47b9bfa03730 1183 m_si5351Config.crystalLoad = SI5351_CRYSTAL_LOAD_10PF;
kenjiArai 0:47b9bfa03730 1184 m_si5351Config.crystalPPM = 30;
kenjiArai 0:47b9bfa03730 1185 m_si5351Config.plla_configured = false;
kenjiArai 0:47b9bfa03730 1186 m_si5351Config.plla_freq = 0;
kenjiArai 0:47b9bfa03730 1187 m_si5351Config.pllb_configured = false;
kenjiArai 0:47b9bfa03730 1188 m_si5351Config.pllb_freq = 0;
kenjiArai 0:47b9bfa03730 1189 }
kenjiArai 0:47b9bfa03730 1190
kenjiArai 0:47b9bfa03730 1191 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1192 /*!
kenjiArai 0:47b9bfa03730 1193 Initializes I2C and configures the breakout (call this function before
kenjiArai 0:47b9bfa03730 1194 doing anything else)
kenjiArai 0:47b9bfa03730 1195 */
kenjiArai 0:47b9bfa03730 1196 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1197 err_t Adafruit_SI5351::begin(void)
kenjiArai 0:47b9bfa03730 1198 {
kenjiArai 0:47b9bfa03730 1199 /* Initialise I2C */
kenjiArai 0:47b9bfa03730 1200 Wire.begin();
kenjiArai 0:47b9bfa03730 1201
kenjiArai 0:47b9bfa03730 1202 /* ToDo: Make sure we're actually connected */
kenjiArai 0:47b9bfa03730 1203
kenjiArai 0:47b9bfa03730 1204 /* Disable all outputs setting CLKx_DIS high */
kenjiArai 0:47b9bfa03730 1205 ASSERT_STATUS(write8(SI5351_REGISTER_3_OUTPUT_ENABLE_CONTROL, 0xFF));
kenjiArai 0:47b9bfa03730 1206
kenjiArai 0:47b9bfa03730 1207 /* Power down all output drivers */
kenjiArai 0:47b9bfa03730 1208 ASSERT_STATUS(write8(SI5351_REGISTER_16_CLK0_CONTROL, 0x80));
kenjiArai 0:47b9bfa03730 1209 ASSERT_STATUS(write8(SI5351_REGISTER_17_CLK1_CONTROL, 0x80));
kenjiArai 0:47b9bfa03730 1210 ASSERT_STATUS(write8(SI5351_REGISTER_18_CLK2_CONTROL, 0x80));
kenjiArai 0:47b9bfa03730 1211 ASSERT_STATUS(write8(SI5351_REGISTER_19_CLK3_CONTROL, 0x80));
kenjiArai 0:47b9bfa03730 1212 ASSERT_STATUS(write8(SI5351_REGISTER_20_CLK4_CONTROL, 0x80));
kenjiArai 0:47b9bfa03730 1213 ASSERT_STATUS(write8(SI5351_REGISTER_21_CLK5_CONTROL, 0x80));
kenjiArai 0:47b9bfa03730 1214 ASSERT_STATUS(write8(SI5351_REGISTER_22_CLK6_CONTROL, 0x80));
kenjiArai 0:47b9bfa03730 1215 ASSERT_STATUS(write8(SI5351_REGISTER_23_CLK7_CONTROL, 0x80));
kenjiArai 0:47b9bfa03730 1216
kenjiArai 0:47b9bfa03730 1217 /* Set the load capacitance for the XTAL */
kenjiArai 0:47b9bfa03730 1218 ASSERT_STATUS(write8(SI5351_REGISTER_183_CRYSTAL_INTERNAL_LOAD_CAPACITANCE,
kenjiArai 0:47b9bfa03730 1219 m_si5351Config.crystalLoad));
kenjiArai 0:47b9bfa03730 1220
kenjiArai 0:47b9bfa03730 1221 /* Set interrupt masks as required (see Register 2 description in AN619).
kenjiArai 0:47b9bfa03730 1222 By default, ClockBuilder Desktop sets this register to 0x18.
kenjiArai 0:47b9bfa03730 1223 Note that the least significant nibble must remain 0x8, but the most
kenjiArai 0:47b9bfa03730 1224 significant nibble may be modified to suit your needs. */
kenjiArai 0:47b9bfa03730 1225
kenjiArai 0:47b9bfa03730 1226 /* Reset the PLL config fields just in case we call init again */
kenjiArai 0:47b9bfa03730 1227 m_si5351Config.plla_configured = false;
kenjiArai 0:47b9bfa03730 1228 m_si5351Config.plla_freq = 0;
kenjiArai 0:47b9bfa03730 1229 m_si5351Config.pllb_configured = false;
kenjiArai 0:47b9bfa03730 1230 m_si5351Config.pllb_freq = 0;
kenjiArai 0:47b9bfa03730 1231
kenjiArai 0:47b9bfa03730 1232 /* All done! */
kenjiArai 0:47b9bfa03730 1233 m_si5351Config.initialised = true;
kenjiArai 0:47b9bfa03730 1234
kenjiArai 0:47b9bfa03730 1235 return ERROR_NONE;
kenjiArai 0:47b9bfa03730 1236 }
kenjiArai 0:47b9bfa03730 1237
kenjiArai 0:47b9bfa03730 1238 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1239 /*!
kenjiArai 0:47b9bfa03730 1240 @brief Configures the Si5351 with config settings generated in
kenjiArai 0:47b9bfa03730 1241 ClockBuilder. You can use this function to make sure that
kenjiArai 0:47b9bfa03730 1242 your HW is properly configure and that there are no problems
kenjiArai 0:47b9bfa03730 1243 with the board itself.
kenjiArai 0:47b9bfa03730 1244
kenjiArai 0:47b9bfa03730 1245 Running this function should provide the following output:
kenjiArai 0:47b9bfa03730 1246 * Channel 0: 120.00 MHz
kenjiArai 0:47b9bfa03730 1247 * Channel 1: 12.00 MHz
kenjiArai 0:47b9bfa03730 1248 * Channel 2: 13.56 MHz
kenjiArai 0:47b9bfa03730 1249
kenjiArai 0:47b9bfa03730 1250 @note This will overwrite all of the config registers!
kenjiArai 0:47b9bfa03730 1251 */
kenjiArai 0:47b9bfa03730 1252 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1253 err_t Adafruit_SI5351::setClockBuilderData(void)
kenjiArai 0:47b9bfa03730 1254 {
kenjiArai 0:47b9bfa03730 1255 uint16_t i = 0;
kenjiArai 0:47b9bfa03730 1256
kenjiArai 0:47b9bfa03730 1257 /* Make sure we've called init first */
kenjiArai 0:47b9bfa03730 1258 ASSERT(m_si5351Config.initialised, ERROR_DEVICENOTINITIALISED);
kenjiArai 0:47b9bfa03730 1259
kenjiArai 0:47b9bfa03730 1260 /* Disable all outputs setting CLKx_DIS high */
kenjiArai 0:47b9bfa03730 1261 ASSERT_STATUS(write8(SI5351_REGISTER_3_OUTPUT_ENABLE_CONTROL, 0xFF));
kenjiArai 0:47b9bfa03730 1262
kenjiArai 0:47b9bfa03730 1263 /* Writes configuration data to device using the register map contents
kenjiArai 0:47b9bfa03730 1264 generated by ClockBuilder Desktop (registers 15-92 + 149-170) */
kenjiArai 0:47b9bfa03730 1265 for (i=0; i<sizeof(m_si5351_regs_15to92_149to170)/2; i++)
kenjiArai 0:47b9bfa03730 1266 {
kenjiArai 0:47b9bfa03730 1267 ASSERT_STATUS(write8( m_si5351_regs_15to92_149to170[i][0],
kenjiArai 0:47b9bfa03730 1268 m_si5351_regs_15to92_149to170[i][1] ));
kenjiArai 0:47b9bfa03730 1269 }
kenjiArai 0:47b9bfa03730 1270
kenjiArai 0:47b9bfa03730 1271 /* Apply soft reset */
kenjiArai 0:47b9bfa03730 1272 ASSERT_STATUS(write8(SI5351_REGISTER_177_PLL_RESET, 0xAC));
kenjiArai 0:47b9bfa03730 1273
kenjiArai 0:47b9bfa03730 1274 /* Enabled desired outputs (see Register 3) */
kenjiArai 0:47b9bfa03730 1275 ASSERT_STATUS(write8(SI5351_REGISTER_3_OUTPUT_ENABLE_CONTROL, 0x00));
kenjiArai 0:47b9bfa03730 1276
kenjiArai 0:47b9bfa03730 1277 return ERROR_NONE;
kenjiArai 0:47b9bfa03730 1278 }
kenjiArai 0:47b9bfa03730 1279
kenjiArai 0:47b9bfa03730 1280 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1281 /*!
kenjiArai 0:47b9bfa03730 1282 @brief Sets the multiplier for the specified PLL using integer values
kenjiArai 0:47b9bfa03730 1283
kenjiArai 0:47b9bfa03730 1284 @param pll The PLL to configure, which must be one of the following:
kenjiArai 0:47b9bfa03730 1285 - SI5351_PLL_A
kenjiArai 0:47b9bfa03730 1286 - SI5351_PLL_B
kenjiArai 0:47b9bfa03730 1287 @param mult The PLL integer multiplier (must be between 15 and 90)
kenjiArai 0:47b9bfa03730 1288 */
kenjiArai 0:47b9bfa03730 1289 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1290 err_t Adafruit_SI5351::setupPLLInt(si5351PLL_t pll, uint8_t mult)
kenjiArai 0:47b9bfa03730 1291 {
kenjiArai 0:47b9bfa03730 1292 return setupPLL(pll, mult, 0, 1);
kenjiArai 0:47b9bfa03730 1293 }
kenjiArai 0:47b9bfa03730 1294
kenjiArai 0:47b9bfa03730 1295 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1296 /*!
kenjiArai 0:47b9bfa03730 1297 @brief Sets the multiplier for the specified PLL
kenjiArai 0:47b9bfa03730 1298
kenjiArai 0:47b9bfa03730 1299 @param pll The PLL to configure, which must be one of the following:
kenjiArai 0:47b9bfa03730 1300 - SI5351_PLL_A
kenjiArai 0:47b9bfa03730 1301 - SI5351_PLL_B
kenjiArai 0:47b9bfa03730 1302 @param mult The PLL integer multiplier (must be between 15 and 90)
kenjiArai 0:47b9bfa03730 1303 @param num The 20-bit numerator for fractional output (0..1,048,575).
kenjiArai 0:47b9bfa03730 1304 Set this to '0' for integer output.
kenjiArai 0:47b9bfa03730 1305 @param denom The 20-bit denominator for fractional output (1..1,048,575).
kenjiArai 0:47b9bfa03730 1306 Set this to '1' or higher to avoid divider by zero errors.
kenjiArai 0:47b9bfa03730 1307
kenjiArai 0:47b9bfa03730 1308 @section PLL Configuration
kenjiArai 0:47b9bfa03730 1309
kenjiArai 0:47b9bfa03730 1310 fVCO is the PLL output, and must be between 600..900MHz, where:
kenjiArai 0:47b9bfa03730 1311
kenjiArai 0:47b9bfa03730 1312 fVCO = fXTAL * (a+(b/c))
kenjiArai 0:47b9bfa03730 1313
kenjiArai 0:47b9bfa03730 1314 fXTAL = the crystal input frequency
kenjiArai 0:47b9bfa03730 1315 a = an integer between 15 and 90
kenjiArai 0:47b9bfa03730 1316 b = the fractional numerator (0..1,048,575)
kenjiArai 0:47b9bfa03730 1317 c = the fractional denominator (1..1,048,575)
kenjiArai 0:47b9bfa03730 1318
kenjiArai 0:47b9bfa03730 1319 NOTE: Try to use integers whenever possible to avoid clock jitter
kenjiArai 0:47b9bfa03730 1320 (only use the a part, setting b to '0' and c to '1').
kenjiArai 0:47b9bfa03730 1321
kenjiArai 0:47b9bfa03730 1322 See: http://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf
kenjiArai 0:47b9bfa03730 1323 */
kenjiArai 0:47b9bfa03730 1324 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1325 err_t Adafruit_SI5351::setupPLL(si5351PLL_t pll,
kenjiArai 0:47b9bfa03730 1326 uint8_t mult,
kenjiArai 0:47b9bfa03730 1327 uint32_t num,
kenjiArai 0:47b9bfa03730 1328 uint32_t denom)
kenjiArai 0:47b9bfa03730 1329 {
kenjiArai 0:47b9bfa03730 1330 uint32_t P1; /* PLL config register P1 */
kenjiArai 0:47b9bfa03730 1331 uint32_t P2; /* PLL config register P2 */
kenjiArai 0:47b9bfa03730 1332 uint32_t P3; /* PLL config register P3 */
kenjiArai 0:47b9bfa03730 1333
kenjiArai 0:47b9bfa03730 1334 /* Basic validation */
kenjiArai 0:47b9bfa03730 1335 ASSERT( m_si5351Config.initialised, ERROR_DEVICENOTINITIALISED );
kenjiArai 0:47b9bfa03730 1336 ASSERT( (mult > 14) && (mult < 91), ERROR_INVALIDPARAMETER ); /* mult = 15..90 */
kenjiArai 0:47b9bfa03730 1337 ASSERT( denom > 0, ERROR_INVALIDPARAMETER ); /* Avoid divide by zero */
kenjiArai 0:47b9bfa03730 1338 ASSERT( num <= 0xFFFFF, ERROR_INVALIDPARAMETER ); /* 20-bit limit */
kenjiArai 0:47b9bfa03730 1339 ASSERT( denom <= 0xFFFFF, ERROR_INVALIDPARAMETER ); /* 20-bit limit */
kenjiArai 0:47b9bfa03730 1340
kenjiArai 0:47b9bfa03730 1341 /* Feedback Multisynth Divider Equation
kenjiArai 0:47b9bfa03730 1342 *
kenjiArai 0:47b9bfa03730 1343 * where: a = mult, b = num and c = denom
kenjiArai 0:47b9bfa03730 1344 *
kenjiArai 0:47b9bfa03730 1345 * P1 register is an 18-bit value using following formula:
kenjiArai 0:47b9bfa03730 1346 *
kenjiArai 0:47b9bfa03730 1347 * P1[17:0] = 128 * mult + floor(128*(num/denom)) - 512
kenjiArai 0:47b9bfa03730 1348 *
kenjiArai 0:47b9bfa03730 1349 * P2 register is a 20-bit value using the following formula:
kenjiArai 0:47b9bfa03730 1350 *
kenjiArai 0:47b9bfa03730 1351 * P2[19:0] = 128 * num - denom * floor(128*(num/denom))
kenjiArai 0:47b9bfa03730 1352 *
kenjiArai 0:47b9bfa03730 1353 * P3 register is a 20-bit value using the following formula:
kenjiArai 0:47b9bfa03730 1354 *
kenjiArai 0:47b9bfa03730 1355 * P3[19:0] = denom
kenjiArai 0:47b9bfa03730 1356 */
kenjiArai 0:47b9bfa03730 1357
kenjiArai 0:47b9bfa03730 1358 /* Set the main PLL config registers */
kenjiArai 0:47b9bfa03730 1359 if (num == 0)
kenjiArai 0:47b9bfa03730 1360 {
kenjiArai 0:47b9bfa03730 1361 /* Integer mode */
kenjiArai 0:47b9bfa03730 1362 P1 = 128 * mult - 512;
kenjiArai 0:47b9bfa03730 1363 P2 = num;
kenjiArai 0:47b9bfa03730 1364 P3 = denom;
kenjiArai 0:47b9bfa03730 1365 }
kenjiArai 0:47b9bfa03730 1366 else
kenjiArai 0:47b9bfa03730 1367 {
kenjiArai 0:47b9bfa03730 1368 /* Fractional mode */
kenjiArai 0:47b9bfa03730 1369 P1 = (uint32_t)(128 * mult + floor(128 * ((float)num/(float)denom)) - 512);
kenjiArai 0:47b9bfa03730 1370 P2 = (uint32_t)(128 * num - denom * floor(128 * ((float)num/(float)denom)));
kenjiArai 0:47b9bfa03730 1371 P3 = denom;
kenjiArai 0:47b9bfa03730 1372 }
kenjiArai 0:47b9bfa03730 1373
kenjiArai 0:47b9bfa03730 1374 /* Get the appropriate starting point for the PLL registers */
kenjiArai 0:47b9bfa03730 1375 uint8_t baseaddr = (pll == SI5351_PLL_A ? 26 : 34);
kenjiArai 0:47b9bfa03730 1376
kenjiArai 0:47b9bfa03730 1377 /* The datasheet is a nightmare of typos and inconsistencies here! */
kenjiArai 0:47b9bfa03730 1378 ASSERT_STATUS( write8( baseaddr, (P3 & 0x0000FF00) >> 8));
kenjiArai 0:47b9bfa03730 1379 ASSERT_STATUS( write8( baseaddr+1, (P3 & 0x000000FF)));
kenjiArai 0:47b9bfa03730 1380 ASSERT_STATUS( write8( baseaddr+2, (P1 & 0x00030000) >> 16));
kenjiArai 0:47b9bfa03730 1381 ASSERT_STATUS( write8( baseaddr+3, (P1 & 0x0000FF00) >> 8));
kenjiArai 0:47b9bfa03730 1382 ASSERT_STATUS( write8( baseaddr+4, (P1 & 0x000000FF)));
kenjiArai 0:47b9bfa03730 1383 ASSERT_STATUS( write8( baseaddr+5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16) ));
kenjiArai 0:47b9bfa03730 1384 ASSERT_STATUS( write8( baseaddr+6, (P2 & 0x0000FF00) >> 8));
kenjiArai 0:47b9bfa03730 1385 ASSERT_STATUS( write8( baseaddr+7, (P2 & 0x000000FF)));
kenjiArai 0:47b9bfa03730 1386
kenjiArai 0:47b9bfa03730 1387 /* Reset both PLLs */
kenjiArai 0:47b9bfa03730 1388 ASSERT_STATUS( write8(SI5351_REGISTER_177_PLL_RESET, (1<<7) | (1<<5) ));
kenjiArai 0:47b9bfa03730 1389
kenjiArai 0:47b9bfa03730 1390 /* Store the frequency settings for use with the Multisynth helper */
kenjiArai 0:47b9bfa03730 1391 if (pll == SI5351_PLL_A)
kenjiArai 0:47b9bfa03730 1392 {
kenjiArai 0:47b9bfa03730 1393 float fvco = m_si5351Config.crystalFreq * (mult + ( (float)num / (float)denom ));
kenjiArai 0:47b9bfa03730 1394 m_si5351Config.plla_configured = true;
kenjiArai 0:47b9bfa03730 1395 m_si5351Config.plla_freq = (uint32_t)floor(fvco);
kenjiArai 0:47b9bfa03730 1396 }
kenjiArai 0:47b9bfa03730 1397 else
kenjiArai 0:47b9bfa03730 1398 {
kenjiArai 0:47b9bfa03730 1399 float fvco = m_si5351Config.crystalFreq * (mult + ( (float)num / (float)denom ));
kenjiArai 0:47b9bfa03730 1400 m_si5351Config.pllb_configured = true;
kenjiArai 0:47b9bfa03730 1401 m_si5351Config.pllb_freq = (uint32_t)floor(fvco);
kenjiArai 0:47b9bfa03730 1402 }
kenjiArai 0:47b9bfa03730 1403
kenjiArai 0:47b9bfa03730 1404 return ERROR_NONE;
kenjiArai 0:47b9bfa03730 1405 }
kenjiArai 0:47b9bfa03730 1406
kenjiArai 0:47b9bfa03730 1407 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1408 /*!
kenjiArai 0:47b9bfa03730 1409 @brief Configures the Multisynth divider using integer output.
kenjiArai 0:47b9bfa03730 1410
kenjiArai 0:47b9bfa03730 1411 @param output The output channel to use (0..2)
kenjiArai 0:47b9bfa03730 1412 @param pllSource The PLL input source to use, which must be one of:
kenjiArai 0:47b9bfa03730 1413 - SI5351_PLL_A
kenjiArai 0:47b9bfa03730 1414 - SI5351_PLL_B
kenjiArai 0:47b9bfa03730 1415 @param div The integer divider for the Multisynth output,
kenjiArai 0:47b9bfa03730 1416 which must be one of the following values:
kenjiArai 0:47b9bfa03730 1417 - SI5351_MULTISYNTH_DIV_4
kenjiArai 0:47b9bfa03730 1418 - SI5351_MULTISYNTH_DIV_6
kenjiArai 0:47b9bfa03730 1419 - SI5351_MULTISYNTH_DIV_8
kenjiArai 0:47b9bfa03730 1420 */
kenjiArai 0:47b9bfa03730 1421 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1422 err_t Adafruit_SI5351::setupMultisynthInt(uint8_t output,
kenjiArai 0:47b9bfa03730 1423 si5351PLL_t pllSource,
kenjiArai 0:47b9bfa03730 1424 si5351MultisynthDiv_t div)
kenjiArai 0:47b9bfa03730 1425 {
kenjiArai 0:47b9bfa03730 1426 return setupMultisynth(output, pllSource, div, 0, 1);
kenjiArai 0:47b9bfa03730 1427 }
kenjiArai 0:47b9bfa03730 1428
kenjiArai 0:47b9bfa03730 1429
kenjiArai 0:47b9bfa03730 1430 err_t Adafruit_SI5351::setupRdiv(uint8_t output, si5351RDiv_t div) {
kenjiArai 0:47b9bfa03730 1431 ASSERT( output < 3, ERROR_INVALIDPARAMETER); /* Channel range */
kenjiArai 0:47b9bfa03730 1432
kenjiArai 0:47b9bfa03730 1433 uint8_t Rreg, regval;
kenjiArai 0:47b9bfa03730 1434
kenjiArai 0:47b9bfa03730 1435 if (output == 0) Rreg = SI5351_REGISTER_44_MULTISYNTH0_PARAMETERS_3;
kenjiArai 0:47b9bfa03730 1436 if (output == 1) Rreg = SI5351_REGISTER_52_MULTISYNTH1_PARAMETERS_3;
kenjiArai 0:47b9bfa03730 1437 if (output == 2) Rreg = SI5351_REGISTER_60_MULTISYNTH2_PARAMETERS_3;
kenjiArai 0:47b9bfa03730 1438
kenjiArai 0:47b9bfa03730 1439 read8(Rreg, &regval);
kenjiArai 0:47b9bfa03730 1440
kenjiArai 0:47b9bfa03730 1441 regval &= 0x0F;
kenjiArai 0:47b9bfa03730 1442 uint8_t divider = div;
kenjiArai 0:47b9bfa03730 1443 divider &= 0x07;
kenjiArai 0:47b9bfa03730 1444 divider <<= 4;
kenjiArai 0:47b9bfa03730 1445 regval |= divider;
kenjiArai 0:47b9bfa03730 1446 return write8(Rreg, regval);
kenjiArai 0:47b9bfa03730 1447 }
kenjiArai 0:47b9bfa03730 1448
kenjiArai 0:47b9bfa03730 1449 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1450 /*!
kenjiArai 0:47b9bfa03730 1451 @brief Configures the Multisynth divider, which determines the
kenjiArai 0:47b9bfa03730 1452 output clock frequency based on the specified PLL input.
kenjiArai 0:47b9bfa03730 1453
kenjiArai 0:47b9bfa03730 1454 @param output The output channel to use (0..2)
kenjiArai 0:47b9bfa03730 1455 @param pllSource The PLL input source to use, which must be one of:
kenjiArai 0:47b9bfa03730 1456 - SI5351_PLL_A
kenjiArai 0:47b9bfa03730 1457 - SI5351_PLL_B
kenjiArai 0:47b9bfa03730 1458 @param div The integer divider for the Multisynth output.
kenjiArai 0:47b9bfa03730 1459 If pure integer values are used, this value must
kenjiArai 0:47b9bfa03730 1460 be one of:
kenjiArai 0:47b9bfa03730 1461 - SI5351_MULTISYNTH_DIV_4
kenjiArai 0:47b9bfa03730 1462 - SI5351_MULTISYNTH_DIV_6
kenjiArai 0:47b9bfa03730 1463 - SI5351_MULTISYNTH_DIV_8
kenjiArai 0:47b9bfa03730 1464 If fractional output is used, this value must be
kenjiArai 0:47b9bfa03730 1465 between 8 and 900.
kenjiArai 0:47b9bfa03730 1466 @param num The 20-bit numerator for fractional output
kenjiArai 0:47b9bfa03730 1467 (0..1,048,575). Set this to '0' for integer output.
kenjiArai 0:47b9bfa03730 1468 @param denom The 20-bit denominator for fractional output
kenjiArai 0:47b9bfa03730 1469 (1..1,048,575). Set this to '1' or higher to
kenjiArai 0:47b9bfa03730 1470 avoid divide by zero errors.
kenjiArai 0:47b9bfa03730 1471
kenjiArai 0:47b9bfa03730 1472 @section Output Clock Configuration
kenjiArai 0:47b9bfa03730 1473
kenjiArai 0:47b9bfa03730 1474 The multisynth dividers are applied to the specified PLL output,
kenjiArai 0:47b9bfa03730 1475 and are used to reduce the PLL output to a valid range (500kHz
kenjiArai 0:47b9bfa03730 1476 to 160MHz). The relationship can be seen in this formula, where
kenjiArai 0:47b9bfa03730 1477 fVCO is the PLL output frequency and MSx is the multisynth
kenjiArai 0:47b9bfa03730 1478 divider:
kenjiArai 0:47b9bfa03730 1479
kenjiArai 0:47b9bfa03730 1480 fOUT = fVCO / MSx
kenjiArai 0:47b9bfa03730 1481
kenjiArai 0:47b9bfa03730 1482 Valid multisynth dividers are 4, 6, or 8 when using integers,
kenjiArai 0:47b9bfa03730 1483 or any fractional values between 8 + 1/1,048,575 and 900 + 0/1
kenjiArai 0:47b9bfa03730 1484
kenjiArai 0:47b9bfa03730 1485 The following formula is used for the fractional mode divider:
kenjiArai 0:47b9bfa03730 1486
kenjiArai 0:47b9bfa03730 1487 a + b / c
kenjiArai 0:47b9bfa03730 1488
kenjiArai 0:47b9bfa03730 1489 a = The integer value, which must be 4, 6 or 8 in integer mode (MSx_INT=1)
kenjiArai 0:47b9bfa03730 1490 or 8..900 in fractional mode (MSx_INT=0).
kenjiArai 0:47b9bfa03730 1491 b = The fractional numerator (0..1,048,575)
kenjiArai 0:47b9bfa03730 1492 c = The fractional denominator (1..1,048,575)
kenjiArai 0:47b9bfa03730 1493
kenjiArai 0:47b9bfa03730 1494 @note Try to use integers whenever possible to avoid clock jitter
kenjiArai 0:47b9bfa03730 1495
kenjiArai 0:47b9bfa03730 1496 @note For output frequencies > 150MHz, you must set the divider
kenjiArai 0:47b9bfa03730 1497 to 4 and adjust to PLL to generate the frequency (for example
kenjiArai 0:47b9bfa03730 1498 a PLL of 640 to generate a 160MHz output clock). This is not
kenjiArai 0:47b9bfa03730 1499 yet supported in the driver, which limits frequencies to
kenjiArai 0:47b9bfa03730 1500 500kHz .. 150MHz.
kenjiArai 0:47b9bfa03730 1501
kenjiArai 0:47b9bfa03730 1502 @note For frequencies below 500kHz (down to 8kHz) Rx_DIV must be
kenjiArai 0:47b9bfa03730 1503 used, but this isn't currently implemented in the driver.
kenjiArai 0:47b9bfa03730 1504 */
kenjiArai 0:47b9bfa03730 1505 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1506 err_t Adafruit_SI5351::setupMultisynth(uint8_t output,
kenjiArai 0:47b9bfa03730 1507 si5351PLL_t pllSource,
kenjiArai 0:47b9bfa03730 1508 uint32_t div,
kenjiArai 0:47b9bfa03730 1509 uint32_t num,
kenjiArai 0:47b9bfa03730 1510 uint32_t denom)
kenjiArai 0:47b9bfa03730 1511 {
kenjiArai 0:47b9bfa03730 1512 uint32_t P1; /* Multisynth config register P1 */
kenjiArai 0:47b9bfa03730 1513 uint32_t P2; /* Multisynth config register P2 */
kenjiArai 0:47b9bfa03730 1514 uint32_t P3; /* Multisynth config register P3 */
kenjiArai 0:47b9bfa03730 1515
kenjiArai 0:47b9bfa03730 1516 /* Basic validation */
kenjiArai 0:47b9bfa03730 1517 ASSERT( m_si5351Config.initialised, ERROR_DEVICENOTINITIALISED);
kenjiArai 0:47b9bfa03730 1518 ASSERT( output < 3, ERROR_INVALIDPARAMETER); /* Channel range */
kenjiArai 0:47b9bfa03730 1519 ASSERT( div > 3, ERROR_INVALIDPARAMETER); /* Divider integer value */
kenjiArai 0:47b9bfa03730 1520 ASSERT( div < 901, ERROR_INVALIDPARAMETER); /* Divider integer value */
kenjiArai 0:47b9bfa03730 1521 ASSERT( denom > 0, ERROR_INVALIDPARAMETER ); /* Avoid divide by zero */
kenjiArai 0:47b9bfa03730 1522 ASSERT( num <= 0xFFFFF, ERROR_INVALIDPARAMETER ); /* 20-bit limit */
kenjiArai 0:47b9bfa03730 1523 ASSERT( denom <= 0xFFFFF, ERROR_INVALIDPARAMETER ); /* 20-bit limit */
kenjiArai 0:47b9bfa03730 1524
kenjiArai 0:47b9bfa03730 1525 /* Make sure the requested PLL has been initialised */
kenjiArai 0:47b9bfa03730 1526 if (pllSource == SI5351_PLL_A)
kenjiArai 0:47b9bfa03730 1527 {
kenjiArai 0:47b9bfa03730 1528 ASSERT(m_si5351Config.plla_configured = true, ERROR_INVALIDPARAMETER);
kenjiArai 0:47b9bfa03730 1529 }
kenjiArai 0:47b9bfa03730 1530 else
kenjiArai 0:47b9bfa03730 1531 {
kenjiArai 0:47b9bfa03730 1532 ASSERT(m_si5351Config.pllb_configured = true, ERROR_INVALIDPARAMETER);
kenjiArai 0:47b9bfa03730 1533 }
kenjiArai 0:47b9bfa03730 1534
kenjiArai 0:47b9bfa03730 1535 /* Output Multisynth Divider Equations
kenjiArai 0:47b9bfa03730 1536 *
kenjiArai 0:47b9bfa03730 1537 * where: a = div, b = num and c = denom
kenjiArai 0:47b9bfa03730 1538 *
kenjiArai 0:47b9bfa03730 1539 * P1 register is an 18-bit value using following formula:
kenjiArai 0:47b9bfa03730 1540 *
kenjiArai 0:47b9bfa03730 1541 * P1[17:0] = 128 * a + floor(128*(b/c)) - 512
kenjiArai 0:47b9bfa03730 1542 *
kenjiArai 0:47b9bfa03730 1543 * P2 register is a 20-bit value using the following formula:
kenjiArai 0:47b9bfa03730 1544 *
kenjiArai 0:47b9bfa03730 1545 * P2[19:0] = 128 * b - c * floor(128*(b/c))
kenjiArai 0:47b9bfa03730 1546 *
kenjiArai 0:47b9bfa03730 1547 * P3 register is a 20-bit value using the following formula:
kenjiArai 0:47b9bfa03730 1548 *
kenjiArai 0:47b9bfa03730 1549 * P3[19:0] = c
kenjiArai 0:47b9bfa03730 1550 */
kenjiArai 0:47b9bfa03730 1551
kenjiArai 0:47b9bfa03730 1552 /* Set the main PLL config registers */
kenjiArai 0:47b9bfa03730 1553 if (num == 0)
kenjiArai 0:47b9bfa03730 1554 {
kenjiArai 0:47b9bfa03730 1555 /* Integer mode */
kenjiArai 0:47b9bfa03730 1556 P1 = 128 * div - 512;
kenjiArai 0:47b9bfa03730 1557 P2 = num;
kenjiArai 0:47b9bfa03730 1558 P3 = denom;
kenjiArai 0:47b9bfa03730 1559 }
kenjiArai 0:47b9bfa03730 1560 else
kenjiArai 0:47b9bfa03730 1561 {
kenjiArai 0:47b9bfa03730 1562 /* Fractional mode */
kenjiArai 0:47b9bfa03730 1563 P1 = (uint32_t)(128 * div + floor(128 * ((float)num/(float)denom)) - 512);
kenjiArai 0:47b9bfa03730 1564 P2 = (uint32_t)(128 * num - denom * floor(128 * ((float)num/(float)denom)));
kenjiArai 0:47b9bfa03730 1565 P3 = denom;
kenjiArai 0:47b9bfa03730 1566 }
kenjiArai 0:47b9bfa03730 1567
kenjiArai 0:47b9bfa03730 1568 /* Get the appropriate starting point for the PLL registers */
kenjiArai 0:47b9bfa03730 1569 uint8_t baseaddr = 0;
kenjiArai 0:47b9bfa03730 1570 switch (output)
kenjiArai 0:47b9bfa03730 1571 {
kenjiArai 0:47b9bfa03730 1572 case 0:
kenjiArai 0:47b9bfa03730 1573 baseaddr = SI5351_REGISTER_42_MULTISYNTH0_PARAMETERS_1;
kenjiArai 0:47b9bfa03730 1574 break;
kenjiArai 0:47b9bfa03730 1575 case 1:
kenjiArai 0:47b9bfa03730 1576 baseaddr = SI5351_REGISTER_50_MULTISYNTH1_PARAMETERS_1;
kenjiArai 0:47b9bfa03730 1577 break;
kenjiArai 0:47b9bfa03730 1578 case 2:
kenjiArai 0:47b9bfa03730 1579 baseaddr = SI5351_REGISTER_58_MULTISYNTH2_PARAMETERS_1;
kenjiArai 0:47b9bfa03730 1580 break;
kenjiArai 0:47b9bfa03730 1581 }
kenjiArai 0:47b9bfa03730 1582
kenjiArai 0:47b9bfa03730 1583 /* Set the MSx config registers */
kenjiArai 0:47b9bfa03730 1584 ASSERT_STATUS( write8( baseaddr, (P3 & 0x0000FF00) >> 8));
kenjiArai 0:47b9bfa03730 1585 ASSERT_STATUS( write8( baseaddr+1, (P3 & 0x000000FF)));
kenjiArai 0:47b9bfa03730 1586 ASSERT_STATUS( write8( baseaddr+2, (P1 & 0x00030000) >> 16)); /* ToDo: Add DIVBY4 (>150MHz) and R0 support (<500kHz) later */
kenjiArai 0:47b9bfa03730 1587 ASSERT_STATUS( write8( baseaddr+3, (P1 & 0x0000FF00) >> 8));
kenjiArai 0:47b9bfa03730 1588 ASSERT_STATUS( write8( baseaddr+4, (P1 & 0x000000FF)));
kenjiArai 0:47b9bfa03730 1589 ASSERT_STATUS( write8( baseaddr+5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16) ));
kenjiArai 0:47b9bfa03730 1590 ASSERT_STATUS( write8( baseaddr+6, (P2 & 0x0000FF00) >> 8));
kenjiArai 0:47b9bfa03730 1591 ASSERT_STATUS( write8( baseaddr+7, (P2 & 0x000000FF)));
kenjiArai 0:47b9bfa03730 1592
kenjiArai 0:47b9bfa03730 1593 /* Configure the clk control and enable the output */
kenjiArai 0:47b9bfa03730 1594 uint8_t clkControlReg = 0x0F; /* 8mA drive strength, MS0 as CLK0 source, Clock not inverted, powered up */
kenjiArai 0:47b9bfa03730 1595 if (pllSource == SI5351_PLL_B) clkControlReg |= (1 << 5); /* Uses PLLB */
kenjiArai 0:47b9bfa03730 1596 if (num == 0) clkControlReg |= (1 << 6); /* Integer mode */
kenjiArai 0:47b9bfa03730 1597 switch (output)
kenjiArai 0:47b9bfa03730 1598 {
kenjiArai 0:47b9bfa03730 1599 case 0:
kenjiArai 0:47b9bfa03730 1600 ASSERT_STATUS(write8(SI5351_REGISTER_16_CLK0_CONTROL, clkControlReg));
kenjiArai 0:47b9bfa03730 1601 break;
kenjiArai 0:47b9bfa03730 1602 case 1:
kenjiArai 0:47b9bfa03730 1603 ASSERT_STATUS(write8(SI5351_REGISTER_17_CLK1_CONTROL, clkControlReg));
kenjiArai 0:47b9bfa03730 1604 break;
kenjiArai 0:47b9bfa03730 1605 case 2:
kenjiArai 0:47b9bfa03730 1606 ASSERT_STATUS(write8(SI5351_REGISTER_18_CLK2_CONTROL, clkControlReg));
kenjiArai 0:47b9bfa03730 1607 break;
kenjiArai 0:47b9bfa03730 1608 }
kenjiArai 0:47b9bfa03730 1609
kenjiArai 0:47b9bfa03730 1610 return ERROR_NONE;
kenjiArai 0:47b9bfa03730 1611 }
kenjiArai 0:47b9bfa03730 1612
kenjiArai 0:47b9bfa03730 1613 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1614 /*!
kenjiArai 0:47b9bfa03730 1615 @brief Enables or disables all clock outputs
kenjiArai 0:47b9bfa03730 1616 */
kenjiArai 0:47b9bfa03730 1617 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1618 err_t Adafruit_SI5351::enableOutputs(bool enabled)
kenjiArai 0:47b9bfa03730 1619 {
kenjiArai 0:47b9bfa03730 1620 /* Make sure we've called init first */
kenjiArai 0:47b9bfa03730 1621 ASSERT(m_si5351Config.initialised, ERROR_DEVICENOTINITIALISED);
kenjiArai 0:47b9bfa03730 1622
kenjiArai 0:47b9bfa03730 1623 /* Enabled desired outputs (see Register 3) */
kenjiArai 0:47b9bfa03730 1624 ASSERT_STATUS(write8(SI5351_REGISTER_3_OUTPUT_ENABLE_CONTROL, enabled ? 0x00: 0xFF));
kenjiArai 0:47b9bfa03730 1625
kenjiArai 0:47b9bfa03730 1626 return ERROR_NONE;
kenjiArai 0:47b9bfa03730 1627 }
kenjiArai 0:47b9bfa03730 1628
kenjiArai 0:47b9bfa03730 1629 /* ---------------------------------------------------------------------- */
kenjiArai 0:47b9bfa03730 1630 /* PRUVATE FUNCTIONS */
kenjiArai 0:47b9bfa03730 1631 /* ---------------------------------------------------------------------- */
kenjiArai 0:47b9bfa03730 1632
kenjiArai 0:47b9bfa03730 1633 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1634 /*!
kenjiArai 0:47b9bfa03730 1635 @brief Writes a register and an 8 bit value over I2C
kenjiArai 0:47b9bfa03730 1636 */
kenjiArai 0:47b9bfa03730 1637 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1638 err_t Adafruit_SI5351::write8 (uint8_t reg, uint8_t value)
kenjiArai 0:47b9bfa03730 1639 {
kenjiArai 0:47b9bfa03730 1640 Wire.beginTransmission(SI5351_ADDRESS);
kenjiArai 0:47b9bfa03730 1641 #if ARDUINO >= 100
kenjiArai 0:47b9bfa03730 1642 Wire.write(reg);
kenjiArai 0:47b9bfa03730 1643 Wire.write(value & 0xFF);
kenjiArai 0:47b9bfa03730 1644 #else
kenjiArai 0:47b9bfa03730 1645 Wire.send(reg);
kenjiArai 0:47b9bfa03730 1646 Wire.send(value & 0xFF);
kenjiArai 0:47b9bfa03730 1647 #endif
kenjiArai 0:47b9bfa03730 1648 Wire.endTransmission();
kenjiArai 0:47b9bfa03730 1649
kenjiArai 0:47b9bfa03730 1650 // ToDo: Check for I2C errors
kenjiArai 0:47b9bfa03730 1651
kenjiArai 0:47b9bfa03730 1652 return ERROR_NONE;
kenjiArai 0:47b9bfa03730 1653 }
kenjiArai 0:47b9bfa03730 1654
kenjiArai 0:47b9bfa03730 1655 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1656 /*!
kenjiArai 0:47b9bfa03730 1657 @brief Reads an 8 bit value over I2C
kenjiArai 0:47b9bfa03730 1658 */
kenjiArai 0:47b9bfa03730 1659 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1660 err_t Adafruit_SI5351::read8(uint8_t reg, uint8_t *value)
kenjiArai 0:47b9bfa03730 1661 {
kenjiArai 0:47b9bfa03730 1662 Wire.beginTransmission(SI5351_ADDRESS);
kenjiArai 0:47b9bfa03730 1663 #if ARDUINO >= 100
kenjiArai 0:47b9bfa03730 1664 Wire.write(reg);
kenjiArai 0:47b9bfa03730 1665 #else
kenjiArai 0:47b9bfa03730 1666 Wire.send(reg);
kenjiArai 0:47b9bfa03730 1667 #endif
kenjiArai 0:47b9bfa03730 1668 Wire.endTransmission();
kenjiArai 0:47b9bfa03730 1669
kenjiArai 0:47b9bfa03730 1670 Wire.requestFrom(SI5351_ADDRESS, 1);
kenjiArai 0:47b9bfa03730 1671 #if ARDUINO >= 100
kenjiArai 0:47b9bfa03730 1672 *value = Wire.read();
kenjiArai 0:47b9bfa03730 1673 #else
kenjiArai 0:47b9bfa03730 1674 *value = Wire.read();
kenjiArai 0:47b9bfa03730 1675 #endif
kenjiArai 0:47b9bfa03730 1676
kenjiArai 0:47b9bfa03730 1677 // ToDo: Check for I2C errors
kenjiArai 0:47b9bfa03730 1678
kenjiArai 0:47b9bfa03730 1679 return ERROR_NONE;
kenjiArai 0:47b9bfa03730 1680 }
kenjiArai 0:47b9bfa03730 1681
kenjiArai 0:47b9bfa03730 1682 #endif
kenjiArai 0:47b9bfa03730 1683
kenjiArai 0:47b9bfa03730 1684 ////////////////////////////////////////////////////////////////////////////////
kenjiArai 0:47b9bfa03730 1685 // Adafruit_SI5351.h
kenjiArai 0:47b9bfa03730 1686 ////////////////////////////////////////////////////////////////////////////////
kenjiArai 0:47b9bfa03730 1687 #if 0
kenjiArai 0:47b9bfa03730 1688 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1689 /*!
kenjiArai 0:47b9bfa03730 1690 @file Adafruit_SI5351.h
kenjiArai 0:47b9bfa03730 1691 @author K. Townsend (Adafruit Industries)
kenjiArai 0:47b9bfa03730 1692
kenjiArai 0:47b9bfa03730 1693 @section LICENSE
kenjiArai 0:47b9bfa03730 1694
kenjiArai 0:47b9bfa03730 1695 Software License Agreement (BSD License)
kenjiArai 0:47b9bfa03730 1696
kenjiArai 0:47b9bfa03730 1697 Copyright (c) 2014, Adafruit Industries
kenjiArai 0:47b9bfa03730 1698 All rights reserved.
kenjiArai 0:47b9bfa03730 1699
kenjiArai 0:47b9bfa03730 1700 Redistribution and use in source and binary forms, with or without
kenjiArai 0:47b9bfa03730 1701 modification, are permitted provided that the following conditions are met:
kenjiArai 0:47b9bfa03730 1702 1. Redistributions of source code must retain the above copyright
kenjiArai 0:47b9bfa03730 1703 notice, this list of conditions and the following disclaimer.
kenjiArai 0:47b9bfa03730 1704 2. Redistributions in binary form must reproduce the above copyright
kenjiArai 0:47b9bfa03730 1705 notice, this list of conditions and the following disclaimer in the
kenjiArai 0:47b9bfa03730 1706 documentation and/or other materials provided with the distribution.
kenjiArai 0:47b9bfa03730 1707 3. Neither the name of the copyright holders nor the
kenjiArai 0:47b9bfa03730 1708 names of its contributors may be used to endorse or promote products
kenjiArai 0:47b9bfa03730 1709 derived from this software without specific prior written permission.
kenjiArai 0:47b9bfa03730 1710
kenjiArai 0:47b9bfa03730 1711 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
kenjiArai 0:47b9bfa03730 1712 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
kenjiArai 0:47b9bfa03730 1713 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
kenjiArai 0:47b9bfa03730 1714 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
kenjiArai 0:47b9bfa03730 1715 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
kenjiArai 0:47b9bfa03730 1716 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
kenjiArai 0:47b9bfa03730 1717 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
kenjiArai 0:47b9bfa03730 1718 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
kenjiArai 0:47b9bfa03730 1719 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
kenjiArai 0:47b9bfa03730 1720 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
kenjiArai 0:47b9bfa03730 1721 */
kenjiArai 0:47b9bfa03730 1722 /**************************************************************************/
kenjiArai 0:47b9bfa03730 1723 #ifndef _SI5351_H_
kenjiArai 0:47b9bfa03730 1724 #define _SI5351_H_
kenjiArai 0:47b9bfa03730 1725
kenjiArai 0:47b9bfa03730 1726 #if ARDUINO >= 100
kenjiArai 0:47b9bfa03730 1727 #include <Arduino.h>
kenjiArai 0:47b9bfa03730 1728 #else
kenjiArai 0:47b9bfa03730 1729 #include <WProgram.h>
kenjiArai 0:47b9bfa03730 1730 #endif
kenjiArai 0:47b9bfa03730 1731 //#include <Adafruit_Sensor.h>
kenjiArai 0:47b9bfa03730 1732 #include <Wire.h>
kenjiArai 0:47b9bfa03730 1733
kenjiArai 0:47b9bfa03730 1734 #include "errors.h"
kenjiArai 0:47b9bfa03730 1735 #include "asserts.h"
kenjiArai 0:47b9bfa03730 1736
kenjiArai 0:47b9bfa03730 1737 #define SI5351_ADDRESS (0x60) // Assumes ADDR pin = low
kenjiArai 0:47b9bfa03730 1738 #define SI5351_READBIT (0x01)
kenjiArai 0:47b9bfa03730 1739
kenjiArai 0:47b9bfa03730 1740 /* Test setup from SI5351 ClockBuilder
kenjiArai 0:47b9bfa03730 1741 * -----------------------------------
kenjiArai 0:47b9bfa03730 1742 * XTAL: 25 MHz
kenjiArai 0:47b9bfa03730 1743 * Channel 0: 120.00 MHz
kenjiArai 0:47b9bfa03730 1744 * Channel 1: 12.00 MHz
kenjiArai 0:47b9bfa03730 1745 * Channel 2: 13.56 MHz
kenjiArai 0:47b9bfa03730 1746 */
kenjiArai 0:47b9bfa03730 1747 static const uint8_t m_si5351_regs_15to92_149to170[100][2] =
kenjiArai 0:47b9bfa03730 1748 {
kenjiArai 0:47b9bfa03730 1749 { 15, 0x00 }, /* Input source = crystal for PLLA and PLLB */
kenjiArai 0:47b9bfa03730 1750 { 16, 0x4F }, /* CLK0 Control: 8mA drive, Multisynth 0 as CLK0 source, Clock not inverted, Source = PLLA, Multisynth 0 in integer mode, clock powered up */
kenjiArai 0:47b9bfa03730 1751 { 17, 0x4F }, /* CLK1 Control: 8mA drive, Multisynth 1 as CLK1 source, Clock not inverted, Source = PLLA, Multisynth 1 in integer mode, clock powered up */
kenjiArai 0:47b9bfa03730 1752 { 18, 0x6F }, /* CLK2 Control: 8mA drive, Multisynth 2 as CLK2 source, Clock not inverted, Source = PLLB, Multisynth 2 in integer mode, clock powered up */
kenjiArai 0:47b9bfa03730 1753 { 19, 0x80 }, /* CLK3 Control: Not used ... clock powered down */
kenjiArai 0:47b9bfa03730 1754 { 20, 0x80 }, /* CLK4 Control: Not used ... clock powered down */
kenjiArai 0:47b9bfa03730 1755 { 21, 0x80 }, /* CLK5 Control: Not used ... clock powered down */
kenjiArai 0:47b9bfa03730 1756 { 22, 0x80 }, /* CLK6 Control: Not used ... clock powered down */
kenjiArai 0:47b9bfa03730 1757 { 23, 0x80 }, /* CLK7 Control: Not used ... clock powered down */
kenjiArai 0:47b9bfa03730 1758 { 24, 0x00 }, /* Clock disable state 0..3 (low when disabled) */
kenjiArai 0:47b9bfa03730 1759 { 25, 0x00 }, /* Clock disable state 4..7 (low when disabled) */
kenjiArai 0:47b9bfa03730 1760 /* PLL_A Setup */
kenjiArai 0:47b9bfa03730 1761 { 26, 0x00 },
kenjiArai 0:47b9bfa03730 1762 { 27, 0x05 },
kenjiArai 0:47b9bfa03730 1763 { 28, 0x00 },
kenjiArai 0:47b9bfa03730 1764 { 29, 0x0C },
kenjiArai 0:47b9bfa03730 1765 { 30, 0x66 },
kenjiArai 0:47b9bfa03730 1766 { 31, 0x00 },
kenjiArai 0:47b9bfa03730 1767 { 32, 0x00 },
kenjiArai 0:47b9bfa03730 1768 { 33, 0x02 },
kenjiArai 0:47b9bfa03730 1769 /* PLL_B Setup */
kenjiArai 0:47b9bfa03730 1770 { 34, 0x02 },
kenjiArai 0:47b9bfa03730 1771 { 35, 0x71 },
kenjiArai 0:47b9bfa03730 1772 { 36, 0x00 },
kenjiArai 0:47b9bfa03730 1773 { 37, 0x0C },
kenjiArai 0:47b9bfa03730 1774 { 38, 0x1A },
kenjiArai 0:47b9bfa03730 1775 { 39, 0x00 },
kenjiArai 0:47b9bfa03730 1776 { 40, 0x00 },
kenjiArai 0:47b9bfa03730 1777 { 41, 0x86 },
kenjiArai 0:47b9bfa03730 1778 /* Multisynth Setup */
kenjiArai 0:47b9bfa03730 1779 { 42, 0x00 },
kenjiArai 0:47b9bfa03730 1780 { 43, 0x01 },
kenjiArai 0:47b9bfa03730 1781 { 44, 0x00 },
kenjiArai 0:47b9bfa03730 1782 { 45, 0x01 },
kenjiArai 0:47b9bfa03730 1783 { 46, 0x00 },
kenjiArai 0:47b9bfa03730 1784 { 47, 0x00 },
kenjiArai 0:47b9bfa03730 1785 { 48, 0x00 },
kenjiArai 0:47b9bfa03730 1786 { 49, 0x00 },
kenjiArai 0:47b9bfa03730 1787 { 50, 0x00 },
kenjiArai 0:47b9bfa03730 1788 { 51, 0x01 },
kenjiArai 0:47b9bfa03730 1789 { 52, 0x00 },
kenjiArai 0:47b9bfa03730 1790 { 53, 0x1C },
kenjiArai 0:47b9bfa03730 1791 { 54, 0x00 },
kenjiArai 0:47b9bfa03730 1792 { 55, 0x00 },
kenjiArai 0:47b9bfa03730 1793 { 56, 0x00 },
kenjiArai 0:47b9bfa03730 1794 { 57, 0x00 },
kenjiArai 0:47b9bfa03730 1795 { 58, 0x00 },
kenjiArai 0:47b9bfa03730 1796 { 59, 0x01 },
kenjiArai 0:47b9bfa03730 1797 { 60, 0x00 },
kenjiArai 0:47b9bfa03730 1798 { 61, 0x18 },
kenjiArai 0:47b9bfa03730 1799 { 62, 0x00 },
kenjiArai 0:47b9bfa03730 1800 { 63, 0x00 },
kenjiArai 0:47b9bfa03730 1801 { 64, 0x00 },
kenjiArai 0:47b9bfa03730 1802 { 65, 0x00 },
kenjiArai 0:47b9bfa03730 1803 { 66, 0x00 },
kenjiArai 0:47b9bfa03730 1804 { 67, 0x00 },
kenjiArai 0:47b9bfa03730 1805 { 68, 0x00 },
kenjiArai 0:47b9bfa03730 1806 { 69, 0x00 },
kenjiArai 0:47b9bfa03730 1807 { 70, 0x00 },
kenjiArai 0:47b9bfa03730 1808 { 71, 0x00 },
kenjiArai 0:47b9bfa03730 1809 { 72, 0x00 },
kenjiArai 0:47b9bfa03730 1810 { 73, 0x00 },
kenjiArai 0:47b9bfa03730 1811 { 74, 0x00 },
kenjiArai 0:47b9bfa03730 1812 { 75, 0x00 },
kenjiArai 0:47b9bfa03730 1813 { 76, 0x00 },
kenjiArai 0:47b9bfa03730 1814 { 77, 0x00 },
kenjiArai 0:47b9bfa03730 1815 { 78, 0x00 },
kenjiArai 0:47b9bfa03730 1816 { 79, 0x00 },
kenjiArai 0:47b9bfa03730 1817 { 80, 0x00 },
kenjiArai 0:47b9bfa03730 1818 { 81, 0x00 },
kenjiArai 0:47b9bfa03730 1819 { 82, 0x00 },
kenjiArai 0:47b9bfa03730 1820 { 83, 0x00 },
kenjiArai 0:47b9bfa03730 1821 { 84, 0x00 },
kenjiArai 0:47b9bfa03730 1822 { 85, 0x00 },
kenjiArai 0:47b9bfa03730 1823 { 86, 0x00 },
kenjiArai 0:47b9bfa03730 1824 { 87, 0x00 },
kenjiArai 0:47b9bfa03730 1825 { 88, 0x00 },
kenjiArai 0:47b9bfa03730 1826 { 89, 0x00 },
kenjiArai 0:47b9bfa03730 1827 { 90, 0x00 },
kenjiArai 0:47b9bfa03730 1828 { 91, 0x00 },
kenjiArai 0:47b9bfa03730 1829 { 92, 0x00 },
kenjiArai 0:47b9bfa03730 1830 /* Misc Config Register */
kenjiArai 0:47b9bfa03730 1831 { 149, 0x00 },
kenjiArai 0:47b9bfa03730 1832 { 150, 0x00 },
kenjiArai 0:47b9bfa03730 1833 { 151, 0x00 },
kenjiArai 0:47b9bfa03730 1834 { 152, 0x00 },
kenjiArai 0:47b9bfa03730 1835 { 153, 0x00 },
kenjiArai 0:47b9bfa03730 1836 { 154, 0x00 },
kenjiArai 0:47b9bfa03730 1837 { 155, 0x00 },
kenjiArai 0:47b9bfa03730 1838 { 156, 0x00 },
kenjiArai 0:47b9bfa03730 1839 { 157, 0x00 },
kenjiArai 0:47b9bfa03730 1840 { 158, 0x00 },
kenjiArai 0:47b9bfa03730 1841 { 159, 0x00 },
kenjiArai 0:47b9bfa03730 1842 { 160, 0x00 },
kenjiArai 0:47b9bfa03730 1843 { 161, 0x00 },
kenjiArai 0:47b9bfa03730 1844 { 162, 0x00 },
kenjiArai 0:47b9bfa03730 1845 { 163, 0x00 },
kenjiArai 0:47b9bfa03730 1846 { 164, 0x00 },
kenjiArai 0:47b9bfa03730 1847 { 165, 0x00 },
kenjiArai 0:47b9bfa03730 1848 { 166, 0x00 },
kenjiArai 0:47b9bfa03730 1849 { 167, 0x00 },
kenjiArai 0:47b9bfa03730 1850 { 168, 0x00 },
kenjiArai 0:47b9bfa03730 1851 { 169, 0x00 },
kenjiArai 0:47b9bfa03730 1852 { 170, 0x00 }
kenjiArai 0:47b9bfa03730 1853 };
kenjiArai 0:47b9bfa03730 1854
kenjiArai 0:47b9bfa03730 1855 /* See http://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf for registers 26..41 */
kenjiArai 0:47b9bfa03730 1856 enum
kenjiArai 0:47b9bfa03730 1857 {
kenjiArai 0:47b9bfa03730 1858 SI5351_REGISTER_0_DEVICE_STATUS = 0,
kenjiArai 0:47b9bfa03730 1859 SI5351_REGISTER_1_INTERRUPT_STATUS_STICKY = 1,
kenjiArai 0:47b9bfa03730 1860 SI5351_REGISTER_2_INTERRUPT_STATUS_MASK = 2,
kenjiArai 0:47b9bfa03730 1861 SI5351_REGISTER_3_OUTPUT_ENABLE_CONTROL = 3,
kenjiArai 0:47b9bfa03730 1862 SI5351_REGISTER_9_OEB_PIN_ENABLE_CONTROL = 9,
kenjiArai 0:47b9bfa03730 1863 SI5351_REGISTER_15_PLL_INPUT_SOURCE = 15,
kenjiArai 0:47b9bfa03730 1864 SI5351_REGISTER_16_CLK0_CONTROL = 16,
kenjiArai 0:47b9bfa03730 1865 SI5351_REGISTER_17_CLK1_CONTROL = 17,
kenjiArai 0:47b9bfa03730 1866 SI5351_REGISTER_18_CLK2_CONTROL = 18,
kenjiArai 0:47b9bfa03730 1867 SI5351_REGISTER_19_CLK3_CONTROL = 19,
kenjiArai 0:47b9bfa03730 1868 SI5351_REGISTER_20_CLK4_CONTROL = 20,
kenjiArai 0:47b9bfa03730 1869 SI5351_REGISTER_21_CLK5_CONTROL = 21,
kenjiArai 0:47b9bfa03730 1870 SI5351_REGISTER_22_CLK6_CONTROL = 22,
kenjiArai 0:47b9bfa03730 1871 SI5351_REGISTER_23_CLK7_CONTROL = 23,
kenjiArai 0:47b9bfa03730 1872 SI5351_REGISTER_24_CLK3_0_DISABLE_STATE = 24,
kenjiArai 0:47b9bfa03730 1873 SI5351_REGISTER_25_CLK7_4_DISABLE_STATE = 25,
kenjiArai 0:47b9bfa03730 1874 SI5351_REGISTER_42_MULTISYNTH0_PARAMETERS_1 = 42,
kenjiArai 0:47b9bfa03730 1875 SI5351_REGISTER_43_MULTISYNTH0_PARAMETERS_2 = 43,
kenjiArai 0:47b9bfa03730 1876 SI5351_REGISTER_44_MULTISYNTH0_PARAMETERS_3 = 44,
kenjiArai 0:47b9bfa03730 1877 SI5351_REGISTER_45_MULTISYNTH0_PARAMETERS_4 = 45,
kenjiArai 0:47b9bfa03730 1878 SI5351_REGISTER_46_MULTISYNTH0_PARAMETERS_5 = 46,
kenjiArai 0:47b9bfa03730 1879 SI5351_REGISTER_47_MULTISYNTH0_PARAMETERS_6 = 47,
kenjiArai 0:47b9bfa03730 1880 SI5351_REGISTER_48_MULTISYNTH0_PARAMETERS_7 = 48,
kenjiArai 0:47b9bfa03730 1881 SI5351_REGISTER_49_MULTISYNTH0_PARAMETERS_8 = 49,
kenjiArai 0:47b9bfa03730 1882 SI5351_REGISTER_50_MULTISYNTH1_PARAMETERS_1 = 50,
kenjiArai 0:47b9bfa03730 1883 SI5351_REGISTER_51_MULTISYNTH1_PARAMETERS_2 = 51,
kenjiArai 0:47b9bfa03730 1884 SI5351_REGISTER_52_MULTISYNTH1_PARAMETERS_3 = 52,
kenjiArai 0:47b9bfa03730 1885 SI5351_REGISTER_53_MULTISYNTH1_PARAMETERS_4 = 53,
kenjiArai 0:47b9bfa03730 1886 SI5351_REGISTER_54_MULTISYNTH1_PARAMETERS_5 = 54,
kenjiArai 0:47b9bfa03730 1887 SI5351_REGISTER_55_MULTISYNTH1_PARAMETERS_6 = 55,
kenjiArai 0:47b9bfa03730 1888 SI5351_REGISTER_56_MULTISYNTH1_PARAMETERS_7 = 56,
kenjiArai 0:47b9bfa03730 1889 SI5351_REGISTER_57_MULTISYNTH1_PARAMETERS_8 = 57,
kenjiArai 0:47b9bfa03730 1890 SI5351_REGISTER_58_MULTISYNTH2_PARAMETERS_1 = 58,
kenjiArai 0:47b9bfa03730 1891 SI5351_REGISTER_59_MULTISYNTH2_PARAMETERS_2 = 59,
kenjiArai 0:47b9bfa03730 1892 SI5351_REGISTER_60_MULTISYNTH2_PARAMETERS_3 = 60,
kenjiArai 0:47b9bfa03730 1893 SI5351_REGISTER_61_MULTISYNTH2_PARAMETERS_4 = 61,
kenjiArai 0:47b9bfa03730 1894 SI5351_REGISTER_62_MULTISYNTH2_PARAMETERS_5 = 62,
kenjiArai 0:47b9bfa03730 1895 SI5351_REGISTER_63_MULTISYNTH2_PARAMETERS_6 = 63,
kenjiArai 0:47b9bfa03730 1896 SI5351_REGISTER_64_MULTISYNTH2_PARAMETERS_7 = 64,
kenjiArai 0:47b9bfa03730 1897 SI5351_REGISTER_65_MULTISYNTH2_PARAMETERS_8 = 65,
kenjiArai 0:47b9bfa03730 1898 SI5351_REGISTER_66_MULTISYNTH3_PARAMETERS_1 = 66,
kenjiArai 0:47b9bfa03730 1899 SI5351_REGISTER_67_MULTISYNTH3_PARAMETERS_2 = 67,
kenjiArai 0:47b9bfa03730 1900 SI5351_REGISTER_68_MULTISYNTH3_PARAMETERS_3 = 68,
kenjiArai 0:47b9bfa03730 1901 SI5351_REGISTER_69_MULTISYNTH3_PARAMETERS_4 = 69,
kenjiArai 0:47b9bfa03730 1902 SI5351_REGISTER_70_MULTISYNTH3_PARAMETERS_5 = 70,
kenjiArai 0:47b9bfa03730 1903 SI5351_REGISTER_71_MULTISYNTH3_PARAMETERS_6 = 71,
kenjiArai 0:47b9bfa03730 1904 SI5351_REGISTER_72_MULTISYNTH3_PARAMETERS_7 = 72,
kenjiArai 0:47b9bfa03730 1905 SI5351_REGISTER_73_MULTISYNTH3_PARAMETERS_8 = 73,
kenjiArai 0:47b9bfa03730 1906 SI5351_REGISTER_74_MULTISYNTH4_PARAMETERS_1 = 74,
kenjiArai 0:47b9bfa03730 1907 SI5351_REGISTER_75_MULTISYNTH4_PARAMETERS_2 = 75,
kenjiArai 0:47b9bfa03730 1908 SI5351_REGISTER_76_MULTISYNTH4_PARAMETERS_3 = 76,
kenjiArai 0:47b9bfa03730 1909 SI5351_REGISTER_77_MULTISYNTH4_PARAMETERS_4 = 77,
kenjiArai 0:47b9bfa03730 1910 SI5351_REGISTER_78_MULTISYNTH4_PARAMETERS_5 = 78,
kenjiArai 0:47b9bfa03730 1911 SI5351_REGISTER_79_MULTISYNTH4_PARAMETERS_6 = 79,
kenjiArai 0:47b9bfa03730 1912 SI5351_REGISTER_80_MULTISYNTH4_PARAMETERS_7 = 80,
kenjiArai 0:47b9bfa03730 1913 SI5351_REGISTER_81_MULTISYNTH4_PARAMETERS_8 = 81,
kenjiArai 0:47b9bfa03730 1914 SI5351_REGISTER_82_MULTISYNTH5_PARAMETERS_1 = 82,
kenjiArai 0:47b9bfa03730 1915 SI5351_REGISTER_83_MULTISYNTH5_PARAMETERS_2 = 83,
kenjiArai 0:47b9bfa03730 1916 SI5351_REGISTER_84_MULTISYNTH5_PARAMETERS_3 = 84,
kenjiArai 0:47b9bfa03730 1917 SI5351_REGISTER_85_MULTISYNTH5_PARAMETERS_4 = 85,
kenjiArai 0:47b9bfa03730 1918 SI5351_REGISTER_86_MULTISYNTH5_PARAMETERS_5 = 86,
kenjiArai 0:47b9bfa03730 1919 SI5351_REGISTER_87_MULTISYNTH5_PARAMETERS_6 = 87,
kenjiArai 0:47b9bfa03730 1920 SI5351_REGISTER_88_MULTISYNTH5_PARAMETERS_7 = 88,
kenjiArai 0:47b9bfa03730 1921 SI5351_REGISTER_89_MULTISYNTH5_PARAMETERS_8 = 89,
kenjiArai 0:47b9bfa03730 1922 SI5351_REGISTER_90_MULTISYNTH6_PARAMETERS = 90,
kenjiArai 0:47b9bfa03730 1923 SI5351_REGISTER_91_MULTISYNTH7_PARAMETERS = 91,
kenjiArai 0:47b9bfa03730 1924 SI5351_REGISTER_092_CLOCK_6_7_OUTPUT_DIVIDER = 92,
kenjiArai 0:47b9bfa03730 1925 SI5351_REGISTER_165_CLK0_INITIAL_PHASE_OFFSET = 165,
kenjiArai 0:47b9bfa03730 1926 SI5351_REGISTER_166_CLK1_INITIAL_PHASE_OFFSET = 166,
kenjiArai 0:47b9bfa03730 1927 SI5351_REGISTER_167_CLK2_INITIAL_PHASE_OFFSET = 167,
kenjiArai 0:47b9bfa03730 1928 SI5351_REGISTER_168_CLK3_INITIAL_PHASE_OFFSET = 168,
kenjiArai 0:47b9bfa03730 1929 SI5351_REGISTER_169_CLK4_INITIAL_PHASE_OFFSET = 169,
kenjiArai 0:47b9bfa03730 1930 SI5351_REGISTER_170_CLK5_INITIAL_PHASE_OFFSET = 170,
kenjiArai 0:47b9bfa03730 1931 SI5351_REGISTER_177_PLL_RESET = 177,
kenjiArai 0:47b9bfa03730 1932 SI5351_REGISTER_183_CRYSTAL_INTERNAL_LOAD_CAPACITANCE = 183
kenjiArai 0:47b9bfa03730 1933 };
kenjiArai 0:47b9bfa03730 1934
kenjiArai 0:47b9bfa03730 1935 typedef enum
kenjiArai 0:47b9bfa03730 1936 {
kenjiArai 0:47b9bfa03730 1937 SI5351_PLL_A = 0,
kenjiArai 0:47b9bfa03730 1938 SI5351_PLL_B,
kenjiArai 0:47b9bfa03730 1939 } si5351PLL_t;
kenjiArai 0:47b9bfa03730 1940
kenjiArai 0:47b9bfa03730 1941 typedef enum
kenjiArai 0:47b9bfa03730 1942 {
kenjiArai 0:47b9bfa03730 1943 SI5351_CRYSTAL_LOAD_6PF = (1<<6),
kenjiArai 0:47b9bfa03730 1944 SI5351_CRYSTAL_LOAD_8PF = (2<<6),
kenjiArai 0:47b9bfa03730 1945 SI5351_CRYSTAL_LOAD_10PF = (3<<6)
kenjiArai 0:47b9bfa03730 1946 } si5351CrystalLoad_t;
kenjiArai 0:47b9bfa03730 1947
kenjiArai 0:47b9bfa03730 1948 typedef enum
kenjiArai 0:47b9bfa03730 1949 {
kenjiArai 0:47b9bfa03730 1950 SI5351_CRYSTAL_FREQ_25MHZ = (25000000),
kenjiArai 0:47b9bfa03730 1951 SI5351_CRYSTAL_FREQ_27MHZ = (27000000)
kenjiArai 0:47b9bfa03730 1952 } si5351CrystalFreq_t;
kenjiArai 0:47b9bfa03730 1953
kenjiArai 0:47b9bfa03730 1954 typedef enum
kenjiArai 0:47b9bfa03730 1955 {
kenjiArai 0:47b9bfa03730 1956 SI5351_MULTISYNTH_DIV_4 = 4,
kenjiArai 0:47b9bfa03730 1957 SI5351_MULTISYNTH_DIV_6 = 6,
kenjiArai 0:47b9bfa03730 1958 SI5351_MULTISYNTH_DIV_8 = 8
kenjiArai 0:47b9bfa03730 1959 } si5351MultisynthDiv_t;
kenjiArai 0:47b9bfa03730 1960
kenjiArai 0:47b9bfa03730 1961 typedef enum
kenjiArai 0:47b9bfa03730 1962 {
kenjiArai 0:47b9bfa03730 1963 SI5351_R_DIV_1 = 0,
kenjiArai 0:47b9bfa03730 1964 SI5351_R_DIV_2 = 1,
kenjiArai 0:47b9bfa03730 1965 SI5351_R_DIV_4 = 2,
kenjiArai 0:47b9bfa03730 1966 SI5351_R_DIV_8 = 3,
kenjiArai 0:47b9bfa03730 1967 SI5351_R_DIV_16 = 4,
kenjiArai 0:47b9bfa03730 1968 SI5351_R_DIV_32 = 5,
kenjiArai 0:47b9bfa03730 1969 SI5351_R_DIV_64 = 6,
kenjiArai 0:47b9bfa03730 1970 SI5351_R_DIV_128 = 7,
kenjiArai 0:47b9bfa03730 1971 } si5351RDiv_t;
kenjiArai 0:47b9bfa03730 1972
kenjiArai 0:47b9bfa03730 1973 typedef struct
kenjiArai 0:47b9bfa03730 1974 {
kenjiArai 0:47b9bfa03730 1975 bool initialised;
kenjiArai 0:47b9bfa03730 1976 si5351CrystalFreq_t crystalFreq;
kenjiArai 0:47b9bfa03730 1977 si5351CrystalLoad_t crystalLoad;
kenjiArai 0:47b9bfa03730 1978 uint32_t crystalPPM;
kenjiArai 0:47b9bfa03730 1979 bool plla_configured;
kenjiArai 0:47b9bfa03730 1980 uint32_t plla_freq;
kenjiArai 0:47b9bfa03730 1981 bool pllb_configured;
kenjiArai 0:47b9bfa03730 1982 uint32_t pllb_freq;
kenjiArai 0:47b9bfa03730 1983 } si5351Config_t;
kenjiArai 0:47b9bfa03730 1984
kenjiArai 0:47b9bfa03730 1985 class Adafruit_SI5351
kenjiArai 0:47b9bfa03730 1986 {
kenjiArai 0:47b9bfa03730 1987 public:
kenjiArai 0:47b9bfa03730 1988 Adafruit_SI5351(void);
kenjiArai 0:47b9bfa03730 1989
kenjiArai 0:47b9bfa03730 1990 err_t begin(void);
kenjiArai 0:47b9bfa03730 1991 err_t setClockBuilderData(void);
kenjiArai 0:47b9bfa03730 1992 err_t setupPLL(si5351PLL_t pll, uint8_t mult, uint32_t num, uint32_t denom);
kenjiArai 0:47b9bfa03730 1993 err_t setupPLLInt(si5351PLL_t pll, uint8_t mult);
kenjiArai 0:47b9bfa03730 1994 err_t setupMultisynth(uint8_t output, si5351PLL_t pllSource, uint32_t div, uint32_t num, uint32_t denom);
kenjiArai 0:47b9bfa03730 1995 err_t setupMultisynthInt(uint8_t output, si5351PLL_t pllSource, si5351MultisynthDiv_t div);
kenjiArai 0:47b9bfa03730 1996 err_t enableOutputs(bool enabled);
kenjiArai 0:47b9bfa03730 1997 err_t setupRdiv(uint8_t output, si5351RDiv_t div);
kenjiArai 0:47b9bfa03730 1998
kenjiArai 0:47b9bfa03730 1999 private:
kenjiArai 0:47b9bfa03730 2000 si5351Config_t m_si5351Config;
kenjiArai 0:47b9bfa03730 2001
kenjiArai 0:47b9bfa03730 2002 err_t write8(uint8_t reg, uint8_t value);
kenjiArai 0:47b9bfa03730 2003 err_t read8(uint8_t reg, uint8_t *value);
kenjiArai 0:47b9bfa03730 2004 };
kenjiArai 0:47b9bfa03730 2005
kenjiArai 0:47b9bfa03730 2006 #endif
kenjiArai 0:47b9bfa03730 2007
kenjiArai 0:47b9bfa03730 2008 #endif
kenjiArai 0:47b9bfa03730 2009 //
kenjiArai 4:8c63d15c8c2e 2010