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/

si5351a.h

Committer:
kenjiArai
Date:
2017-01-05
Revision:
1:a2309757c450
Parent:
0:47b9bfa03730
Child:
2:8fe745836ea6

File content as of revision 1:a2309757c450:

/*
 * 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   5th, 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