▼ Follow for more valuable content
“ In FPGA development, how to design a highly compatible and reliable I2C master controller? Jack believes the key lies in the generation and control of the SCL clock. This article will delve into the design ideas for the I2C bus SCL clock, from frequency division methods, sampling timing to clock phase-shifting strategies.”
01 SCL Clock Design IdeasClock Frequency Division MethodsIn FPGA design, the clock frequencies for the I2C bus standard/fast mode and high-speed mode are generally much lower than the system clock, which means the SCL clock needs to be obtained through frequency division. The commonly used frequency division implementations are as follows:
| Method | Description |
| Logic Implementation | Implement a counter that counts the system clock. When the count value is reached, the divided clock signal is inverted. |
| IP Core Implementation | Use IP cores provided by FPGA manufacturers (PLL/MMCM). Configure the IP core to output the divided clock. |
SDA Sampling TimingIn FPGA timing logic design, we usually use the single edge of the clock for signal synchronization, meaning the value is assigned after the single edge ends. In the I2C bus protocol, the following conventions apply to the SDA data line:
- Data is sampled on the high level of SCL, and data changes occur during the low level of SCL.
- Data must meet the setup time requirements.
- Data must meet the hold time requirements.
| Parameter | Description |
| Setup Time(Setup time) | The minimum time that SDA data must remain stable before the rising edge of the SCL clock. |
| Hold Time(Hold time) | The minimum time that SDA data must remain stable after the rising edge of the SCL clock. |
IIC Clock Generation StrategyWhen the I2C bus operates in standard and fast modes, and the FPGA system clock frequency is relatively high (≥8M), the timing margin of the SDA data line is sufficient, allowing the direct use of the clock divider from the previous section to generate the SCL_CLK clock. This clock can function normally in a relatively ideal environment and simple I2C bus applications. However, when I2C operates in high-speed mode, high reliability, high compatibility, and under stringent environmental requirements, we can also phase-shift the SCL_CLK clock, using the phase-shifted clock as the SCL clock, while SCL_CLK is used for I2C timing control.
| Clock | Description |
| SCL_CLK | Obtained by dividing the system clock through PLL/MMCM/logic divider. |
| IIC_CLK | Simple application: IIC_CLK = SCL_CLK; Phase-shifted application: IIC_CLK = offset * SCL_CLK. |
| Note:To achieve high compatibility, the phase-shifting method is used to generate the SCL clock. |
02 SCL Clock Design ImplementationIn the previous section, we chose logic division as the clock division method, generating the SCL clock through frequency division followed by phase-shifting. This section will provide a detailed design based on the previous content.Logic Division DesignTo achieve compatibility, we use logic division for frequency division. To achieve precise frequency division, we first need to clarify the clock frequency of the I2C bus and then confirm the count value of the counter. The calculation formula is as follows:
| f_iic = f_system / (2 * count)where, f_system: system clock frequency.f_iic: I2C bus frequency.count: count value. Each time the count value is reached, the clock level is switched, so the frequency calculation needs to be multiplied by 2. |
In the previous interface design, the frequency division count value (CLK_DIV) is used as a parameter. Therefore, for the logic implementation of the divider, the required resources are as follows:
| Signal | Type | bit | Description |
| scl_clk | reg | 1 | The clock obtained from frequency division |
| clk_div_cnt | reg | 16 | Counter accumulation number |
The Verilog code for the logic implementation of the divider is as follows:
reg scl_clk;reg [15:0] clk_div_cnt; // SCL_CLK: system clock divide control. always @(posedge clk_i or negedge rst_n) begin if(rst_n == 1'b0) begin clk_div_cnt <= 16'd0; scl_clk <= 1'b1; end else begin if(clk_div_cnt < CLK_DIV) clk_div_cnt <= clk_div_cnt + 1'b1; else begin clk_div_cnt <= 16'd0; scl_clk <= ~scl_clk; end endend
Clock Phase-Shifting DesignIn the I2C bus, clock phase-shifting is used to ensure that the setup time and hold time of the SDA data meet the timing requirements on the SCL clock. The common phase-shifting ratios and applications are shown in the table below:
| Phase Shift Ratio | Description |
| 90 degrees (1/4) | Advantages: Balances setup time and hold time.Application: The most commonly used phase shift ratio. |
| 180 degrees (1/2) | Advantages: Maximum setup time.Disadvantages: Minimum hold time. Application: Scenarios with strict setup time requirements. |
| 45 degrees (1/8) | Advantages: Ample hold time.Disadvantages: Short setup time.Application: Scenarios with strict hold time requirements. |
| Selection Criteria:90 degrees (1/4): Multiple slave devices, general mode (standard/fast/high-speed).180 degrees (1/2): Strict setup time requirements.45 degrees (1/8): Strict hold time requirements. |
For a general IIC master controller, we choose the most commonly used phase-shift of 1/4 clock to generate the SCL clock. Based on the I2C bus, the SDA data switches during the low level, is valid during the high level, and switches at the falling edge, thus we have the following design for the SCL clock:
- The SCL clock is the inverted clock of the SCL_CLK clock.
- The SCL clock is phase-shifted by 1/4 cycle relative to the SCL_CLK clock.
This means that the SCL_CLK clock is inverted after being phase-shifted by 1/4 to obtain the SCL clock for the I2C bus. The clock phase and offset are shown below:
clk_div_cnt: 0 → 1 → ... → SCL_CLK_OFFSET → ... → CLK_DIV → 0 ↓ Timing state switch, write operation data shift, bits & byte count scl_clk: ┌───┐ ┌───┐ ┌───┐ │ │ │ │ │ │ ───┘ └───┘ └───┘ └─── iic_scl: ┌───┐ ┌───┐ ┌───┐ │ │ │ │ │ │ ──┘ └───┘ └───┘ └──── ↑ Bus data capture edge Note: 1. scl_clk serves as the timing logic clock for the I2C master controller; 2. iic_scl is the I2C bus clock signal output to the IIC slave; 3. At the falling edge of the scl_clk clock, timing state switches, write operation data shifts, etc., are executed; 4. SDA data is captured during the high level of iic_scl.
Clock Level ControlAccording to the I2C bus protocol, the SCL clock line only has pulse signals during transmission, and remains high when idle. Therefore, based on the previously generated phase-shifted 1/4 and inverted SCL clock, we need to add control conditions: “maintain high level under idle conditions.”The complete Verilog code for implementing SCL clock control is as follows:
// ============================================================================// iic_scl: timing control. // ============================================================================localparam SCL_CLK_OFFSET = CLK_DIV - CLK_DIV/4; reg scl_clk;reg scl_clk_reg;reg [15:0] clk_div_cnt; // SCL_CLK: system clock divide control. always @(posedge clk_i or negedge rst_n) begin if(rst_n == 1'b0) begin clk_div_cnt <= 16'd0; scl_clk <= 1'b1; end else begin if(clk_div_cnt < CLK_DIV) clk_div_cnt <= clk_div_cnt + 1'b1; else begin clk_div_cnt <= 16'd0; scl_clk <= ~scl_clk; end endend // iic_scl: generate a 1/4 phase-shift clock for scl_clk. always @(posedge clk_i or negedge rst_n) begin if(rst_n == 1'b0) scl_clk_reg <= 1'b1; else if(clk_div_cnt == SCL_CLK_OFFSET) begin if(current_state == IDLE || current_state == STOP1 || current_state == STOP2 || current_state == ERROR) scl_clk_reg <= 1'b1; else scl_clk_reg <= ~scl_clk; endend assign iic_scl = scl_clk_reg;
03 Conclusion
Through logic division and precise clock phase-shifting design, we have implemented a highly compatible I2C SCL clock control code. It not only meets the timing requirements in multi-mode and multi-device scenarios but also balances setup time and hold time.
Following this series of articles, we will gradually transform theory into practice, from timing analysis to state machine division, functional design ideas to final code implementation, ultimately achieving a robust IIC master controller. Stay tuned!
✨ Thank you for reading! ✨
Click ‘Like’ to let more friends see this valuable content 🌟