I'm trying to implement an I2C master - slave example in an FPGA (Verilog).
As the I2C protocol specifies, the master must make sure that it writes the next bit enough time before the clock signal goes high (rising edge in SCL). Then, the slave can read this bit in the mentioned rising edge. To achieve this I generate 2 clock phase-shifted signals: one (whose rising edge comes before) is used as a clock signal to write each bit. The other, is directly connected to SDA.
However, the slave is not aware of the mentioned first signal, it just receives SCL. Then, how can the slave write bits before the SCL rising edge arrives? In which edge should it write?
Verilog code
Clock generator
module double_clk_gen
#(parameter CLK_DIV = 20,
parameter CLK0_HS = 1,
parameter CLK1_HS = 1'bz) (
output reg clkout0,
output reg clkout1,
input wire en,
input wire clk
);
localparam CS_START = 0, CS_RUN = 1;
parameter div = CLK_DIV / 2;
reg [15:0] cnt;
always @ (posedge clk) begin
if (en) begin
if (cnt < 1*div) begin
clkout0 <= CLK0_HS;
clkout1 <= 0;
end else if ((cnt >= 1*div) && (cnt < 2*div)) begin
clkout0 <= CLK0_HS;
clkout1 <= CLK1_HS;
end else if ((cnt >= 2*div) && (cnt < 3*div)) begin
clkout0 <= 0;
clkout1 <= CLK1_HS;
end else if ((cnt >= 3*div) && (cnt < 4*div)) begin
clkout0 <= 0;
clkout1 <= 0;
end else begin
clkout0 <= clkout0;
clkout1 <= clkout1;
end
if (cnt == 4*div - 1)
cnt <= 0;
else
cnt <= cnt + 1;
end else begin
clkout0 <= 0;
clkout1 <= CLK1_HS;
cnt <= 0;
end
end
endmodule
Timing diagrams
Two clk. signals
SDA
and SCL
are the normal I2C signals. _sda_clk
is the clock signal generated to write the bits, which is phase-shifted with regards to SCL to write them before the latter's rising edge.