90 lines
2.3 KiB
Systemverilog
90 lines
2.3 KiB
Systemverilog
`timescale 1ps/1ps
|
|
`default_nettype none
|
|
|
|
module i2c_io_output #(parameter [6:0] I2C_ADDR = 7'h5a,
|
|
parameter IO_BYTES_COUNT = 2,
|
|
localparam DATA_WIDTH = IO_BYTES_COUNT * 8)
|
|
(input wire clock,
|
|
input wire reset,
|
|
|
|
input wire i_scl,
|
|
input wire i_sdi,
|
|
output wire o_sdo,
|
|
|
|
output reg [DATA_WIDTH-1:0] o_data);
|
|
|
|
/* -------- I2C Receiver -------- */
|
|
logic [7:0] i2c_data;
|
|
logic i2c_strobe;
|
|
logic i2c_start;
|
|
logic i2c_stop;
|
|
logic i2c_ack;
|
|
|
|
i2c_receiver i2c_receiver_impl
|
|
(.clock(clock), .reset(reset),
|
|
.i_scl(i_scl), .i_sdi(i_sdi), .o_sdo(o_sdo),
|
|
.o_data(i2c_data),
|
|
.o_strobe(i2c_strobe),
|
|
.o_start(i2c_start),
|
|
.o_stop(i2c_stop),
|
|
.i_ack(i2c_ack));
|
|
|
|
/* -------- FSM -------- */
|
|
enum int unsigned {
|
|
ST_IDLE = 0,
|
|
ST_RECEIVE_ADDR,
|
|
ST_RECEIVE_BYTE,
|
|
ST_COMPLETE
|
|
} state;
|
|
|
|
localparam BYTE_CNTR_W = $clog2(IO_BYTES_COUNT);
|
|
|
|
logic [BYTE_CNTR_W-1:0] byte_cntr;
|
|
logic [DATA_WIDTH-1:0] data;
|
|
|
|
always_ff @(posedge clock)
|
|
if (reset) begin
|
|
state <= ST_IDLE;
|
|
byte_cntr <= '0;
|
|
end
|
|
else begin
|
|
if (i2c_stop)
|
|
state <= ST_IDLE;
|
|
case (state)
|
|
ST_IDLE: begin
|
|
if (i2c_start)
|
|
state <= ST_RECEIVE_ADDR;
|
|
end
|
|
|
|
ST_RECEIVE_ADDR: begin
|
|
if (i2c_strobe)
|
|
if (i2c_data == {I2C_ADDR, 1'b0}) begin
|
|
i2c_ack <= 1'b1;
|
|
byte_cntr <= '0;
|
|
state <= ST_RECEIVE_BYTE;
|
|
end
|
|
else begin
|
|
i2c_ack <= 1'b0;
|
|
state <= ST_IDLE;
|
|
end
|
|
end
|
|
|
|
ST_RECEIVE_BYTE: begin
|
|
if (i2c_strobe) begin
|
|
data <= {data[DATA_WIDTH-8-1:0], i2c_data}; // MSB first
|
|
byte_cntr <= byte_cntr + 1'b1;
|
|
|
|
if (byte_cntr == BYTE_CNTR_W'(IO_BYTES_COUNT-1))
|
|
state <= ST_COMPLETE;
|
|
end
|
|
end
|
|
|
|
ST_COMPLETE: begin
|
|
o_data <= data;
|
|
state <= ST_IDLE;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
endmodule // i2c_io_output
|