/* I2C_driver.v - Implements an I2C interface This file is part of the 9086 project. Copyright (c) 2023 Efthymios Kritikos This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ module I2C_driver ( input wire clock, inout wire SDA_, output reg SCL, input wire [6:0] address, output reg I2C_BUSY=0, input wire I2C_SEND, input wire [7:0] i2c_data ); reg SDA; reg i2c_bus_dir=0; assign SDA_=(i2c_bus_dir==0)?SDA:1'bz; reg [5:0] i2c_state = 6'b100100; reg [3:0] data_bit_counter; reg [7:0] data_internal; reg [6:0]address_internal; always @(posedge clock) begin case (i2c_state) /***** start sequence ******/ 6'b000000:begin i2c_bus_dir<=0; SDA<=1; SCL<=1; i2c_state<=6'b000001; end 6'b000001:begin SDA<=0; SCL<=1; i2c_state<=6'b000010; end 6'b000010:begin SDA<=0; SCL<=0; i2c_state<=6'b000011; data_bit_counter<=0; end /****** Set address ********/ 6'b000011:begin SCL<=0; i2c_state<=6'b000100; end 6'b000100:begin SCL<=0; SDA<=address_internal[6:6]; address_internal[6:0]<={address_internal[5:0],1'b0}; data_bit_counter<=data_bit_counter+1; i2c_state<=6'b000101; end 6'b000101:begin SCL<=1; i2c_state<=6'b000110; end 6'b000110:begin SCL<=1; if(data_bit_counter==4'd7) i2c_state<=6'b000111; else i2c_state<=6'b000011; end /****** Read/Write *********/ 6'b000111:begin SCL<=0; i2c_state<=6'b001000; end 6'b001000:begin SCL<=0; SDA<=0;/*Write=0 Read=1*/ i2c_state<=6'b001001; end 6'b001001:begin SCL<=1; i2c_state<=6'b001010; end 6'b001010:begin SCL<=1; i2c_state<=6'b001011; end /****** Acknowledge ********/ 6'b001011:begin SCL<=0; i2c_bus_dir<=1; i2c_state<=6'b001100; end 6'b001100:begin SCL<=0; i2c_state<=6'b001101; end 6'b001101:begin SCL<=1; i2c_state<=6'b001110; end 6'b001110:begin SCL<=1; // if (SDA==1)begin // led<=1; // i2c_state<=6'b011111; // end else begin i2c_state<=6'b001111; data_bit_counter<=0; // end end /****** separator ********/ 6'b001111:begin SCL<=0; SDA<=0; i2c_state<=6'b010000; end 6'b010000:begin SCL<=0; i2c_state<=6'b010001; end 6'b010001:begin SCL<=0; SDA<=1; i2c_state<=6'b010010; end 6'b010010:begin SCL<=0; SDA<=1; i2c_state<=6'b010011; end 6'b010011:begin SCL<=0; SDA<=0; i2c_state<=6'b010100; end /****** Send data ********/ 6'b010100:begin SCL<=0; i2c_bus_dir<=0; i2c_state<=6'b010101; end 6'b010101:begin SCL<=0; SDA<=data_internal[7:7]; data_internal[7:0]<={data_internal[6:0],1'b0}; data_bit_counter<=data_bit_counter+1; i2c_state<=6'b010110; end 6'b010110:begin SCL<=1; i2c_state<=6'b010111; end 6'b010111:begin SCL<=1; if(data_bit_counter==4'd8)begin i2c_state<=6'b011000; end else i2c_state<=6'b010100; end /****** Acknowledge ********/ 6'b011000:begin i2c_bus_dir<=1; SCL<=0; i2c_state<=6'b011001; end 6'b011001:begin SCL<=0; i2c_state<=6'b011010; end 6'b011010:begin SCL<=1; i2c_state<=6'b011011; end 6'b011011:begin SCL<=1; // if (SDA==1)begin // led<=1; // i2c_state<=6'b011111; // end else begin i2c_state<=6'b011100; i2c_bus_dir<=0; // end end /****** separator ********/ 6'b011100:begin SCL<=0; SDA<=0; i2c_state<=6'b011101; end 6'b011101:begin SCL<=0; i2c_state<=6'b011110; end 6'b011110:begin SCL<=0; SDA<=1; i2c_state<=6'b011111; end 6'b011111:begin SCL<=0; SDA<=1; i2c_state<=6'b100000; end 6'b100000:begin SCL<=0; SDA<=0; i2c_state<=6'b100001; end /****** stop bit *******/ 6'b100001:begin SCL<=1; SDA<=0; i2c_state<=6'b100010; end 6'b100010:begin SCL<=1; SDA<=1; i2c_state<=6'b100011; end 6'b100011:begin SCL<=1; SDA<=1; i2c_state<=6'b100100; I2C_BUSY<=0; end 6'b100100:begin if(I2C_SEND==1)begin I2C_BUSY<=1; i2c_state<=0; data_internal<=i2c_data; address_internal<=address; end end default:begin SCL<=0; SDA<=0; end endcase end endmodule