107 lines
2.7 KiB
Systemverilog
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
|