mirror of
https://github.com/MiSTer-devel/MacPlus_MiSTer.git
synced 2024-11-30 05:49:36 +00:00
97 lines
2.1 KiB
Verilog
97 lines
2.1 KiB
Verilog
|
|
module i2c
|
|
(
|
|
input CLK,
|
|
|
|
input START,
|
|
input READ,
|
|
input [6:0] I2C_ADDR,
|
|
input I2C_WLEN, // 0 - one byte, 1 - two bytes
|
|
input [7:0] I2C_WDATA1,
|
|
input [7:0] I2C_WDATA2,
|
|
output [7:0] I2C_RDATA,
|
|
output reg END = 1,
|
|
output reg ACK = 0,
|
|
|
|
//I2C bus
|
|
output I2C_SCL,
|
|
inout I2C_SDA
|
|
);
|
|
|
|
|
|
// Clock Setting
|
|
parameter CLK_Freq = 50_000_000; // 50 MHz
|
|
parameter I2C_Freq = 400_000; // 400 KHz
|
|
|
|
localparam I2C_FreqX2 = I2C_Freq*2;
|
|
|
|
reg I2C_CLOCK;
|
|
reg [31:0] cnt;
|
|
wire [31:0] cnt_next = cnt + I2C_FreqX2;
|
|
|
|
always @(posedge CLK) begin
|
|
cnt <= cnt_next;
|
|
if(cnt_next >= CLK_Freq) begin
|
|
cnt <= cnt_next - CLK_Freq;
|
|
I2C_CLOCK <= ~I2C_CLOCK;
|
|
end
|
|
end
|
|
|
|
assign I2C_SCL = SCLK | I2C_CLOCK;
|
|
assign I2C_SDA = SDO[3] ? 1'bz : 1'b0;
|
|
|
|
reg SCLK = 1;
|
|
reg [3:0] SDO = 4'b1111;
|
|
reg [0:7] rdata;
|
|
|
|
assign I2C_RDATA = rdata;
|
|
|
|
always @(posedge CLK) begin
|
|
reg old_clk;
|
|
reg old_st;
|
|
reg rd,len;
|
|
|
|
reg [5:0] SD_COUNTER = 'b111111;
|
|
reg [0:31] SD;
|
|
|
|
old_clk <= I2C_CLOCK;
|
|
old_st <= START;
|
|
|
|
// delay to make sure SDA changed while SCL is stabilized at low
|
|
if(old_clk && ~I2C_CLOCK && ~SD_COUNTER[5]) SDO[0] <= SD[SD_COUNTER[4:0]];
|
|
SDO[3:1] <= SDO[2:0];
|
|
|
|
if(~old_st && START) begin
|
|
SCLK <= 1;
|
|
SDO <= 4'b1111;
|
|
ACK <= 0;
|
|
END <= 0;
|
|
rd <= READ;
|
|
len <= I2C_WLEN;
|
|
if(READ) SD <= {2'b10, I2C_ADDR, 1'b1, 1'b1, 8'b11111111, 1'b0, 3'b011, 9'b111111111};
|
|
else SD <= {2'b10, I2C_ADDR, 1'b0, 1'b1, I2C_WDATA1, 1'b1, I2C_WDATA2, 4'b1011};
|
|
SD_COUNTER <= 0;
|
|
end else begin
|
|
if(~old_clk && I2C_CLOCK && ~&SD_COUNTER) begin
|
|
SD_COUNTER <= SD_COUNTER + 6'd1;
|
|
case(SD_COUNTER)
|
|
01: SCLK <= 0;
|
|
10: ACK <= ACK | I2C_SDA;
|
|
19: if(~rd) begin
|
|
ACK <= ACK | I2C_SDA;
|
|
if(~len) SD_COUNTER <= 29;
|
|
end
|
|
20: if(rd) SCLK <= 1;
|
|
23: if(rd) END <= 1;
|
|
28: if(~rd) ACK <= ACK | I2C_SDA;
|
|
29: if(~rd) SCLK <= 1;
|
|
32: if(~rd) END <= 1;
|
|
endcase
|
|
|
|
if(SD_COUNTER >= 11 && SD_COUNTER <= 18) rdata[SD_COUNTER[4:0]-11] <= I2C_SDA;
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule
|