I2C Controller in Verilog

I2C Master


module i2c_master (
    input wire clk,               // System clock
    input wire reset,             // Reset signal
    input wire start,             // Start transmission signal
    input wire [6:0] address,     // I2C slave address
    input wire [7:0] data_in,     // Data to send
    output reg sda,               // Serial Data Line
    output reg scl,               // Serial Clock Line
    output reg done               // Transmission done flag
);
    // States
    parameter IDLE = 3'b000,
              START = 3'b001,
              SEND_ADDR = 3'b010,
              SEND_DATA = 3'b011,
              STOP = 3'b100;

    reg [2:0] state;              // Current state
    reg [3:0] bit_cnt;            // Bit counter
    reg [7:0] shift_reg;          // Shift register for data

    always @(posedge clk or posedge reset) begin
        if (reset) begin
            state <= IDLE;
            sda <= 1'b1;            // Idle state for SDA is high
            scl <= 1'b1;            // Idle state for SCL is high
            done <= 1'b0;
            bit_cnt <= 4'b0;
            shift_reg <= 8'b0;
        end else begin
            case (state)
                IDLE: begin
                    done <= 1'b0;
                    if (start) begin
                        state <= START;
                        shift_reg <= {address, 1'b0}; // Address with write bit
                        bit_cnt <= 7; // 7 bits for address
                        sda <= 1'b0; // Start condition
                    end
                end

                START: begin
                    scl <= 1'b0; // Pull SCL low
                    state <= SEND_ADDR;
                end

                SEND_ADDR: begin
                    if (bit_cnt >= 0) begin
                        sda <= shift_reg[bit_cnt]; // Send address bit
                        bit_cnt <= bit_cnt - 1;
                    end else begin
                        state <= SEND_DATA; // Move to data state
                        bit_cnt <= 7; // Reset bit counter for data
                        shift_reg <= data_in; // Load data to shift register
                    end
                end

                SEND_DATA: begin
                    if (bit_cnt >= 0) begin
                        sda <= shift_reg[bit_cnt]; // Send data bit
                        bit_cnt <= bit_cnt - 1;
                    end else begin
                        state <= STOP; // Move to stop state
                    end
                end

                STOP: begin
                    scl <= 1'b1; // Pull SCL high
                    sda <= 1'b1; // Stop condition
                    done <= 1'b1; // Indicate transmission done
                    state <= IDLE; // Go back to idle
                end

                default: state <= IDLE; // Default to idle
            endcase
        end
    end
endmodule