标签:png stat 取数据 iic 电视 没有 div ESS bit
一、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)读时序
读时序也存在一些问题,停止信号出现了和写时序时同样的问题,没有完全符合预期,数据接收部分全为高阻状态。
还有一种IIC驱动的写法,和调用仿真模型的来测试iic驱动程序,留待更新。
注:
(1)文字叙述方面参考了小梅哥,正点原子,至芯科技的相关文章;
(2)代码设计参考了小梅哥,CrazyBingo的设计思路;
标签:png stat 取数据 iic 电视 没有 div ESS bit
原文地址:https://www.cnblogs.com/571328401-/p/12639976.html