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