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/
Diff: si5351a.cpp
- Revision:
- 3:af2d99cfb3f0
- Parent:
- 2:8fe745836ea6
- Child:
- 4:8c63d15c8c2e
--- a/si5351a.cpp Fri Jan 06 14:06:42 2017 +0000 +++ b/si5351a.cpp Sat Jan 07 05:54:36 2017 +0000 @@ -24,7 +24,7 @@ * http://mbed.org/users/kenjiArai/ * * Started: December 24th, 2016 - * Revised: January 6th, 2017 + * Revised: January 7th, 2017 * */ @@ -65,13 +65,13 @@ { base_freq = base_clk_freq; x_cap = xtal_cap; - drv_current = drive_current; + drv_current = drive_current; si5351_init(); } /* - * 1~100MHz fixed PLL (XTAL * PLL_N)MHz, fractional divider - * 100~150MHz fractional PLL 600-900MHz, fixed divider 6 + * 1~110MHz fixed PLL (XTAL * PLL_N)MHz, fractional divider + * 110~150MHz fractional PLL 600-900MHz, fixed divider 6 * 150~200MHz fractional PLL 600-900MHz, fixed divider 4 */ uint32_t SI5351A::set_frequency(uint8_t channel, uint32_t freq) @@ -85,51 +85,77 @@ pll = SI5351_PLL_B; } si5351_disable_output(); - if (freq <= FREQ_100MHZ){ + if (freq <= FREQ_110MHZ){ if((channel == SI5351_CLK1) && (clk2_state == CLK_OUT_FIXEDDIV)){ - DBG("DBG: Error CLK2 uses as over 100MHz!!\r\n"); + DBG("DBG: Error CLK2 uses as over 110MHz!!\r\n"); return 0; } else if((channel == SI5351_CLK2) && (clk1_state == CLK_OUT_FIXEDDIV)){ - DBG("DBG: Error CLK1 uses as over 100MHz!!\r\n"); + DBG("DBG: Error CLK1 uses as over 110MHz!!\r\n"); return 0; } DBG("DBG: Passed condition\r\n"); - if (freq > FREQ_450KHZ){ // over 450KHz - si5351_setupPLL(pll, PLL_N, 0, 1); + if (freq > FREQ_450KHZ){ // over 450KHz to 110MHz + si5351_set_PLL_input_condition(FREQ_900MHZ); + si5351_setupPLL(pll, pll_n, 0, 1); f = si5351_set_frequency_fixedpll(channel, pll, pll_freq, freq, 0); } else if (freq > FREQ_75KHZ){ - si5351_setupPLL(pll, PLL_N, 0, 1); + si5351_set_PLL_input_condition(FREQ_600MHZ); + si5351_setupPLL(pll, pll_n, 0, 1); f = si5351_set_frequency_fixedpll( channel, pll, pll_freq, freq * 8, SI5351_R_DIV_8); f /= 8.0f; } else if (freq > FREQ_20KHZ){ - si5351_setupPLL(pll, PLL_N, 0, 1); + si5351_set_PLL_input_condition(FREQ_600MHZ); + si5351_setupPLL(pll, pll_n, 0, 1); f = si5351_set_frequency_fixedpll( channel, pll, pll_freq, freq * 32, SI5351_R_DIV_32); f /= 32.0f; } else { - si5351_setupPLL(pll, PLL_N, 0, 1); + si5351_set_PLL_input_condition(FREQ_600MHZ); + si5351_setupPLL(pll, pll_n, 0, 1); f = si5351_set_frequency_fixedpll( channel, pll, pll_freq, freq * 128, SI5351_R_DIV_128); +#if defined(RANGE_EXTENDED) + // CAUTION !!!!!! + if (f == 0){ // This part is outside of specification!! + DBG("DBG: Out of range but try again!\r\n"); + pll_n = 15; // around 375MHz + pll_freq = base_freq * pll_n; + pll_freq = (uint32_t)((double)pll_freq / compensation); + si5351_setupPLL(pll, pll_n, 0, 1); + f = si5351_set_frequency_fixedpll( + channel, pll, pll_freq, freq * 128, SI5351_R_DIV_128); + } +#endif f /= 128.0f; } state = CLK_OUT_FIXEDPLL; } else { - DBG("DBG: Set over 100MHz clock\r\n"); + DBG("DBG: Set over 110MHz clock\r\n"); if((channel == SI5351_CLK1) && (clk2_state == CLK_OUT_FIXEDPLL)){ - DBG("DBG: Error CLK2 uses as under 100MHz!!\r\n"); + DBG("DBG: Error CLK2 uses as under 110MHz!!\r\n"); return 0; } else if((channel == SI5351_CLK2) && (clk1_state == CLK_OUT_FIXEDPLL)){ - DBG("DBG: Error CLK1 uses as under 100MHz!!\r\n"); + DBG("DBG: Error CLK1 uses as under 110MHz!!\r\n"); return 0; } DBG("DBG: Passed condition\r\n"); if (freq < FREQ_150MHZ) { - DBG("DBG: Set 100MHz to 150MHz clock\r\n"); + DBG("DBG: Set 110MHz to 150MHz clock\r\n"); f = si5351_set_frequency_fixeddiv(channel, pll, freq, 6); } else { +#if defined(RANGE_EXTENDED) + DBG("DBG: Set over 150MHz clock (RANGE_EXTENDED)\r\n"); + f = si5351_set_frequency_fixeddiv(channel, pll, freq, 4); +#else DBG("DBG: Set over 150MHz clock\r\n"); - f = si5351_set_frequency_fixeddiv(channel, pll, freq, 4); + if (freq > FREQ_200MHZ) { + DBG("DBG: Over 200MHz\r\n"); + f = 0; + } else { + f = si5351_set_frequency_fixeddiv(channel, pll, freq, 4); + } +#endif } state = CLK_OUT_FIXEDDIV; } @@ -159,7 +185,7 @@ f_err = (uint32_t)f; if ((clk0_state == CLK_OUT_NOT_USED) || (clk0_state == CLK_OUT_FIXEDDIV)){ - DBG("DBG: error over 100MHz\r\n"); + DBG("DBG: error over 110MHz\r\n"); return f_err; // return current frequency } } else if (channel == SI5351_CLK1){ @@ -167,7 +193,7 @@ f_err = (uint32_t)f; if ((clk1_state == CLK_OUT_NOT_USED) || (clk1_state == CLK_OUT_FIXEDDIV)){ - DBG("DBG: error over 100MHz\r\n"); + DBG("DBG: error over 110MHz\r\n"); return f_err; // return current frequency } } else if (channel == SI5351_CLK2){ @@ -175,7 +201,7 @@ f_err = (uint32_t)f; if ((clk2_state == CLK_OUT_NOT_USED) || (clk2_state == CLK_OUT_FIXEDDIV)){ - DBG("DBG: error over 100MHz\r\n"); + DBG("DBG: error over 110MHz\r\n"); return f_err; // return current frequency } } else { @@ -185,8 +211,8 @@ double f_tatget = f + (double)diff; uint32_t freq = (uint32_t)f_tatget; DBG("DBG: Target F=%u\r\n", freq); - // only range between 1MHz to 100MHz - if ((freq > FREQ_100MHZ) || (freq < FREQ_450KHZ)){// between 450KHz-100MHz + // only range between 1MHz to 110MHz + if ((freq > FREQ_110MHZ) || (freq < FREQ_450KHZ)){// between 450KHz-110MHz DBG("DBG: Out of range\r\n"); return f_err; // return current frequency } @@ -207,7 +233,7 @@ if (num >=0x100000){ // 20-bit limit DBG("DBG: error num over 20bit\r\n"); return f_err; // return current frequency - } + } if (denom >=0x100000){ // 20-bit limit DBG("DBG: error denom over 20bit\r\n"); return f_err; // return current frequency @@ -266,8 +292,16 @@ void SI5351A::f_compensation(uint32_t target_f, uint32_t measured_f) { - compensation = (double)target_f / (double)measured_f; - pll_freq = (uint32_t)((double)pll_freq / compensation); + double new_comp_data; + + if (compensation == 1.0f){ + compensation = (double)target_f / (double)measured_f; + pll_freq = (uint32_t)((double)pll_freq / compensation); + } else { + new_comp_data = (double)target_f / (double)measured_f; + pll_freq = (uint32_t)((double)pll_freq / new_comp_data); + compensation *= new_comp_data; + } } static const uint8_t reg_table[] = { @@ -320,7 +354,6 @@ void SI5351A::si5351_init(void) { addr = SI5351_I2C_ADDR; - pll_freq = base_freq * PLL_N; clk0_freq = 0; clk1_freq = 0; clk2_freq = 0; @@ -328,6 +361,7 @@ clk1_state = CLK_OUT_NOT_USED; clk2_state = CLK_OUT_NOT_USED; compensation = 1.0f; + si5351_set_PLL_input_condition(FREQ_900MHZ); si5351_reset_pll(); si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff); // Total load capacitance less than or equal to 12 pF (See AN551) @@ -371,6 +405,25 @@ si5351_write(SI5351_REG_177_PLL_RESET, 0xa0); } +void SI5351A::si5351_set_PLL_input_condition(uint32_t freq) +{ + uint8_t n; + uint32_t dt; + + n = (uint8_t)(freq / base_freq); + dt = base_freq * n; + while (true){ + if (dt > FREQ_900MHZ){ --n;} + if (dt < FREQ_600MHZ){ ++n;} + dt = base_freq * n; + if ((dt <= FREQ_900MHZ) && (dt >= FREQ_600MHZ)){ break;} + } + pll_n = n; + pll_freq = dt; + pll_freq = (uint32_t)((double)pll_freq / compensation); + DBG("DBG: Change PLL_N data / pll_n=%u, pll_freq=%u\r\n", pll_n, pll_freq); +} + /******************************************************************************/ /*! @brief Sets the multiplier for the specified PLL @@ -603,7 +656,7 @@ div4 = SI5351_DIVBY4; P1 = P2 = 0; P3 = 1; - multisynth_double = 4.0f; + multisynth_double = 4.0f; } else if (num == 0) { DBG("DBG: enter num==0\r\n"); /* Integer mode */ @@ -885,7 +938,7 @@ buf[1] = 8; // # of reading bytes si5351_read(buf); reg_pll_8bytes(buf); - printf("[MultiSynth-n P1,P2,P3]\r\n"); + printf("[MultiSynth-n P1,P2,P3]\r\n"); printf("--> Mltsyn0 * "); buf[0] = 42; // register address buf[1] = 8; // # of reading bytes @@ -966,7 +1019,7 @@ printf("not inverted"); } printf(", Drive strength-> "); - printf("%umA\r\n", 2 + 2 * (dt & 0x03)); + printf("%umA\r\n", 2 + 2 * (dt & 0x03)); } /******************************************************************************/