本文先简单介绍一下I2C总线协议,然后给出一个可以用于Verification的verilog model。

1.I2C协议
   2条双向串行线,一条数据线SDA,一条时钟线SCL。

   SDA传输数据是大端传输,每次传输8bit,即一字节。
   支持多主控(multimastering),任何时间点只能有一个主控。
   总线上每个设备都有自己的一个addr,共7个bit,广播地址全0。
   系统中可能有多个同种芯片,为此addr分为固定部分和可编程部份,细节视芯片而定,看datasheet。

1.1 I2C位传输
   数据传输:SCL为高电平时,SDA线若保持稳定,那么SDA上是在传输数据bit。
   若SDA发生跳变,则用来表示一个会话的开始或结束(后面讲)。
   数据改变:SCL为低电平时,SDA线才能改变传输的bit。

I2C总线协议之可以用于验证的verilog model

1.2 I2C开始和结束信号
   开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
   结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。

I2C总线协议之可以用于验证的verilog model

 

1.3 I2C应答信号

   Master每发送完8bit数据后等待Slave的ACK。
   即在第9个clock,若从IC发ACK,SDA会被拉低。
   若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程。

I2C总线协议之可以用于验证的verilog model

1.4 I2C写流程
写寄存器的标准流程为:
1.    Master发起START
2.    Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
3.    Slave发送ACK
4.    Master发送reg addr(8bit),等待ACK
5.    Slave发送ACK
6.    Master发送data(8bit),即要写入寄存器中的数据,等待ACK
7.    Slave发送ACK
8.    第6步和第7步可以重复多次,即顺序写多个寄存器
9.    Master发起STOP

写一个寄存器

I2C总线协议之可以用于验证的verilog model

写多个寄存器

I2C总线协议之可以用于验证的verilog model

1.5 I2C读流程
读寄存器的标准流程为:
1.    Master发送I2C addr(7bit)和w操作1(1bit),等待ACK
2.    Slave发送ACK
3.    Master发送reg addr(8bit),等待ACK
4.    Slave发送ACK
5.    Master发起START
6.    Master发送I2C addr(7bit)和r操作1(1bit),等待ACK
7.    Slave发送ACK
8.    Slave发送data(8bit),即寄存器里的值
9.    Master发送ACK
10.    第8步和第9步可以重复多次,即顺序读多个寄存器

读一个寄存器

I2C总线协议之可以用于验证的verilog model

读多个寄存器

I2C总线协议之可以用于验证的verilog model

 

2.I2C master的verilog model

  1 module i2c_master_model (scl, sda);
2 inout scl;
3 inout sda;
4
5 parameter slave_addr_reg = 7'b0110101; //slave addr
6 int i;
7 reg R_scl = 1'bz;
8 reg R_sda = 1'bz;
9
10 reg clk = 0;
11 always #(1329.1125) clk = !clk;
12
13 assign scl = R_scl;
14 assign sda = R_sda;
15
16 task start; //start condition
17 @(posedge clk);
18 R_sda = 1;
19 R_scl = 1;
20 @(posedge clk);
21 R_sda = 0;
22 @(posedge clk);
23 R_scl = 0;
24 endtask
25
26 task stop; //stop condition
27 R_sda = 0;
28 @(posedge clk);
29 R_scl = 1;
30 @(posedge clk);
31 R_sda = 1;
32 @(posedge clk);
33 R_scl = 1'bz;
34 @(posedge clk);
35 @(posedge clk);
36 R_sda = 1'bz;
37 endtask
38
39 task rw_slave_addr(input [6:0] slave_addr, input rw);
40 for(i=6; i>=0; i--) begin
41 @(posedge clk);
42 R_sda = slave_addr[i];
43 @(posedge clk);
44 R_scl = 1;
45 @(posedge clk);
46 @(posedge clk);
47 R_scl = 0;
48 end
49 @(posedge clk);
50 R_sda = rw;
51 @(posedge clk);
52 R_scl = 1;
53 @(posedge clk);
54 @(posedge clk);
55 R_scl = 0;
56 @(posedge clk);
57 R_sda = 1'bz;
58 @(posedge clk);
59 R_scl = 1;
60 if(sda != 0) $display("ACK error at time: %t", $time);
61 @(posedge clk);
62 @(posedge clk);
63 R_scl = 0;
64 @(posedge clk);
65 endtask
66
67 task send_byte(input [7:0] send_byte);
68 for(i=7; i>=0; i--) begin
69 R_sda = send_byte[i];
70 @(posedge clk);
71 R_scl = 1;
72 @(posedge clk);
73 @(posedge clk);
74 R_scl = 0;
75 @(posedge clk);
76 end
77 R_sda = 1'bz;
78 @(posedge clk);
79 R_scl = 1'b1;
80 if(sda != 0) $display("ACK error at time: %t", $time);
81 @(posedge clk);
82 @(posedge clk);
83 R_scl = 0;
84 @(posedge clk);
85 endtask
86
87 task recv_byte(output [7:0] recv_dat);
88 for(i+7; i>=0; i--) begin
89 @(posedge clk);
90 R_scl = 1;
91 recv_dat[i] = sda;
92 @(posedge clk);
93 @(posedge clk);
94 R_scl = 0;
95 @(posedge clk);
96 end
97 R_sda = 1'b0; //send ACK
98 @(posedge clk);
99 R_scl = 1;
100 @(posedge clk);
101 @(posedge clk);
102 R_scl = 0;
103 @(posedge clk);
104 R_sda = 1'bz;
105 endtask
106
107 task recv_byte_noack(output [7:0] recv_dat);
108 for(i+7; i>=0; i--) begin
109 @(posedge clk);
110 R_scl = 1;
111 recv_dat[i] = sda;
112 @(posedge clk);
113 @(posedge clk);
114 R_scl = 0;
115 @(posedge clk);
116 end
117 R_sda = 1'b1; //send NOACK
118 @(posedge clk);
119 R_scl = 1;
120 @(posedge clk);
121 @(posedge clk);
122 R_scl = 0;
123 @(posedge clk);
124 R_sda = 1'bz;
125 endtask
126
127 task write_reg(input [7:0]addr, input [7:0] dat);
128 start;
129 rw_slave_addr(slave_addr_reg, 0);
130 send_byte(addr);
131 send_byte(dat);
132 stop;
133 endtask
134
135 task read_reg(input [7:0] addr, output [7:0] recv_dat);
136 start;
137 rw_slave_addr(slave_addr_reg, 0);
138 send_byte(addr);
139 start;
140 rw_slave_addr(slave_addr_reg, 1);
141 recv_byte_noack(recv_dat);
142 stop;
143 endtask
144
145 task write_reg_2byte(input [7:0]addr, input [15:0] dat);
146 start;
147 rw_slave_addr(slave_addr_reg, 0);
148 send_byte(addr);
149 send_byte(dat[15:8]);
150 send_byte(dat[7:0]);
151 stop;
152 endtask
153
154 task read_reg_2byte(input [7:0] addr, output [15:0] recv_dat);
155 start;
156 rw_slave_addr(slave_addr_reg, 0);
157 send_byte(addr);
158 start;
159 rw_slave_addr(slave_addr_reg, 1);
160 recv_byte_noack(recv_dat[15:8]);
161 recv_byte_noack(recv_dat[7:0]);
162 stop;
163 endtask



相关文章:

  • 2021-10-12
  • 2021-12-17
  • 2022-12-23
  • 2022-03-05
  • 2021-12-20
  • 2021-11-09
  • 2021-05-25
猜你喜欢
  • 2021-04-08
  • 2021-10-26
  • 2021-10-14
  • 2021-08-17
相关资源
相似解决方案