Kenji Arai / Si5351A

Dependents:   clockGenerator Check_Si5351A_Clock_generator t2d Thing2Do ... more

Revision:
0:47b9bfa03730
Child:
1:a2309757c450
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/si5351a.h	Sun Jan 01 01:21:34 2017 +0000
@@ -0,0 +1,280 @@
+/*
+ * mbed Library / Silicon Laboratories Inc. Si5351A-B-GT
+ *      I2C-PROGRAMMABLE ANY-FREQUENCY CMOS CLOCK GENERATOR
+ *      https://www.silabs.com/products/
+ *          timing/clock-generator/si535x/pages/Si5351A-B-GM.aspx
+ *
+ *  Checked on Nucleo-F411RE & F401RE mbed board
+ *
+ *  Original & Reference program:
+ *  1)
+ *      https://github.com/adafruit/Adafruit_Si5351_Library
+ *      see original source (bottom part of si5351a.cpp file)
+ *         Software License Agreement (BSD License)
+ *         Copyright (c) 2014, Adafruit Industries  All rights reserved.
+ *  2)
+ *      https://gist.github.com/edy555/f1ee7ef44fe4f5c6f7618ac4cbbe66fb
+ *      made by TT@Hokkaido-san (edy555)
+ *      http://ttrftech.tumblr.com/
+ *      http://ttrftech.tumblr.com/post/150247113216/
+ *          si5351a-configuration-how-to-and-signal-quality
+ *
+ *  Modified by Kenji Arai / JH1PJL
+ *      http://www.page.sannet.ne.jp/kenjia/index.html
+ *      http://mbed.org/users/kenjiArai/
+ *
+ *      Started:  December 24th, 2016
+ *      Revised:  January   1st, 2017
+ *
+ */
+
+#ifndef        MBED_SI5351A
+#define        MBED_SI5351A
+
+////////////// ADDRESS /////////////////////////////////////////////////////////
+//  7bit address = 0b1100000(0x60) -> 8bit = 0b11000000(0xc0)
+//      -> Fixed adddress (No other choises)
+#define SI5351_I2C_ADDR     (0x60<<1)
+
+////////////// REGISTER DEFINITION /////////////////////////////////////////////
+#define SI5351_REG_3_OUTPUT_ENABLE_CONTROL  3
+#define SI5351_REG_16_CLK0_CONTROL          16
+#define SI5351_REG_17_CLK1_CONTROL          17
+#define SI5351_REG_18_CLK2_CONTROL          18
+#define SI5351_REG_26_PLL_A                 26
+#define SI5351_REG_34_PLL_B                 34
+#define SI5351_REG_42_MULTISYNTH0           42
+#define SI5351_REG_44_MULTISYNTH0_P3        44
+#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_177_PLL_RESET            177
+#define SI5351_REG_183_CRYSTAL_LOAD         183
+
+////////////// Configration ////////////////////////////////////////////////////
+// PLLn
+#define SI5351_PLL_A        0
+#define SI5351_PLL_B        1
+// CLKn
+#define SI5351_CLK0         0
+#define SI5351_CLK1         1
+#define SI5351_CLK2         2
+// REG_44_MULTISYNTH0, REG_52_MULTISYNTH1, REG_60_MULTISYNTH2
+#define SI5351_R_DIV_1      (0<<4)
+#define SI5351_R_DIV_2      (1<<4)
+#define SI5351_R_DIV_4      (2<<4)
+#define SI5351_R_DIV_8      (3<<4)
+#define SI5351_R_DIV_16     (4<<4)
+#define SI5351_R_DIV_32     (5<<4)
+#define SI5351_R_DIV_64     (6<<4)
+#define SI5351_R_DIV_128    (7<<4)
+#define SI5351_DIVBY4       (3<<2)
+// REG_16_CLK0_CONTROL, REG_17_CLK1_CONTROL, REG_18_CLK2_CONTROL
+#define SI5351_CLK_POWERDOWN                (1<<7)
+#define SI5351_CLK_INTEGER_MODE             (1<<6)
+#define SI5351_CLK_PLL_SELECT_B             (1<<5)
+#define SI5351_CLK_INVERT                   (1<<4)
+#define SI5351_CLK_INPUT_MASK               (3<<2)
+#define SI5351_CLK_INPUT_XTAL               (0<<2)
+#define SI5351_CLK_INPUT_CLKIN              (1<<2)
+#define SI5351_CLK_INPUT_MULTISYNTH_0_4     (2<<2)
+#define SI5351_CLK_INPUT_MULTISYNTH_N       (3<<2)
+#define SI5351_CLK_DRIVE_STRENGTH_MASK      (3<<0)
+#define SI5351_CLK_DRIVE_STRENGTH_2MA       (0<<0)
+#define SI5351_CLK_DRIVE_STRENGTH_4MA       (1<<0)
+#define SI5351_CLK_DRIVE_STRENGTH_6MA       (2<<0)
+#define SI5351_CLK_DRIVE_STRENGTH_8MA       (3<<0)
+// REG_177_PLL_RESET
+#define SI5351_PLL_RESET_B          (1<<7)
+#define SI5351_PLL_RESET_A          (1<<5)
+// REG_183_CRYSTAL_LOAD
+#define SI5351_CRYSTAL_LOAD_6PF     (1<<6)
+#define SI5351_CRYSTAL_LOAD_8PF     (2<<6)
+#define SI5351_CRYSTAL_LOAD_10PF    (3<<6)
+
+// Frequency
+#define FREQ_150MHZ     (150000000UL)
+#define FREQ_100MHZ     (100000000UL)
+#define FREQ_1MHZ       (1000000UL)
+#define FREQ_450KHZ     (450000UL)
+#define FREQ_75KHZ      (75000UL)
+#define FREQ_20KHZ      (20000UL)
+
+typedef enum {  // Operating mode
+  CLK_OUT_NOT_USED  = 0, CLK_OUT_FIXEDPLL, CLK_OUT_FIXEDDIV
+} OperatingMode;
+
+/** Silicon Laboratories Inc. Si5351A
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "si5351a.h"
+ *
+ * I2C i2c(I2C_SDA, I2C_SCL);       // communication with Si5351A
+ * SI5351 clk(i2c, 25000000UL);     // Base clock = 25MHz
+ *
+ * int main() {
+ *   clk.set_frequency(SI5351_CLK0, 10000000);   // CLK0=10MHz
+ *   while(true) {
+ *      wait(1000);
+ *   }
+ * }
+ *
+ * // ---------  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) RESOURCE USAGE
+ * // PLLA -> only for CLK0 (You can change freqency any time to any value.)
+ * // PLLB -> use for bothe CLK1 & CLK2
+ * // If you set a freq. less than 100MHz,
+ * //    You can change both CLK1 & CLK2 independently.
+ * // Over 100MHz, you may have a trouble becase need to change PLLB freq.
+ * //
+ * // 3) DISCONTINUITY
+ * // If you use multiple output, you will lose output signal when you change
+ * //   the output frequency even not specific CLKn during I2C acccess. 
+ * // --------------------------------------------------------------------------
+ *
+ * @endcode
+ */
+
+class SI5351A
+{
+public:
+    /** Configure data pin
+      * @param data SDA and SCL pins
+      * @param External base clock frequency
+      * @param Internal capacitor value (10pF, 8pF & 6pF/ Default 8pF)
+      * @param Output current drive strength(Default 2mA) same value CLK0,1,2
+      */
+    SI5351A(PinName p_sda, PinName p_scl,
+            uint32_t base_clk_freq,
+            uint8_t xtal_cap = SI5351_CRYSTAL_LOAD_8PF,
+            uint8_t drive_current = SI5351_CLK_DRIVE_STRENGTH_2MA
+    );
+
+    /** Configure data pin (with other devices on I2C line)
+      * @param I2C previous definition
+      * @param External base clock frequency
+      * @param Internal capacitor value (10pF, 8pF & 6pF/ Default 8pF)
+      * @param Output current drive strength(Default 2mA) same value CLK0,1,2
+      */
+    SI5351A(I2C& p_i2c,
+            uint32_t base_clk_freq,
+            uint8_t xtal_cap = SI5351_CRYSTAL_LOAD_8PF,
+            uint8_t drive_current = SI5351_CLK_DRIVE_STRENGTH_2MA
+    );
+
+    /** Set frequency
+      * @param output channel CLK0=0, CLK1=1, CLK2=2
+      * @param target frequency (unit = Hz)
+      * @return output frequency
+      */
+    uint32_t set_frequency(uint8_t channel, uint32_t freq);
+
+    /** shift frequency after setting frequency (Range: 750KHz to 100MHz )
+      * @param desired channel CLK0=0, CLK1=1, CLK2=2
+      * @param sift(+/-) frequency (unit = Hz)
+      * @return output frequency
+      */
+    uint32_t shift_freq(uint8_t channel, int32_t diff);
+
+    /** read frequency
+      * @param select channel CLK0=0, CLK1=1, CLK2=2
+      * @return output frequency
+      */
+    uint32_t read_freq(uint8_t channel);
+
+
+    /** reset Si5351A all registers
+      * @param none
+      * @return none
+      */
+    void all_reset(void);
+
+    //--------------- Debug interface -------------------------------  
+
+    /** debug / print registers
+      * @param none
+      * @return none (but print on console)
+      */
+    void debug_reg_print(void);
+
+    /** debug / check registers and shows current configlation
+      * @param none
+      * @return none (but print on console)
+      */
+    void debug_current_config(void);
+
+    /** debug / set CLK0: 120.00MHz, CLK1: 12.00MHz, CLK2: 13.56MHz
+      *          as demonstration purpose for hardware check  (@25MHz Xtal)
+      * @param none
+      * @return none
+      */    
+    void debug_example_clock(void);
+
+protected:
+    I2C  _i2c;
+
+    uint32_t gcd(uint32_t x, uint32_t y);
+    void si5351_read(const uint8_t *buf);
+    void si5351_write(uint8_t reg, uint8_t dat);
+    void si5351_bulk_write(const uint8_t *buf, uint8_t len);
+    double si5351_set_frequency_fixeddiv(
+                        uint8_t     channel,
+                        uint32_t    pll,
+                        uint32_t    freq,
+                        uint32_t    div);
+    double si5351_set_frequency_fixedpll(
+                        uint8_t     channel,
+                        uint32_t    pll,
+                        uint32_t    pllfreq,
+                        uint32_t    freq,
+                        uint8_t     factor);
+    double si5351_setupMultisynth(
+                        uint8_t     output,
+                        uint8_t     pllSource,
+                        uint32_t    div,
+                        uint32_t    num,
+                        uint32_t    denom,
+                        uint8_t     factor);
+    void si5351_setupPLL(
+                        uint8_t     pll,
+                        uint8_t     mult,
+                        uint32_t    num,
+                        uint32_t    denom);
+    void si5351_reset_pll(void);
+    void si5351_enable_output(void);
+    void si5351_disable_output(void);
+    void si5351_disable_all_output(void);
+    void si5351_init(void);
+    void put_dump(const uint8_t *buff, uint8_t ofs, uint8_t cnt);
+    void prnt_reg(uint8_t offset, uint8_t n);
+    void reg_16_17_18(uint8_t dt);
+    void reg_pll_8bytes(uint8_t *buf);
+    void reg_mltisyc_8bytes(uint8_t *buf);
+
+private:
+    uint8_t     addr;           // Chip I2C address
+    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
+    uint32_t    plla_freq;      // Calculated freq of PLLA
+    uint32_t    pllb_freq;      // Calculated freq of PLLB
+    // Setting frequency
+    double      clk0_freq;
+    double      clk1_freq;
+    double      clk2_freq;
+    // operating mode
+    uint8_t     clk0_state;
+    uint8_t     clk1_state;
+    uint8_t     clk2_state;
+
+};   // class SI5351A
+
+#endif  // MBED_SI5351A