2023-11-09 22:10:34 +00:00
|
|
|
/* 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 <http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
module I2C_driver (
|
|
|
|
input wire clock,
|
2023-12-04 22:40:53 +00:00
|
|
|
input wire SDA_input,
|
|
|
|
output wire SDA_output,
|
|
|
|
output reg SDA_direction, //1:output 0:input
|
2023-11-09 22:10:34 +00:00
|
|
|
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;
|
|
|
|
|
2023-12-04 22:40:53 +00:00
|
|
|
assign SDA_output=SDA;
|
2023-11-09 22:10:34 +00:00
|
|
|
|
|
|
|
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
|
2023-12-04 22:40:53 +00:00
|
|
|
SDA_direction<=1;
|
2023-11-09 22:10:34 +00:00
|
|
|
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;
|
2023-12-04 22:40:53 +00:00
|
|
|
SDA_direction<=0;
|
2023-11-09 22:10:34 +00:00
|
|
|
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;
|
2023-12-09 00:53:52 +00:00
|
|
|
if (SDA_input==1)begin
|
|
|
|
i2c_state<=6'b111111; //TODO: Don't freeze the entire driver if a single error occurs!! (here and on the second ack as well)
|
|
|
|
end else begin
|
2023-11-09 22:10:34 +00:00
|
|
|
i2c_state<=6'b001111;
|
|
|
|
data_bit_counter<=0;
|
2023-12-09 00:53:52 +00:00
|
|
|
end
|
2023-11-09 22:10:34 +00:00
|
|
|
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;
|
2023-12-04 22:40:53 +00:00
|
|
|
SDA_direction<=1;
|
2023-11-09 22:10:34 +00:00
|
|
|
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
|
2023-12-04 22:40:53 +00:00
|
|
|
SDA_direction<=0;
|
2023-11-09 22:10:34 +00:00
|
|
|
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;
|
2023-12-09 00:53:52 +00:00
|
|
|
if (SDA_input==1)begin
|
|
|
|
i2c_state<=6'b111111;
|
|
|
|
end else begin
|
2023-11-09 22:10:34 +00:00
|
|
|
i2c_state<=6'b011100;
|
2023-12-04 22:40:53 +00:00
|
|
|
SDA_direction<=1;
|
2023-12-09 00:53:52 +00:00
|
|
|
end
|
2023-11-09 22:10:34 +00:00
|
|
|
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
|