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