一、IIC基本概念
IIC 总线(I2C bus, Inter-IC bus)是一个双向的两线连续总线,提供集成电路(ICs)之间的通信线路。IIC总线是一种串行扩展技术,最早由Philips公司推出,广泛应用于电视,录像机和音频设备,IIC 总线的意思是“完成集成电路或功能单元之间信息交换的规范或协议”。 Philips 公司推出的 IIC 总线采用一条数据线(SDA),加一条时钟线(SCL)来完成数据的传输及外围器件的扩展。 如图1所示:
图1
二、主机和从机的概念
主机就是负责整个系统的任务协调与分配,从机一般是通过接收主机的指令从而完成某些特定的任务,主机和从机之间通过总线连接,进行数据通讯。
三、传输速率
IIC 总线数据传输速率在标准模式下可达 100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s。IIC总线上的主设备与从设备之间以字节(8位)为单位进行双向的数据传输,IIC协议为半双工协议。
四、器件地址的概念
每个 IIC 器件都有一个器件地址,有的器件地址在出厂时地址就设置好了,用户不可以更改(例如 OV7670 器件地址为固定的 0x42),有的确定了几位,剩下几位由硬件确定(比如常见的 IIC 接口的 EEPROM 存储器,留有 3 个控制地 址的引脚,由用户自己在硬件设计时确定)。
五、总体时序简介
图2
在IIC器件开始通信(传输数据)之前,串行时钟线SCL和串行数据线SDA线由于上拉的原 因处于高电平状态,此时IIC总线处于空闲状态。如果主机(此处指FPGA)想开始传输数据,只需在SCL为高电平时将SDA线拉低,产生一个起始信号,从机检测到起始信号后,准备接收数 据,当数据传输完成,主机只需产生一个停止信号,告诉从机数据传输结束,停止信号的产生 是在SCL为高电平时, SDA从低电平跳变到高电平,从机检测到停止信号后,停止接收数据。 IiC 整体时序如图2所示,起始信号之前为空闲状态,起始信号之后到停止信号之前的这一段为数据传 输状态,主机可以向从机写数据, 也可以读取从机输出的数据,数据的传输由双向数据线( SDA) 完成。停止信号产生后,总线再次处于空闲状态。
由于IIC总线协议启动和停止信号都是在SCL高电平期间发生跳变的(当不发送或接收数据时,SCL一直处于高电平),这就决定了我们其他数据的改变只能发生在SCL低电平期间,在SCL为高电平期间,数据必须保持稳定。即在SCL低电平时改变数据,在SCL高电平时采集数据。
六、三态电路设计
主机(FPGA)给从机发送信号时,如传输启动信号,停止信号,数据位时,sda为输出;从机给主机发送信号,如ACK,读取数据时,sda充当输入,如图3所示;
图3
七、单字节写时序
图4 单字节写时序
由时序图可以看出,如果要向EEPROM 24C64中写入1字节,那么必须经过以下步骤。
(1)发送启动信号;
(2)发送器件地址(CONTROL BYTE);
(3)接收并检测EEPROM发送过来的应答信号(ACK);
(4)发送高字节地址位(ADDRESS HIGH BYTE);
(5)接收并检测EEPROM发送过来的应答信号(ACK);
(6)发送低字节地址位(ADDRESS LOW BYTE);
(7)接收并检测EEPROM发送过来的应答信号(ACK);
(8)发送8bit有效数据(DATA);
(9)接收并检测EEPROM发送过来的应答信号(ACK);
(10)发送停止信号(STOP);
八、单字节读时序
图5 单字节读时序
由时序图可以看出,如果要向EEPROM 24C64中读出1字节,那么必须经过以下步骤。
(1)发送启动信号;
(2)发送器件地址1010_0000(CONTROL BYTE);
(3)接收并检测EEPROM发送过来的应答信号(ACK);
(4)发送高字节地址位(ADDRESS HIGH BYTE);
(5)接收并检测EEPROM发送过来的应答信号(ACK);
(6)发送低字节地址位(ADDRESS LOW BYTE);
(7)接收并检测EEPROM发送过来的应答信号(ACK);
(8)发送启动信号;
(9)发送器件地址1010_0001(CONTROL BYTE);
(10)接收并检测EEPROM发送过来的应答信号(ACK);
(11)读取1字节的数据(DATA);
(12)发送NO_ACK信号;
(13)发送停止信号(STOP);
九、时序设计
(1)启动信号:在SCL为高电平期间,sda出现从高到低的跳变沿,代表启动信号;
(2)器件地址:EEPROM 24C64 的写时序时的器件地址为:8'b1010_0000,读时序时的器件地址为:8'b1010_0001;
(3)高、低位的字地址:由于24C64有64bit的存储空间,所以我们需要13位的地址位宽才能寻址所有的存储空间,由于IIC协议规定只能以字节形式写入,所以必须将13位的地址扩展为16位的地址,分为高8位和低8位,多出来的前三位填充任意数据即可。
(4)停止信号:在SCL为高电平期间,sda出现从低到高的跳变沿,代表停止信号;
(5)应答信号:应答信号是由数据接收方发出的,当SCL为高电平期间,如果监测到SDA为低电平,则说明有应答信号;
(6)非应答信号:非应答信号也是由数据接收方发出的,当SCL为高电平时,如果SDA为高电平,则说明有非应答信号;
九、代码设计(代码还未上板验证)
功能描述:按键读写EEPROM 24C64
1 module iic_test(
2 clk,
3 rst_n,
4
5 scl,
6 sda,
7
8 key_rd,
9 key_wr,
10
11 //data_in,
12 data_out
13 );
14
15 input clk;
16 input rst_n;
17
18 input key_rd;
19 input key_wr;
20 //input[7:0] data_in;
21
22 output scl;
23 output reg[7:0] data_out;
24
25 inout sda;
26
27 wire flag;
28 reg sda_buffer;
29 reg scl_r;
30
31 reg[11:0] current_state,next_state;
32
33 parameter W_IDLE = 12'd0;
34 parameter W_START = 12'd1;
35 parameter W_DEVICE_ADD = 12'd2;
36 parameter W_ACK1 = 12'd3;
37 parameter W_WORD_H_ADD = 12'd4;
38 parameter W_ACK2 = 12'd5;
39 parameter W_WORD_L_ADD = 12'd6;
40 parameter W_ACK3 = 12'd7;
41 parameter W_DATA = 12'd8;
42 parameter W_ACK4 = 12'd9;
43 parameter W_STOP = 12'd10;
44
45 parameter R_START = 12'd11;
46 parameter R_DEVICE_ADD = 12'd12;
47 parameter R_ACK1 = 12'd13;
48 parameter R_DATA = 12'd14;
49 parameter R_NO_ACK = 12'd15;
50 parameter R_STOP = 12'd16;
51
52 reg[1:0] en;
53 always@(posedge clk or negedge rst_n) // en信号设计
54 if(!rst_n)
55 en <= 2'b00;
56 else begin
57 if(!key_wr)
58 en <= 2'b01;
59 else begin
60 if(!key_rd)
61 en <= 2'b10;
62 end
63 end
64
65 parameter SYS_CLOCK = 50_000_000;
66 parameter SCL_CLOCK = 400_000;
67 localparam SCL_CNT_M = SYS_CLOCK/SCL_CLOCK;
68
69 reg[11:0] cnt;
70 always@(posedge clk or negedge rst_n) begin
71 if(!rst_n)
72 cnt <= 12'd0;
73 else if(cnt == SCL_CNT_M - 1)
74 cnt <= 12'd0;
75 else
76 cnt <= cnt + 1'b1;
77 end
78
79 always@(posedge clk or negedge rst_n) begin
80 if(!rst_n)
81 scl_r <= 1'b1;
82 else if(cnt == SCL_CNT_M >> 1)
83 scl_r <= 1'b0;
84 else if(cnt == 12'd0)
85 scl_r <= 1'b1;
86 else
87 scl_r <= scl_r;
88 end
89
90 wire scl_l;
91 wire scl_h;
92 assign scl_h = (cnt == SCL_CNT_M >> 2) ? 1'b1 : 1'b0; // scl 高电平的中间
93
94 assign scl_l = (cnt == (SCL_CNT_M >> 1) + (SCL_CNT_M >> 2)) ? 1'b1 : 1'b0; // scl低电平的中间
95
96 reg[4:0] count;
97 reg[7:0] memory;
98 always@(posedge clk or negedge rst_n) // 同步时序,次态寄存器迁移到现态寄存器
99 if(!rst_n)
100 current_state <= W_IDLE;
101 else if(scl_l)
102 current_state <= next_state;
103
104 always@(*) begin // 状态转移条件判断
105 next_state = W_IDLE;
106 case(current_state)
107 W_IDLE:begin
108 if(en != 2'b00)
109 next_state = W_START;
110 else
111 next_state = W_IDLE;
112 end
113
114 W_START:begin
115 if(scl_l)
116 next_state = W_DEVICE_ADD;
117 else
118 next_state = W_START;
119 end
120
121 W_DEVICE_ADD:begin
122 if((count == 5'd8) && (scl_l))
123 next_state = W_ACK1;
124 else
125 next_state = W_DEVICE_ADD;
126 end
127
128 W_ACK1:begin
129 if(scl_l)
130 next_state = W_WORD_H_ADD;
131 else
132 next_state = W_ACK1;
133 end
134
135 W_WORD_H_ADD:begin
136 if((count == 5'd8) && (scl_l))
137 next_state = W_ACK2;
138 else
139 next_state = W_WORD_H_ADD;
140 end
141
142 W_ACK2:begin
143 if(scl_l)
144 next_state = W_WORD_L_ADD;
145 else
146 next_state = W_ACK2;
147 end
148
149 W_WORD_L_ADD:begin
150 if((count == 5'd8) && (scl_l))
151 next_state = W_ACK3;
152 else
153 next_state = W_WORD_L_ADD;
154 end
155
156 W_ACK3:begin
157 if(scl_l) begin
158 if(en == 2'b01)
159 next_state = W_DATA;
160 else if(en == 2'b10)
161 next_state = R_START;
162 end
163 else
164 next_state = W_ACK3;
165 end
166
167 W_DATA:begin
168 if((count == 5'd8) && (scl_l))
169 next_state = W_ACK4;
170 else
171 next_state = W_DATA;
172 end
173
174 W_ACK4:begin
175 if(scl_l)
176 next_state = W_STOP;
177 else
178 next_state = W_ACK4;
179 end
180
181 W_STOP:begin
182 if(scl_l)
183 next_state = W_IDLE;
184 else
185 next_state = W_STOP;
186 end
187
188 R_START:begin
189 if(scl_l)
190 next_state = R_DEVICE_ADD;
191 else
192 next_state = R_START;
193 end
194
195 R_DEVICE_ADD:begin
196 if((count == 5'd8) && (scl_l))
197 next_state = R_ACK1;
198 else
199 next_state = R_DEVICE_ADD;
200 end
201
202 R_ACK1:begin
203 if(scl_l)
204 next_state = R_DATA;
205 else
206 next_state = R_ACK1;
207 end
208
209 R_DATA:begin
210 if((count == 5'd8) && (scl_l))
211 next_state = R_NO_ACK;
212 else
213 next_state = R_DATA;
214 end
215
216 R_NO_ACK:begin
217 if(scl_l)
218 next_state = R_STOP;
219 else
220 next_state = R_NO_ACK;
221 end
222
223 R_STOP:begin
224 if(scl_l)
225 next_state = W_IDLE;
226 else
227 next_state = R_STOP;
228 end
229
230 default:next_state = W_IDLE;
231 endcase
232 end
233
234 always@(posedge clk or negedge rst_n) // 状态输出
235 if(!rst_n) begin
236 sda_buffer <= 1'b1;
237 count <= 5'd0;
238 //data_out <= 8'b00000000;
239 memory <= 8'b00000000;
240 end
241 else if(scl_l) begin
242 case(next_state)
243 W_IDLE:begin
244 sda_buffer <= 1'b1;
245 end
246
247 W_START:begin
248 sda_buffer <= 1'b0; //起始位
249 count <= 5'd0;
250 memory <= 8'b10100000; // 写器件地址
251 end
252
253 W_DEVICE_ADD:begin
254 count <= count + 1'b1;
255 sda_buffer <= memory[3'd7 - count];
256 end
257
258 W_ACK1:begin
259 count <= 5'd0;
260 memory <= 8'b00000000; // 高八位字地址
261 end
262
263 W_WORD_H_ADD:begin
264 count <= count + 1'b1;
265 sda_buffer <= memory[3'd7 - count];
266 end
267
268 W_ACK2:begin
269 count <= 5'd0;
270 memory <= 8'b01010011; // 低八位的字地址
271 end
272
273 W_WORD_L_ADD:begin
274 count <= count + 1'b1;
275 sda_buffer <= memory[3'd7 - count];
276 end
277
278 W_ACK3:begin
279 count <= 5'd0;
280 memory <= 8'b11110000; // 写数据
281 end
282
283 W_DATA:begin
284 count <= count + 1'b1;
285 sda_buffer <= memory[3'd7 - count];
286 end
287
288 W_ACK4:begin
289 count <= 5'd0;
290 end
291
292 W_STOP:begin
293 sda_buffer <= 1'b1;
294 end
295
296 R_START:begin
297 sda_buffer <= 1'b0;
298 memory <= 8'b10100001; // 读器件地址
299 count <= 5'd0;
300 end
301
302 R_DEVICE_ADD:begin
303 count <= count + 1'b1;
304 sda_buffer <= memory[3'd7 - count];
305 end
306
307 R_ACK1:begin
308 count <= 5'd0;
309 end
310
311 R_DATA:begin
312 count <= count + 1'b1;
313 //data_out <= {data_out[6:0],sda}; //memory[5'd7 - count] <= sda; // data_out[5'd7 - count] <= sda; data_out[5'd7 - count] <= sda;
314 end
315
316 R_NO_ACK:begin
317 sda_buffer <= 1'b1;
318 end
319
320 R_STOP:begin
321 sda_buffer <= 1'b0;
322 end
323
324 default:begin
325 count <= 5'd0;
326 sda_buffer <= 1'b1;
327 memory <= 8'b00000000;
328 end
329 endcase
330 end
331 else begin
332 sda_buffer <= sda_buffer;
333 count <= count;
334 end
335
336 always@(posedge clk or negedge rst_n)
337 if(!rst_n)
338 data_out <= 8'b00000000;
339 else if(scl_h) begin
340 case(next_state)
341 R_DATA:data_out[3'd7 - count] <= sda;
342 default:;
343 endcase
344 end
345 else
346 data_out <= data_out;
347
348 assign scl = ((current_state >= W_DEVICE_ADD && current_state <= W_ACK4) ||
349 (current_state >= R_DEVICE_ADD && current_state <= R_NO_ACK)) ? scl_r : 1'b1;
350
351 assign flag =((current_state == W_ACK1)||
352 (current_state == W_ACK2) ||
353 (current_state == W_ACK3) ||
354 (current_state == W_ACK4) ||
355 (current_state == R_ACK1) ||
356 (current_state == R_DATA)
357
358 ) ? 1'b0 : 1'b1;
359
360 assign sda = flag ? sda_buffer : 1'bz;
361
362 endmodule
测试代码
1 `timescale 1s/1ps
2 module iic_test_tb;
3 reg clk;
4 reg rst_n;
5
6 reg key_rd; // 低电平有效
7 reg key_wr; // 低电平有效
8
9 wire[7:0] data_out;
10 wire scl;
11 wire sda;
12
13 iic_test u0(
14 .clk(clk),
15 .rst_n(rst_n),
16
17 .scl(scl),
18 .sda(sda),
19
20 .key_wr(key_wr),
21 .key_rd(key_rd),
22 .data_out(data_out)
23 );
24
25 initial
26 clk = 1'b0;
27 always #10 clk = ~clk;
28
29 initial
30 begin
31 rst_n = 1'b0;
32 key_rd = 1'b1;
33 key_wr = 1'b1;
34 #1000;
35 rst_n = 1'b1;
36
37 #800;
38 #8000 key_wr = 1'b0;
39 #40000;
40 key_wr = 1'b1;
41
42 #1000000;
43 key_rd = 0;
44 #40000;
45 key_rd = 1'b1;
46
47 #1000000;
48 $stop;
49 end
50 endmodule
51
52
仿真结果
(1)写时序
写时序存在的一些问题,在停止信号上没有完全符合在SCL的高电平时,sda由0变为1。解决办法是在停止信号之前,再加一个状态,在这个状态中,令scl处于低电平的中间时,sda_buffer为0,这样在停止信号时,就可以由0变1.
(2)读时序
读时序也存在一些问题,停止信号出现了和写时序时同样的问题,没有完全符合预期,数据接收部分全为高阻状态。
注:
(1)文字叙述方面参考了小梅哥,正点原子,至芯科技的相关文章;
(2)代码设计参考了小梅哥,CrazyBingo的设计思路;
下面的代码为至芯科技的源码(最初的代码无法仿真成功,下面是我做了小小修改的代码)
1 // Time : 2020.03.19 22:59 2 // Describe : iic_driver 3 module iic_driver( 4 clk, 5 rst_n, 6 7 iic_scl, 8 iic_sda, 9 10 key_wr, 11 key_rd, 12 13 data_in, 14 data_out 15 ); 16 17 input clk; 18 input rst_n; 19 20 input key_rd; 21 input key_wr; 22 23 input[7:0] data_in; 24 25 inout iic_sda; 26 27 output reg iic_scl; 28 output reg[7:0] data_out; 29 30 reg[7:0] sda_buffer; 31 reg flag; 32 33 assign iic_sda = (flag) ? sda_buffer : 1'bz; 34 35 reg[7:0] count; 36 reg clk_sys; 37 38 always@(posedge clk or negedge rst_n) // 分频为800KHz的时钟 39 if(!rst_n) begin 40 clk_sys <= 1'b0; 41 count <= 8'd0; 42 end 43 else begin 44 if(count < 31) 45 count <= count + 1'b1; 46 else begin 47 count <= 8'd0; 48 clk_sys <= ~clk_sys; 49 end 50 end 51 52 reg[5:0] state; // 状态寄存器 53 54 always@(posedge clk_sys or negedge rst_n) // iic_scl设计 55 if(!rst_n) 56 iic_scl <= 1'b1; 57 else begin 58 if(state > 0) // 当总线忙的时候,iic_scl为近400kHz的时钟 59 iic_scl <= ~iic_scl; 60 else 61 iic_scl <= 1'b1; // 空闲时为高电平 62 end 63 64 reg[1:0] en; 65 always@(posedge clk or negedge rst_n) // en信号设计 66 if(!rst_n) 67 en <= 2'b00; 68 else begin 69 if(!key_wr) 70 en <= 2'b01; 71 else begin 72 if(!key_rd) 73 en <= 2'b10; 74 end 75 end 76 77 reg[3:0] cnt; // 发送或接收数据的个数 78 reg[1:0] temp; // 读/写使能中间寄存器 79 reg[7:0] memory; // 发送或接收数据的中间寄存器 80 81 always@(posedge clk_sys or negedge rst_n) 82 if(!rst_n) begin 83 data_out <= 8'd0; 84 flag <= 1'b1; //复位时,系统获得总线的控制权,作为输出端口 85 sda_buffer <= 1'b1; //向 iic_scl 发送高电平 86 state <= 0; 87 temp <= 2'b0; 88 end 89 else 90 case(state) 91 0:begin 92 if(iic_scl) begin 93 if(en != temp) begin // 有按键按下 94 sda_buffer <= 1'b0; // 发送启动信号 95 state <= 1; 96 temp <= en; 97 cnt <= 0; 98 memory <= 8'b10100000; 99 end 100 else 101 state <= 0; 102 end 103 else 104 state <= 0; 105 end 106 107 1:begin 108 if((iic_scl == 0) && (cnt < 8)) begin // 发送8位控制字,器件地址 109 sda_buffer <= memory[7]; 110 cnt <= cnt + 1'b1; 111 memory <= {memory[6:0],memory[7]}; 112 state <= 1; 113 end 114 else begin 115 if((iic_scl == 0) && (cnt == 8)) begin 116 cnt <= 0; 117 flag <= 0; // 释放总线控制权 118 state <= 2; 119 end 120 else 121 state <= 1; 122 end 123 end 124 125 2:begin 126 if(!iic_scl) begin // 检测应答信号 127 state <= 3; 128 memory <= 8'd0; // 高字节地址 129 end 130 else 131 state <= 2; 132 end 133 134 3:begin // 发送高字节地址 135 if((iic_scl == 0) && (cnt < 8 )) begin 136 flag <= 1'b1; // 系统获得总线控制权 137 sda_buffer <= memory[7]; 138 cnt <= cnt + 1'b1; 139 memory ={memory[6:0],memory[7]}; 140 state <= 3; 141 end 142 else begin 143 if((iic_scl == 0) && (cnt == 8)) begin 144 cnt <= 0; 145 flag <= 0; // 释放总线控制权 146 state <= 4; 147 end 148 else 149 state <= 3; 150 end 151 end 152 153 4:begin 154 if(!iic_scl) begin // 检测应答信号 155 state <= 5; 156 memory <= 8'b00110101; // 低字节地址 157 end 158 else begin 159 state <= 4; 160 end 161 end 162 163 5:begin 164 if((iic_scl == 0) && (cnt < 8)) begin //发送低字节地址 165 flag <= 1'b1; // 获得总线控制权 166 sda_buffer <= memory[7]; 167 cnt <= cnt + 1'b1; 168 memory = {memory[6:0],memory[7]}; 169 state <= 5; 170 end 171 else begin 172 if((iic_scl == 0) && (cnt == 8)) begin 173 cnt <= 0; 174 flag <= 0; // 释放总线控制权 175 state <= 6; 176 end 177 else 178 state <= 5; 179 end 180 end 181 182 6:begin 183 if(!iic_scl) begin // 检测应答信号 184 if(temp == 2'b01) begin // 判断是否为写信号 185 state <= 7; 186 memory = data_in[7:0]; // 发送数据 187 end 188 if(temp == 2'b10) // 判断是否为读信号 189 state <= 11; 190 end 191 else 192 state <= 6; 193 end 194 195 7:begin 196 if((iic_scl == 0) && (cnt < 8)) begin // 发送数据 197 flag <= 1'b1; // 获得总线控制权 198 sda_buffer <= memory[7]; 199 cnt <= cnt + 1'b1; 200 memory = {memory[6:0],memory[7]}; 201 state <= 7; 202 end 203 else begin 204 if((iic_scl == 0) && (cnt == 8)) begin 205 cnt <= 0; 206 flag <= 0; // 释放总线控制权 207 state <= 8; 208 end 209 else 210 state <= 7; 211 end 212 end 213 214 8:begin 215 if(!iic_scl) //检测应答信号 216 state <= 9; 217 else 218 state <= 8; 219 end 220 221 9:begin 222 if(iic_scl == 0) begin 223 flag <= 1; //获得总线控制权 224 sda_buffer <= 0; //拉低IIC的数据线,为发送停止信号做准备 225 state <= 10; 226 end 227 else 228 state <= 9; 229 end 230 231 10:begin 232 if(iic_scl == 1) begin 233 sda_buffer <= 1; // 发送停止信号 234 state <= 0; 235 end 236 else 237 state <= 10; 238 end 239 //--------------------------------------// 240 11:begin 241 flag <= 1; //获得总线控制权 242 sda_buffer <= 1; // 拉高IIC控制线(为发送启动信号做准备) 243 state <= 12; 244 end 245 246 12:begin 247 sda_buffer <= 0; // 发送启动信号 248 state <= 13; 249 memory <= 8'b10100001; 250 end 251 252 13:begin 253 if((iic_scl == 0) && (cnt < 8)) begin // 发送8位控制字 254 flag <= 1; // 获得总线控制权 255 sda_buffer <= memory[7]; 256 cnt <= cnt + 1'b1; 257 memory <= {memory[6:0],memory[7]}; 258 state <= 13; 259 end 260 else begin 261 if((iic_scl == 0) && (cnt == 8)) begin 262 cnt <= 0; 263 flag <= 0; // 释放总线控制权 264 state <= 14; 265 end 266 else 267 state <= 13; 268 end 269 end 270 271 14:begin 272 if(!iic_scl) // 检测应答信号 273 state <= 15; 274 else 275 state <= 14; 276 end 277 278 15:begin 279 if((iic_scl == 1) && (cnt < 8)) begin // 接收数据 280 cnt <= cnt + 1'b1; 281 memory <= {memory[6:0],iic_sda}; 282 end 283 else begin 284 if((iic_scl == 0) && (cnt == 8)) begin 285 cnt <= 0; 286 flag <= 1; // 获得总线控制权 287 state <= 16; 288 sda_buffer <= 1; // 发送应答信号 289 end 290 else 291 state <= 15; 292 end 293 end 294 295 16:begin 296 data_out <= memory; // 发送数据 297 state <= 17; 298 end 299 300 17:begin 301 if(iic_scl == 0) begin 302 sda_buffer <= 0; //拉低IIC的数据线,为发送停止信号做准备 303 state <= 18; 304 end 305 else 306 state <= 17; 307 end 308 309 18:begin // 发送停止信号 310 if(iic_scl == 1) begin 311 sda_buffer <= 1; 312 state <= 0; 313 end 314 else 315 state <= 18; 316 end 317 318 default: state <= 0; 319 endcase 320 321 endmodule 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
测试代码
1 `timescale 1ns/1ps 2 module iic_driver_tb; 3 reg clk; 4 reg rst_n; 5 6 reg key_rd; 7 reg key_wr; 8 9 reg[7:0] data_in; 10 11 wire iic_sda; 12 13 wire iic_scl; 14 wire[7:0] data_out; 15 16 iic_driver u0( 17 .clk(clk), 18 .rst_n(rst_n), 19 20 .iic_scl(iic_scl), 21 .iic_sda(iic_sda), 22 23 .key_wr(key_wr), 24 .key_rd(key_rd), 25 26 .data_in(data_in), 27 .data_out(data_out) 28 ); 29 30 initial 31 clk = 0; 32 always #10 clk = ~clk; 33 34 initial 35 begin 36 rst_n = 1'b0; 37 key_rd = 1'b1; 38 key_wr = 1'b1; 39 data_in = 1'b0; 40 41 #1000; 42 rst_n = 1'b1; 43 44 #800; 45 46 #8000 key_wr = 1'b0; 47 data_in = 8'h23; 48 #4000 key_wr = 1'b1; 49 50 #1000000; 51 key_rd = 1'b0; 52 #40000; 53 key_rd = 1'b1; 54 55 #10000000; 56 $stop; 57 end 58 endmodule
仿真结果:
(1)写时序
(2)读时序