i2c-output-expander/i2c_receiver.sv
2022-06-14 12:50:47 +03:00

107 lines
2.7 KiB
Systemverilog

`timescale 1ps/1ps
`default_nettype none
module i2c_receiver
(input wire clock,
input wire reset,
input wire i_scl,
input wire i_sdi,
output wire o_sdo,
output wire [7:0] o_data,
output wire o_strobe,
output wire o_start,
output wire o_stop,
input wire i_ack); // Active ONE
logic sdi_prev;
logic scl_prev;
logic start_condition;
logic stop_condition;
logic scl_rise;
logic scl_fall;
always_ff @(posedge clock)
if (reset) begin
sdi_prev <= 1'b1;
scl_prev <= 1'b1;
end
else begin
sdi_prev <= i_sdi;
scl_prev <= i_scl;
end
assign start_condition = (sdi_prev == 1'b1) && (i_sdi == 1'b0) && (scl_prev == 1'b1) && (i_scl == 1'b1);
assign stop_condition = (sdi_prev == 1'b0) && (i_sdi == 1'b1) && (scl_prev == 1'b1) && (i_scl == 1'b1);
assign scl_rise = (scl_prev == 1'b0) && (i_scl == 1'b1);
assign scl_fall = (scl_prev == 1'b1) && (i_scl == 1'b0);
enum int unsigned {
ST_WAIT_FOR_START = 0,
ST_RECEIVE_BITS,
ST_WAIT_FOR_SCL_LOW,
ST_SEND_ACK
} state;
logic [2:0] bit_cntr;
logic [7:0] data_sr;
logic byte_strobe;
logic sdo;
always_ff @(posedge clock)
if (reset) begin
state <= ST_WAIT_FOR_START;
bit_cntr <= '0;
byte_strobe <= 1'b0;
sdo <= 1'b1;
end
else begin
byte_strobe <= 1'b0;
if (stop_condition)
state <= ST_WAIT_FOR_START;
else
case (state)
ST_WAIT_FOR_START: begin
sdo <= 1'b1;
if (start_condition) begin
bit_cntr <= '0;
state <= ST_RECEIVE_BITS;
end
end
ST_RECEIVE_BITS:
if (scl_rise) begin
data_sr <= {data_sr[6:0], i_sdi};
bit_cntr <= bit_cntr + 1'b1;
if (bit_cntr == 3'd7) begin
state <= ST_WAIT_FOR_SCL_LOW;
byte_strobe <= 1'b1;
end
end
ST_WAIT_FOR_SCL_LOW:
if (scl_fall) begin
sdo <= i_ack ? 1'b0 : 1'b1;
state <= ST_SEND_ACK;
end
ST_SEND_ACK:
if (scl_fall) begin
sdo <= 1'b1;
state <= ST_RECEIVE_BITS;
end
endcase
end
assign o_data = data_sr;
assign o_strobe = byte_strobe;
assign o_start = start_condition;
assign o_stop = stop_condition;
assign o_sdo = sdo;
endmodule // i2c_receiver