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.

177 lines
5.0 KiB

6 years ago
module i2c_slave (input CLK,
input SCL, /*inout SDA,*/SDA_IN, output SDA_OUT, // FOR TEST
output IS_TRANSMISSION, output IS_READ, output IS_ACK, output WR, //output ACK_MASTER_CTRL,
output /*reg*/ [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 = 9; // !!! - FOR LIMIT BYTES TO TX/RX (WITH ADRESS)
reg /*SDA_IN,*/ SDA_DIR;//, SDA_OUT; // DELETED FOR TEST
initial begin
//SDA_OUT = 0; // DELETED FOR TEST
SCLD = 1;
SDAD = 1;
end
reg SCLD, SDAD;
reg SCL_LAST, SDA_LAST;
reg i2c_state_machine;
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;
always@(negedge CLK) begin
SCLF = SCL;
SDAF = SDA_IN;
end
always@(posedge CLK) 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_bit_counter = 4'd8;
byte_counter = 9'd0;
is_read = 0;
//is_for_me = 1; // RESETS TO ZERO WHEN ADRESS CHECKING
SDA_DIR = 0;
is_ack = 0;
//ack_master_ctrl = 1;
wr = 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 != (2^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 != (2^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
assign IS_TRANSMISSION = i2c_state_machine;
//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;
assign SDA_OUT = SDA_DIR ^ 1;
/* SB_IO #(
.PIN_TYPE(6'b 1010_01),
.PULLUP(1'b 0)
) led_io (
.PACKAGE_PIN(SDA),
.OUTPUT_ENABLE(SDA_DIR),
.D_OUT_0(SDA_OUT),
.D_IN_0(SDA_IN)
); */ // DELETED FOR TEST
endmodule