MacPlus_MiSTer/sys/i2c.v

97 lines
2.1 KiB
Coq
Raw Normal View History

2017-10-22 01:22:56 +00:00
2018-03-05 17:40:43 +00:00
module i2c
2017-10-22 01:22:56 +00:00
(
input CLK,
input START,
2019-09-27 17:11:21 +00:00
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,
2017-10-22 01:22:56 +00:00
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
2019-09-27 17:11:21 +00:00
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;
2017-10-22 01:22:56 +00:00
end
end
assign I2C_SCL = SCLK | I2C_CLOCK;
2019-09-27 17:11:21 +00:00
assign I2C_SDA = SDO[3] ? 1'bz : 1'b0;
2017-10-22 01:22:56 +00:00
2019-09-27 17:11:21 +00:00
reg SCLK = 1;
reg [3:0] SDO = 4'b1111;
reg [0:7] rdata;
assign I2C_RDATA = rdata;
2017-10-22 01:22:56 +00:00
always @(posedge CLK) begin
reg old_clk;
reg old_st;
2019-09-27 17:11:21 +00:00
reg rd,len;
2017-10-22 01:22:56 +00:00
reg [5:0] SD_COUNTER = 'b111111;
reg [0:31] SD;
old_clk <= I2C_CLOCK;
old_st <= START;
2019-09-27 17:11:21 +00:00
// 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];
2017-10-22 01:22:56 +00:00
if(~old_st && START) begin
SCLK <= 1;
2019-09-27 17:11:21 +00:00
SDO <= 4'b1111;
2017-10-22 01:22:56 +00:00
ACK <= 0;
END <= 0;
2019-09-27 17:11:21 +00:00
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};
2017-10-22 01:22:56 +00:00
SD_COUNTER <= 0;
end else begin
if(~old_clk && I2C_CLOCK && ~&SD_COUNTER) begin
SD_COUNTER <= SD_COUNTER + 6'd1;
case(SD_COUNTER)
2019-09-27 17:11:21 +00:00
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;
2017-10-22 01:22:56 +00:00
endcase
2019-09-27 17:11:21 +00:00
if(SD_COUNTER >= 11 && SD_COUNTER <= 18) rdata[SD_COUNTER[4:0]-11] <= I2C_SDA;
end
2017-10-22 01:22:56 +00:00
end
end
endmodule