基于FPGA的I2C verilog

游戏排行榜

空闲位:SCL 高电平 SDA低电平

起始位 :SCL 高电平  SDA 高电平到低电平

结束位:SCL 高电平 SDA低电平到高电平

读写状态:数据+响应位

`timescale 1ns/1ns


module IIC_WM(
Clk,
Rst_n,

IIC_SCL,   //iic时钟线
IIC_SDA     //iic数据总线
);


input Clk;//系统时钟
input Rst_n;//复位

output reg IIC_SCL;//IIC  时钟
inout IIC_SDA;//IIC数据

reg OE;
reg [15:0]cnt;
reg [15:0]IIC_cnt,IIC_cnt_r;
reg [15:0]data_cnt,data_cnt_r;//IIC_cnt 每计数到30,data_cnt加一,IIC_cnt_r计数到30,data_cnt_r加1

wire [7:0]addr;
wire [7:0]data;
reg done;//每当传输完一帧数据30位,done设置为1
reg total_done;//传输完8帧数据置1
reg [3:0]done_cnt;//每次来一个done加1
reg IIC_SDA_tmp;
reg [2:0]ACK;

assign IIC_SDA = OE?IIC_SDA_tmp:1'hz; //oe为1时SDA为输出

parameter CNT_MAX = 124;  

[email protected](posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt <=#1 0;
else if(cnt == CNT_MAX)
cnt <=#1 0;
else if(total_done)
cnt <= #1 0;
else 
cnt <=#1 cnt + 1'b1;


//200k  IIC_SCL 时钟
[email protected](posedge Clk or negedge Rst_n)
if(!Rst_n)
IIC_SCL <=#1 0;
else if(cnt == CNT_MAX)
IIC_SCL <=#1 ~IIC_SCL;
else 
IIC_SCL <=#1 IIC_SCL;


//200k时钟高低电平各有一个计数器

//IIC_cnt 高电平计数

[email protected](posedge Clk)

if(!IIC_SCL)
IIC_cnt <=#1 IIC_cnt + 1'b1;
else 
IIC_cnt <=#1 0;
//IIC_cnt_r 低电平计数
[email protected](posedge Clk)
if(IIC_SCL)
begin
if(total_done)
IIC_cnt_r <=#1 0;
else 
IIC_cnt_r <=#1 IIC_cnt_r + 1'b1;
end 
else 
IIC_cnt_r <=#1 0;


//传完一次数据done_cnt加1
[email protected](posedge Clk or negedge Rst_n)
if(!Rst_n)
done_cnt <=#1 0;
else if(done)
done_cnt <=#1 done_cnt + 1'b1;
else 
done_cnt <=#1 done_cnt;
//
[email protected](posedge Clk or negedge Rst_n)
if(!Rst_n)
total_done <=#1 0;
else if(done_cnt == 8)
total_done <=#1 1;
else 
total_done <=#1 total_done;

//两个计数器,400K时钟高电平为data_cnt_r,低电平data_cnt
//IIC_cnt 每计数到30,data_cnt加一
[email protected](posedge Clk or negedge Rst_n)
if(!Rst_n)
data_cnt <=#1 0;
else if(!total_done)
begin 
if(IIC_cnt == 30)
data_cnt <=#1 data_cnt + 1'b1;
else if(done)
data_cnt <=#1 0;
else 
data_cnt <=#1 data_cnt;
end
else 
data_cnt <=#1 0;
//IIC_cnt_r计数到30,data_cnt_r加1
[email protected](posedge Clk or negedge Rst_n)
if(!Rst_n)
data_cnt_r <=#1 0;
else if(!total_done)
begin 
if(IIC_cnt_r == 30)
data_cnt_r <=#1 data_cnt_r + 1'b1;
else if(data_cnt_r == 30)
data_cnt_r <=#1 0;
else if(done)
data_cnt_r <=#1 0;
else 
data_cnt_r <=#1 data_cnt_r;
end
else 
data_cnt_r <=#1 0;

[email protected](posedge Clk or negedge Rst_n)
if(!Rst_n)
begin 
OE <=#1 1;IIC_SDA_tmp <=#1 1;ACK <=#1 3'b111;
end 
else if(data_cnt_r == 1)//起始位
IIC_SDA_tmp <=#1 0;
else if(data_cnt_r == 29)//结束位
IIC_SDA_tmp <=#1 1;
else if(done)
ACK <=#1 3'b111;
else begin 

case(data_cnt)

//器件地址设置

// 1:IIC_SDA_tmp <=#1 0;
2:IIC_SDA_tmp <=#1 0;
3:IIC_SDA_tmp <=#1 0;
4:IIC_SDA_tmp <=#1 1;
5:IIC_SDA_tmp <=#1 1;
6:IIC_SDA_tmp <=#1 0;
7:IIC_SDA_tmp <=#1 1;
8:IIC_SDA_tmp <=#1 0;
9:IIC_SDA_tmp <=#1 0;
10:begin 
OE <=#1 0;IIC_SDA_tmp <=#1 0;
if(IIC_SDA == 0)
ACK[2] <=#1 IIC_SDA;

end

//器件寄存器地址设置

11:begin IIC_SDA_tmp <=#1 addr[7];OE<=#1 1;end 
12:IIC_SDA_tmp <=#1 addr[6];
13:IIC_SDA_tmp <=#1 addr[5];
14:IIC_SDA_tmp <=#1 addr[4];
15:IIC_SDA_tmp <=#1 addr[3];
16:IIC_SDA_tmp <=#1 addr[2];
17:IIC_SDA_tmp <=#1 addr[1];
18:IIC_SDA_tmp <=#1 addr[0];
19:begin 
OE <=#1 0;IIC_SDA_tmp <=#1 0;
if(IIC_SDA == 0)
ACK[1] <=#1 IIC_SDA;

end

//器件数据读取

20:begin IIC_SDA_tmp <=#1 data[7];OE<=#1 1;end 
21:IIC_SDA_tmp <=#1 data[6];
22:IIC_SDA_tmp <=#1 data[5];
23:IIC_SDA_tmp <=#1 data[4];
24:IIC_SDA_tmp <=#1 data[3];
25:IIC_SDA_tmp <=#1 data[2];
26:IIC_SDA_tmp <=#1 data[1];
27:IIC_SDA_tmp <=#1 data[0];
28:begin 
OE <=#1 0;IIC_SDA_tmp <=#1 0;
if(IIC_SDA == 0)
ACK[0] <=#1 IIC_SDA;
end
// 29:begin IIC_SDA_tmp <=#1 1;OE<=#1 1;end 
default: begin IIC_SDA_tmp <=#1 IIC_SDA_tmp;OE<=#1 1;ACK <=#1 ACK;end 
endcase
end 

[email protected](posedge Clk)
if((ACK == 3'd0)&&(data_cnt_r == 30))
done <=#1 1;
else 
done <=#1 0;


WM8731 WM8731(
.Clk(Clk),
.Rst_n(Rst_n),
.done(done),

.addr(addr),
.data(data)
);

endmodule