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/

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));
 }
 
 /******************************************************************************/