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