Kenji Arai / Si5351A

Dependents:   clockGenerator Check_Si5351A_Clock_generator t2d Thing2Do ... more

Files at this revision

API Documentation at this revision

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