You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
5.7 KiB
189 lines
5.7 KiB
module i2c_slave (input CLK, input RESET,
|
|
input SCL, inout SDA,
|
|
output IS_TRANSMISSION, output IS_READ, output IS_ACK, output WR, //output ACK_MASTER_CTRL,
|
|
output [7:0] RECEIVED_BYTE, input [7:0] BYTE_TO_TRANSMIT,
|
|
output [(MAX_I2C_TRANSACTION_EXP2-1):0] COUNTER);
|
|
// ALL OPERATIONS WITH MEMORY ARE IN POSEDGE CLK, IN NEGEDGE - ONLY SCL AND SDA LATCH
|
|
// COUNTER = 0 - ADRESS RECEIVED, COUNTER >=1 - DATA TRANSMISSION
|
|
// RECEIVED BYTES MUST READ WHEN WR POSEDGE, ADRESS NOT READING ###AND BYTE COUNTER >=1 (BYTE COUNTER = 0 - ADRESS)
|
|
// BYTES TO TRANSMIT MUST WRITE WHEN WR POSEDGE, BYTE COUNTER CAN BE ZERO
|
|
// (FIRST BYTE TRANSMITTED AFTER ADRESS).
|
|
// LAST BYTE HAS NO WR ####BUT LAST BYTE NOT TRANSMITTED (DECAUSE MASTER STOPS TRANSMIT)
|
|
|
|
parameter I2C_ADRESS = 7'h34;
|
|
parameter MAX_I2C_TRANSACTION_EXP2 = 8; // !!! - FOR LIMIT BYTES TO TX/RX (WITH ADRESS)
|
|
|
|
reg /*SDA_IN,*/ SDA_DIR, SDA_OUT;
|
|
wire SDA_IN;
|
|
initial begin
|
|
SDA_OUT = 0;
|
|
end
|
|
|
|
/*reg*/wire SCLD, SDAD;
|
|
|
|
reg SCL_LAST, SDA_LAST;
|
|
reg i2c_state_machine;
|
|
reg i2c_start_latency; // GETS LATENCY (ONE CLK) TO IS_TRANSMISSION WIRE
|
|
// NEEDS WHEN START REPEAT OCCURS
|
|
// WITHOUT THIS THERE ARE NO SIGNALS TO CALL ABOUT END OF PACKET BEFORE START REPEAT
|
|
initial begin
|
|
SCL_LAST = 1; SDA_LAST = 1; i2c_state_machine = 0;
|
|
end
|
|
reg is_read;
|
|
reg [3:0] i2c_bit_counter;
|
|
reg [7:0] received_byte;
|
|
reg [7:0] byte_to_transmit;
|
|
reg [(MAX_I2C_TRANSACTION_EXP2-1):0] byte_counter;
|
|
//reg is_for_me;
|
|
reg is_ack;
|
|
reg wr;//reg ack_master_ctrl;
|
|
|
|
// FILTER
|
|
reg SCLF, SDAF;
|
|
reg [3:0] scl_cnt, sda_cnt;
|
|
|
|
simple_filter FLT_SCL (CLK, RESET, SCLF, SCLD);
|
|
simple_filter FLT_SDA (CLK, RESET, SDAF, SDAD);
|
|
|
|
always@(negedge CLK) begin
|
|
SCLF <= SCL;
|
|
SDAF <= SDA_IN;
|
|
end
|
|
|
|
always@(posedge CLK or negedge RESET) begin
|
|
if (RESET == 0)
|
|
i2c_state_machine <= 0;
|
|
else begin
|
|
/* if (scl_cnt != 0) begin
|
|
scl_cnt = scl_cnt - 1;
|
|
if (scl_cnt == 0) begin
|
|
if (SCLD != SCLF)
|
|
SCLD = SCLF;
|
|
end
|
|
end
|
|
else begin
|
|
if (SCLD != SCLF)
|
|
scl_cnt = 3'd7;
|
|
end
|
|
if (sda_cnt != 0) begin
|
|
sda_cnt = sda_cnt - 1;
|
|
if (sda_cnt == 0) begin
|
|
if (SDAD != SDAF)
|
|
SDAD = SDAF;
|
|
end
|
|
end
|
|
else begin
|
|
if (SDAD != SDAF)
|
|
sda_cnt = 3'd7;
|
|
end*/
|
|
// END OF FILTER
|
|
|
|
//SDA_IN = SDA; // FOR IVERILOG
|
|
if ((SDAD == 0) && (SDA_LAST == 1) && (SCLD == 1)) begin
|
|
i2c_state_machine = 1;
|
|
i2c_start_latency = 0;
|
|
i2c_bit_counter = 4'd8;
|
|
byte_counter = 9'd0;
|
|
//is_for_me = 1; // RESETS TO ZERO WHEN ADRESS CHECKING
|
|
SDA_DIR = 0;
|
|
is_ack = 0;
|
|
//ack_master_ctrl = 1;
|
|
wr = 0;
|
|
end
|
|
else if ((i2c_state_machine == 1) && (i2c_start_latency == 0)) begin
|
|
i2c_start_latency = 1;
|
|
is_read = 0;
|
|
end
|
|
if ((SDAD == 1) && (SDA_LAST == 0) && (SCLD == 1)) begin
|
|
i2c_state_machine = 0;
|
|
SDA_DIR = 0;
|
|
wr = 0;
|
|
end
|
|
if (i2c_state_machine/* && is_for_me*/) begin
|
|
if (!is_read) begin
|
|
if (i2c_bit_counter > 0) begin
|
|
if ((SCL_LAST == 0) && (SCLD == 1)) begin
|
|
received_byte[i2c_bit_counter-1] = SDAD;
|
|
i2c_bit_counter = i2c_bit_counter - 1;
|
|
end
|
|
end
|
|
else begin
|
|
if ((SCL_LAST == 1) && (SCLD == 0) && (is_ack == 0)) begin
|
|
if (byte_counter == 0) begin
|
|
if (received_byte[7:1] != I2C_ADRESS)
|
|
i2c_state_machine = 0; //is_for_me = 0;
|
|
is_read = received_byte[0];
|
|
end
|
|
else begin
|
|
// EMIT SIGNAL OF BYTE RECEIVING
|
|
end
|
|
if (byte_counter != ((1<<MAX_I2C_TRANSACTION_EXP2) - 1))
|
|
byte_counter = byte_counter + 1;
|
|
SDA_DIR = i2c_state_machine; //is_for_me;
|
|
is_ack = i2c_state_machine; //1;
|
|
//if (is_read) begin
|
|
// i2c_bit_counter = 8;
|
|
//end
|
|
end
|
|
else if ((SCL_LAST == 0) && (SCLD == 1) && (is_ack == 1) && (byte_counter > 1))
|
|
wr = 1;
|
|
else if ((SCL_LAST == 1) && (SCLD == 0) && (is_ack == 1)) begin
|
|
is_ack = 0;
|
|
SDA_DIR = 0;
|
|
i2c_bit_counter = 4'd8;
|
|
wr = 0;
|
|
end
|
|
end
|
|
end
|
|
else begin // IS_READ
|
|
if (i2c_bit_counter > 0) begin
|
|
if ((SCL_LAST == 1) && (SCLD == 0)) begin
|
|
wr = 0;
|
|
SDA_DIR = (BYTE_TO_TRANSMIT[i2c_bit_counter-1] ^ 1) /*& is_for_me & ack_master_ctrl*/;
|
|
i2c_bit_counter = i2c_bit_counter - 1;
|
|
is_ack = 0;
|
|
end
|
|
end
|
|
else begin
|
|
if ((SCL_LAST == 1) && (SCLD == 0) && (is_ack == 0)) begin
|
|
SDA_DIR = 0;
|
|
is_ack = 1;
|
|
end
|
|
else if ((SCL_LAST == 0) && (SCLD == 1) && (is_ack == 1)) begin
|
|
i2c_bit_counter = 8;
|
|
i2c_state_machine = (SDAD ^ 1) | SDA_DIR; //ack_master_ctrl = SDAD+1; // MAYBE TRANSMIT BYTE REPEAT
|
|
wr = (SDAD ^ 1) | SDA_DIR;
|
|
if (byte_counter != ((1<<MAX_I2C_TRANSACTION_EXP2) - 1))
|
|
byte_counter = byte_counter + 1;
|
|
// EMIT SIGNAL OF BYTE TO TRANSMIT
|
|
end
|
|
end
|
|
end
|
|
end
|
|
SCL_LAST <= SCLD;
|
|
SDA_LAST <= SDAD;
|
|
//SDA_OUT = (SDA_DIR ^ 1) & SDA; // FOR IVERILOG
|
|
end
|
|
end
|
|
|
|
assign IS_TRANSMISSION = i2c_state_machine & i2c_start_latency;
|
|
//assign SDA = SDA_DIR ? 1'b0 : 1'bz;
|
|
assign IS_ACK = is_ack;
|
|
assign IS_READ = is_read;
|
|
assign WR = wr;//assign ACK_MASTER_CTRL = ack_master_ctrl;
|
|
assign RECEIVED_BYTE = received_byte;
|
|
//assign BYTE_TO_TRANSMIT = byte_to_transmit;
|
|
assign COUNTER = byte_counter;
|
|
|
|
SB_IO #(
|
|
.PIN_TYPE(6'b 1010_01),
|
|
.PULLUP(1'b 0)
|
|
) i2c_io (
|
|
.PACKAGE_PIN(SDA),
|
|
.OUTPUT_ENABLE(SDA_DIR),
|
|
.D_OUT_0(SDA_OUT),
|
|
.D_IN_0(SDA_IN)
|
|
);
|
|
|
|
endmodule
|