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