Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: clockGenerator Check_Si5351A_Clock_generator t2d Thing2Do ... more
Revision 3:af2d99cfb3f0, committed 2017-01-07
- Comitter:
- kenjiArai
- Date:
- Sat Jan 07 05:54:36 2017 +0000
- Parent:
- 2:8fe745836ea6
- Child:
- 4:8c63d15c8c2e
- Commit message:
- added RANGE_EXTENDED mode, output freq=1.627KHz to 300MHz
Changed in this revision
| si5351a.cpp | Show annotated file Show diff for this revision Revisions of this file |
| si5351a.h | Show annotated file Show diff for this revision Revisions of this file |
--- 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));
}
/******************************************************************************/
--- a/si5351a.h Fri Jan 06 14:06:42 2017 +0000
+++ b/si5351a.h Sat Jan 07 05:54:36 2017 +0000
@@ -24,12 +24,23 @@
* http://mbed.org/users/kenjiArai/
*
* Started: December 24th, 2016
- * Revised: January 6th, 2017
+ * Revised: January 7th, 2017
*
*/
-#ifndef MBED_SI5351A
-#define MBED_SI5351A
+#ifndef MBED_SI5351A
+#define MBED_SI5351A
+
+#if 0 // Range extend mode -> set 1
+#define RANGE_EXTENDED
+#endif
+#if defined(RANGE_EXTENDED)
+#warning "Si5351A PLL range is only 600MHz to 900MHz."
+#warning "If you use RANGE_EXTENDED mode, PLL sets 250MHz to 1.3GHz."
+#warning "This causes high possibility to make a \
+ PARMANENT DAMAGE for the chip!!!!!"
+#warning "Don't use this mode!!!"
+#endif
////////////// ADDRESS /////////////////////////////////////////////////////////
// 7bit address = 0b1100000(0x60) -> 8bit = 0b11000000(0xc0)
@@ -48,7 +59,7 @@
#define SI5351_REG_50_MULTISYNTH1 50
#define SI5351_REG_52_MULTISYNTH1_P3 52
#define SI5351_REG_58_MULTISYNTH2 58
-#define SI5351_REG_60_MULTISYNTH2_P3 60
+#define SI5351_REG_60_MULTISYNTH2_P3 60
#define SI5351_REG_177_PLL_RESET 177
#define SI5351_REG_183_CRYSTAL_LOAD 183
@@ -94,8 +105,11 @@
#define SI5351_CRYSTAL_LOAD_10PF (3<<6)
// Frequency
+#define FREQ_900MHZ (900000000UL)
+#define FREQ_600MHZ (600000000UL)
+#define FREQ_200MHZ (200000000UL)
#define FREQ_150MHZ (150000000UL)
-#define FREQ_100MHZ (100000000UL)
+#define FREQ_110MHZ (110000000UL)
#define FREQ_1MHZ (1000000UL)
#define FREQ_450KHZ (450000UL)
#define FREQ_75KHZ (75000UL)
@@ -123,9 +137,9 @@
*
* // --------- CAUTION & RESTRICTION -----------------------------------------
* // 1) SETTING METHOD
- * // 1~100MHz : fixed PLL (XTAL * PLL_N)MHz, fractional divider
- * // 100~150MHz : fractional PLL 600-900MHz, fixed divider 6
- * // 150~200MHz : fractional PLL 600-900MHz, fixed divider 4
+ * // 2.6KHz~100MHz: fixed PLL(around 900 or around 600MHz), fractional divider
+ * // 100~150MHz: fractional PLL 600-900MHz, fixed divider 6
+ * // 150~200MHz: fractional PLL 600-900MHz, fixed divider 4
* //
* // 2) RESOURCE USAGE
* // PLLA -> only for CLK0 (You can change freqency any time to any value.)
@@ -202,7 +216,7 @@
*/
void all_reset(void);
- //--------------- Debug interface ------------------------------------------
+ //--------------- Debug interface ------------------------------------------
/** debug / print registers
* @param none
@@ -220,7 +234,7 @@
* as demonstration purpose for hardware check (@25MHz Xtal)
* @param none
* @return none
- */
+ */
void debug_example_clock(void);
protected:
@@ -253,6 +267,7 @@
uint8_t mult,
uint32_t num,
uint32_t denom);
+ void si5351_set_PLL_input_condition(uint32_t freq);
void si5351_reset_pll(void);
void si5351_enable_output(void);
void si5351_disable_output(void);
@@ -269,7 +284,8 @@
uint32_t base_freq; // Xtal oscilation freq.
uint8_t x_cap; // Internal capacitor value
uint8_t drv_current; // Output current drive strength
- uint32_t pll_freq; // XTAL * PLL_N
+ uint8_t pll_n; // PLL div number (PLL_N)
+ uint32_t pll_freq; // XTAL * pll_n
uint32_t plla_freq; // Calculated freq of PLLA
uint32_t pllb_freq; // Calculated freq of PLLB
double compensation; // Compensation data