I2C

1) I2C结构

I2C 总线在物理连接上比较简单,分别由 SDA(串行数据线)和 SCL(串行时钟线)两条总线及上拉电阻组成。通信的原理是通过控制 SCL 和 SDA 的时序,使其满足 I2C 的总线协议从而进行数据的传输。I2C 总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址(可以从 I2C 器件数据手册得知),主从设备之间就是通过这个地址来确定与哪个器件进行通信。本次实验我们把 FPGA 作为主设备,把挂载在总线上的其他设备(ADV7513)作为从设备。I2C 总线数据传输速率在标准模式下可达 100kbit/s,快速模式下可达400kbit/s,高速模式下可达 3.4Mbit/s。 I2C 总线上的主设备与从设备之间以字节(8 位)为单位进行双向的数据传输。

 I2C

2) I2C时序

通过查阅ADV7513的数据手册(数据手册提供在项目目录下的user_giude文件夹下),可以大概的了解一下IIC的整体时序图时序。

 

I2C

 

I2C

IIC整体时序图注意点如下:

① 空闲状态,SDA和SCL都保持为高

② I2C协议起始位:SCL为高电平时,SDA出现下降沿,产生一个起始位

③ I2C结束位:SCL为高电平时,SDA出现上升沿,产生一个停止位

④ I2C在数据传输过程中SCL与SDA的变化关系:

当 I2C 主机(后面简称主机)向 I2C 从机(后面简称从机) 写入数据时,SDA 上的每一位数据在 SCL 的高电平期间被写入从机中。 从主机角度来看, 需要在 SCL 低电平期间改变要写入的数据。而当主机读取从机中数据时,从机在SCL 低电平期间将数据输出到 SDA 总线上,在 SCL 的高电平期间保持数据稳定,从主机角度来看, 需要在 SCL 的高电平期间将 SDA 线上的数据读取并存储。

每当一个字节的数据或命令传输完成时,数据接收方都会向发送方响应一位应答位。在响应应答位时,数据发出方将 SDA 总线设置为三态输入,由于 I2C 总线上都有上拉电阻,因此此时总线默认为高电平,若数据接收方正确接收到数据,则数据接收方将 SDA 总线拉低,以示正确应答。

例如当主机向从机写入数据或命令时,每个字节都需要从机产生应答信号以告诉主机此次的数据或命令是否成功被写入。所以,当主机将一字节的数据或命令传出后,会将 SDA 信号设置为三态输入,等待从机应答(等待 SDA 被从机拉低为低电平),若从机正确应答,表明当前数据或命令传输成功,可以结束或开始下一个数据或命令的传输,否则表明数据或命令写入失败,主机就可以决定是否放弃写入或者重新发起写入。

值得注意的是,当主机从设备中读出数据时,当读出最后一个数据的时候,要向总线上发送一个NACK停止本次读取。总的来说,就是谁是数据的接收方,谁就要给出响应。

 

 

3) IIC写时序

 I2C

 

 

上图是一张IIC写时序图,从图中我们可以看到,想要对I2C设备进行写操作,需要经历如下步骤。

首先产生一个起始位,然后向总线上给出要访问的I2C设备的7位设备ID和一位读写操作位(0为写操作,1为读操作),等到从机给总线上反馈一个低有效信号ACK时证明总线上存在这个设备,然后才能进行读写操作。

在接收到ACK后,主机向总线上写入要访问的寄存器地址,如存在要访问的寄存器地址,从机会在总线上反馈一个ACK信号,此时,主机可以向从机写入数据。

如主机向从机单次写数据,在写完8位数据后,接收到响应ACK后,将产生一个停止位,结束本次写操作。若是进行连续写入多字节数据,每当写完一字节数据,都会等待ACK才能进行下一字节的写操作。写入全部字节后将产生一个停止位,结束本次写操作。

写操作要注意的几点就是:IIC设备地址,IIC寄存器地址以及将要填充的字节数据。

 

4) IIC读时序

 I2C

 

 

IIC读操作分为两个步骤,进行I2C读操作时,首先要进行写操作,然后才能进行读操作。

首先需要向I2C总线上给出要访问的设备的地址,若总线上存在这个设备,将会给出一个响应ACK信号,然后在给出将要访问的寄存器,接收到ACK信号后产生停止位。

 

经历上一个步骤后,才能开始发起读操作。读设备中寄存器内的值时,首先也要产生一个起始位,然后给出设备地址和读操作命令,接收到ACK信号后,给出要访问的寄存器地址,接收到ACK信号后,从机将会把寄存器中的地址输出到I2C总线上。

若是只读一字节数据,在一字节数据接收完成后,将会产生一个NACK信号,主机接收到NACK信号后将终止本次读操作;若是进行多字节的读操作,当还未接收到最后一字节数据时,每当接收完一字节的数据,将会接收到一个ACK信号,主机在接收到ACK信号后继续接收从机发出的数据。当主机接收到从机的NACK信号后,产生停止位,结束本次操作。

 

3) 功能设计

驱动模块的功能框图如下,上游模块给出读写请求和读写地址,在使能start信号后即可以开始进行数据的传输。用户可以将数据写入到I2C从设备中也可以从I2C从设备中读出数据,传输错误时将给出一个错误信号err_flag。传输完成后根据读写请求回应一个读写完成信号。

 

 

I2C

 

状态跳转图如下:

I2C

 

 

代码设计:

 

  1 /*============================================
  2 #
  3 # Author: Wcc - 1530604142@qq.com
  4 #
  5 # QQ : 1530604142
  6 #
  7 # Last modified: 2019-11-08 18:00
  8 #
  9 # Filename: i2c_driver.v
 10 #
 11 # Description: I2C驱动模块,暂时只能完成对设备地址为1字节的设备进行访问
 12 #               并且暂时还没有错误重传机制,将在后面完善
 13 ============================================*/
 14 `timescale 1ns / 1ps
 15 module i2c_driver(
 16     input   wire            clk     ,//系统时钟
 17     input   wire            rst     ,//系统复位
 18     input   wire            wr_req  ,//写请求信号
 19     input   wire            rd_req  ,//读请求信号
 20     input   wire            start   ,//一次读写开始信号
 21     input   wire    [7:0]   dev_addr,//设备地址
 22     input   wire    [7:0]   mem_addr,//寄存器地址
 23     input   wire    [7:0]   wr_data ,//写入寄存器的数据
 24 
 25     output  reg     [7:0]   rd_data ,//从寄存器读出的数据
 26     output  reg             rd_done ,//一次读操作结束
 27     output  reg             wr_done ,//一次写操作结束
 28     output     reg             err_flag,//发生错误信号
 29     output  reg             scl     ,//i2c时钟
 30     inout   wire            sda      //i2c数据总线   
 31     );
 32 
 33 //==================================================
 34 //parameter define
 35 //==================================================
 36 parameter   IDLE    = 10'b00_0000_0001;//空闲状态
 37 parameter   WR_START= 10'b00_0000_0010;//写起始
 38 parameter   WR_DEV  = 10'b00_0000_0100;//确认设备地址
 39 parameter   WR_MEM  = 10'b00_0000_1000;//确认寄存器地址
 40 parameter   WR_DATA = 10'b00_0001_0000;//写数据
 41 parameter   RD_START= 10'b00_0010_0000;//读开始
 42 parameter   RD_DEV  = 10'b00_0100_0000;//设备地址读操作
 43 parameter   RD_DATA = 10'b00_1000_0000;//读数据
 44 parameter   STOP    = 10'b01_0000_0000;//停止
 45 parameter    ERROR    = 10'b10_0000_0000;//错误
 46 
 47 
 48 parameter   SYS_CYCLE = 20;//系统时钟50M
 49 parameter   IIC_CYCLE = 5000;//IIC 工作频率200K
 50 parameter   MAX      = (IIC_CYCLE/SYS_CYCLE) -1;//驱动时钟的计数最大值
 51 parameter   T_HIGH   = 2000 ;//I2C时钟高电平
 52 parameter   T_LOW    = 3000 ;//I2C时钟低电平
 53 
 54 parameter   FLAG0 = ((T_HIGH/SYS_CYCLE)>>1) - 1;//SCL高电平中点
 55 parameter   FLAG1 = (T_HIGH/SYS_CYCLE) - 1;//SCL下降沿
 56 parameter   FLAG2  = (T_HIGH/SYS_CYCLE) + ((T_LOW/SYS_CYCLE)>>1) -1;//SCL低电平中点
 57 parameter   FLAG3  = (T_HIGH/SYS_CYCLE) + (T_LOW/SYS_CYCLE) - 1;//SCL上升沿
 58 //==================================================
 59 //internal signals
 60 //==================================================
 61 reg     [2:0]   cnt_freq    ;//计数drive_flag 产生I2C时钟
 62 wire            add_cnt_freq;
 63 wire            end_cnt_freq;
 64 
 65 
 66 reg     [5:0]   cnt_flag    ;//计数当前状态有多少个drive_flag
 67 wire            add_cnt_flag;
 68 wire            end_cnt_flag;
 69 reg     [5:0]   x           ;//可变计数器的最大值
 70 
 71 reg     [9:0]   cnt         ;//用来产生驱动信号drive_flag
 72 wire            add_cnt     ;
 73 wire            end_cnt     ;
 74 
 75 reg             drive_flag  ;//用于驱动本模块工作的信号
 76 reg     [8:0]   state       ;//state register
 77 reg             work_flag   ;//work flag
 78 reg             wr_en       ;//三态数据线写使能
 79 reg     [7:0]   data_shift  ;//移位寄存器
 80 reg             ack_flag    ;//响应信号
 81 
 82 reg             wr_sda      ;
 83 wire            rec_sda     ;
 84 
 85 //三态端口声明
 86 assign  sda = wr_en?wr_sda:1'bz;//当主机向数据向数据总线上写数据时,wr_en=1,给出用户数据,当接收数据时,置为高阻
 87 assign  rec_sda = sda;
 88 //--------------------state machine define--------------------
 89 always @(posedge clk)begin
 90     if(rst == 1'b1)begin
 91         state <= IDLE;
 92     end
 93     else begin
 94         case(state)
 95             IDLE:begin
 96                 if(start==1'b1 && (wr_req==1'b1 || rd_req==1'b1))
 97                     state <= WR_START;//接收到开始信号,进入起始状态
 98                 else
 99                     state <= IDLE;
100             end
101 
102             WR_START:begin
103                 if(cnt_flag=='d6 && drive_flag)
104                     state <= WR_DEV;//起始状态结束,进入确认设备地址状态
105                 else
106                     state <= WR_START;
107             end
108 
109             WR_DEV:begin
110                 if(cnt_flag=='d35 && drive_flag && ack_flag==1'b1)//发送完设备地址,并且正确接收到响应
111                     state <= WR_MEM;//确认地址状态结束,进入确认寄存器地址状态
112                 else if(cnt_flag=='d35 && drive_flag && ack_flag==1'b0)//发送完设备地址,并且没有接收到响应
113                     state <= ERROR;//确认地址状态结束,进入确认寄存器地址状态
114                 else
115                     state <= WR_DEV;
116             end
117 
118             WR_MEM:begin
119                 if(cnt_flag=='d35 && drive_flag && ack_flag==1'b1)begin//已经给出写入的寄存器,并且正确接收到响应
120                     if(wr_req==1'b1)
121                         state <= WR_DATA;//确认寄存器地址状态结束,进入写数据状态
122                     else if(wr_req==1'b0 && rd_req==1'b1)
123                         state <= RD_START;//确认寄存器地址状态结束,进入写开始状态
124                 end
125                 else if(cnt_flag=='d35 && drive_flag && ack_flag==1'b0)//发送完设备地址,并且没有接收到响应
126                     state <= ERROR;//确认地址状态结束,进入确认寄存器地址状态
127                 else 
128                     state <= WR_MEM;
129             end
130 
131             WR_DATA:begin
132                 if(cnt_flag=='d35 && drive_flag && ack_flag==1'b1)//已经给出写入数据并正确接收到响应
133                     state <= STOP;//数据写入完成进入停止状态
134                 else if(cnt_flag=='d35 && drive_flag && ack_flag==1'b0)//发送完设备地址,并且没有接收到响应
135                     state <= ERROR;//确认地址状态结束,进入确认寄存器地址状态
136                 else
137                     state <= WR_DATA;
138             end
139 
140             RD_START:begin
141                 if(cnt_flag=='d3 && drive_flag && rd_req)
142                     state <= RD_DEV;//进入设备地址读操作
143                 else
144                     state <= RD_START;
145             end
146 
147             RD_DEV:begin
148                 if(cnt_flag=='d35 && drive_flag && ack_flag==1'b1)
149                     state <= RD_DATA;//进入读数据状态
150                 else if(cnt_flag=='d35 && drive_flag && ack_flag==1'b0)//发送完设备地址,并且没有接收到响应
151                     state <= ERROR;//确认地址状态结束,进入确认寄存器地址状态
152                 else
153                     state <= RD_DEV;
154             end
155 
156             RD_DATA:begin
157                 if(cnt_flag=='d35 && drive_flag && ack_flag==1'b1)
158                     state <= STOP;
159                 else if(cnt_flag=='d35 && drive_flag && ack_flag==1'b0)//发送完设备地址,并且没有接收到响应
160                     state <= ERROR;//确认地址状态结束,进入确认寄存器地址状态
161                 else
162                     state <= RD_DATA;
163             end
164 
165             STOP:begin
166                 if(cnt_flag=='d3 && drive_flag)
167                     state <= IDLE;
168                 else
169                     state <= STOP;
170             end
171 
172             ERROR:begin
173                 state <= IDLE;
174             end
175 
176             default:begin
177                 state <= IDLE;
178             end
179         endcase
180     end
181 end
182 
183 //-------------------work_flag---------------------
184 always @(posedge clk)begin
185     if(rst == 1'b1)begin
186         work_flag <= 1'b0;
187     end
188     else if(state==WR_START)begin//接收到开始信号
189         work_flag <= 1'b1;
190     end
191     else if(wr_done==1'b1 || rd_done==1'b1)begin//一次读写完成
192         work_flag <= 1'b0;
193     end
194 end
195 
196 //--------------------cnt--------------------
197 always @(posedge clk)begin
198     if(rst==1'b1)begin
199         cnt <= 0;
200     end
201     else if(add_cnt)begin
202         if(end_cnt)
203             cnt <= 0;
204         else
205             cnt <= cnt + 1'b1;
206     end
207     else begin
208         cnt <= 'd0;
209     end
210 end
211 
212 assign add_cnt = work_flag;//处于工作状态时一直计数       
213 assign end_cnt = add_cnt && cnt== MAX;//计数到最大值清零
214 
215 //--------------------drive_flag--------------------
216 always @(posedge clk)begin
217     if(rst == 1'b1)begin
218         drive_flag <= 1'b0;
219     end
220     else if(cnt==FLAG0 || cnt==FLAG1 || cnt==FLAG2 || cnt==FLAG3)begin//产生一个驱动信号
221         drive_flag <= 1'b1;
222     end
223     else begin
224         drive_flag <= 1'b0;
225     end
226 end
227 
228 //--------------------cnt_freq--------------------
229 //对驱动信号进行计数,以此来产生I2C时钟
230 always @(posedge clk)begin
231     if(rst==1'b1)begin
232         cnt_freq <= 0;
233     end
234     else if(work_flag == 1'b0)begin
235         cnt_freq <= 'd0;
236     end
237     else if(add_cnt_freq)begin
238         if(end_cnt_freq)
239             cnt_freq <= 0;
240         else
241             cnt_freq <= cnt_freq + 1'b1;
242     end
243     else begin
244         cnt_freq <= cnt_freq;
245     end
246 end
247 
248 assign add_cnt_freq = drive_flag;       
249 assign end_cnt_freq = add_cnt_freq && cnt_freq== 4-1; 
250 
251 //--------------------scl--------------------
252 always @(posedge clk)begin
253     if(rst == 1'b1)begin
254         scl <= 1'b1;
255     end
256     else if(work_flag==1'b1)begin
257         if(cnt_freq=='d1 && drive_flag &&state==STOP)begin
258             scl <= 1'b1;
259         end
260         else if(cnt_freq=='d1 && drive_flag && state!= STOP)begin
261             scl <= 1'b0;
262         end
263         else if(cnt_freq=='d3 && drive_flag)begin
264             scl <= 1'b1;
265         end
266     end
267     else begin
268         scl <= 1'b1;
269     end
270 end
271 
272 //--------------------cnt_flag--------------------
273 //计数当前状态下有多少个drive_flag
274 always @(posedge clk)begin
275     if(rst==1'b1)begin
276         cnt_flag <= 0;
277     end
278     else if(work_flag==1'b0)begin
279         cnt_flag <= 'd0;
280     end
281     else if(add_cnt_flag)begin
282         if(end_cnt_flag)
283             cnt_flag <= 0;
284         else
285             cnt_flag <= cnt_flag + 1'b1;
286     end
287     else begin
288         cnt_flag <= cnt_flag;
289     end
290 end
291 
292 assign add_cnt_flag = drive_flag;       
293 assign end_cnt_flag = add_cnt_flag && cnt_flag== x ; 
294 
295 //--------------------x--------------------
296 //x为不同状态下,计数器的计数最大值
297 always  @(*)begin
298     case(state)
299         IDLE: x=0;
300         WR_START: x= 7 - 1;
301         WR_DEV,WR_MEM,WR_DATA,RD_DEV,RD_DATA: x=36 - 1;
302         RD_START: x= 4 - 1;
303         STOP: x = 4 - 1;
304         default: x = 0;          
305     endcase
306 end
307 
308 //------------------wr_en----------------------
309 always @(posedge clk)begin
310     if(rst == 1'b1)begin
311         wr_en <= 1'b0;
312     end
313     else if(state==WR_START || state==RD_START || state==STOP)begin
314         wr_en <= 1'b1;//在写开始,读开始,和结束状态,由用户操纵数据总线,产生开始或者停止信号,所以写数据使能有效
315     end
316     else if(state==WR_DEV || state==WR_MEM ||state==WR_DATA || state==RD_DEV)begin
317         if(cnt_flag < 'd32)begin//给出用户数据时,写数据使能有效
318             wr_en <= 1'b1;
319         end
320         else begin
321             wr_en <= 1'b0;//等待从设备响应时,写数据使能无效
322         end
323     end
324     else if(state==RD_DATA)begin
325         if(cnt_flag < 'd32)begin
326             wr_en <= 1'b0;//接收数据状态,此时由从机发送数据给主机,写数据使能无效
327         end
328         else begin
329             wr_en <= 1'b1;//接收数据完成,主机需要对从机做出应答,写数据使能有效
330         end
331     end
332     else begin
333         wr_en <= 1'b0;
334     end
335 end
336 
337 //--------------------data_shift--------------------
338 always @(posedge clk)begin
339     if(rst == 1'b1)begin
340         data_shift <= 'd0;
341     end
342     else begin
343         case(state)
344             IDLE:begin
345                 data_shift <= 'd0;//空闲状态,让移位寄存器保持为0
346             end
347 
348             WR_START:begin
349                 data_shift <= {dev_addr[7:1],1'b0};//写开始状态,给出设备写指令
350             end
351 
352             WR_DEV:begin
353                 if(end_cnt_flag && ack_flag==1'b1)
354                     data_shift <= mem_addr;//确认设备状态结束时,给出寄存器地址
355                 else if(cnt_flag<'d32 && cnt_flag[1:0]==2'd3 && drive_flag)
356                     data_shift <= {data_shift[6:0],1'b0};
357             end
358 
359             WR_MEM:begin
360                 if(end_cnt_flag && ack_flag==1'b1 && wr_req==1'b1)//即将进入写数据状态
361                     data_shift <= wr_data;//确认寄存器地址状态结束后给出要写入的数据
362                 else if(cnt_flag<'d32 && cnt_flag[1:0]==2'd3 && drive_flag)
363                     data_shift <= {data_shift[6:0],1'b0};
364             end
365 
366             WR_DATA:begin
367                 if(cnt_flag<'d32 && cnt_flag[1:0]==2'd3 && drive_flag)
368                     data_shift <= {data_shift[6:0],1'b0};//将数据写入到寄存器中
369                 else
370                    data_shift <= data_shift; 
371             end
372 
373             RD_START:begin
374                 data_shift <=  {dev_addr[7:1],1'b1};//读开始时,将读命令填充入移位寄存器
375             end
376 
377 
378             RD_DEV:begin
379                 if(end_cnt_flag && ack_flag==1'b1)
380                     data_shift <= 'd0;
381                 else if(cnt_flag<'d32 && cnt_flag[1:0]==2'd3 && drive_flag)
382                     data_shift <= {data_shift[6:0],1'b0};
383             end
384 
385             RD_DATA:begin
386                 if(cnt_flag<'d32 && cnt_flag[1:0]==2'd1 && drive_flag)
387                     data_shift <= {data_shift[6:0],rec_sda};//将从寄存器中读出的数据填充入移位寄存器
388                 else
389                     data_shift <= data_shift;
390             end
391 
392             default:begin
393                 data_shift <= data_shift;
394             end
395         endcase
396     end
397 end
398 
399 
400 
401 //--------------------wr_sda--------------------
402 always @(posedge clk)begin
403     if(rst == 1'b1)begin
404         wr_sda = 1'b1;
405     end
406     else begin
407         case(state)
408             WR_START:begin
409                 if(cnt_flag=='d4 && drive_flag)
410                     wr_sda <= 1'b0;//产生起始位
411                 else
412                     wr_sda <= wr_sda;
413             end
414 
415             WR_DEV,WR_MEM,WR_DATA,RD_DEV:begin
416                 wr_sda <= data_shift[7];//将数据发送至数据总线上
417             end
418 
419             RD_START:begin
420                 if(cnt_flag=='d0)
421                     wr_sda <= 1'b1;//产生读起始位
422                 else if(cnt_flag=='d1 && drive_flag)
423                     wr_sda <= 1'b0;
424             end
425 
426             RD_DATA:begin
427                 if(cnt_flag>='d32)
428                     wr_sda <= 1'b1;//产生NACK
429                 else
430                     wr_sda <= wr_sda;
431             end
432 
433             STOP:begin
434                     if(cnt_flag=='d0 && wr_en)
435                         wr_sda <= 1'b0;
436                     else if(cnt_flag=='d1 && drive_flag)
437                         wr_sda <= 1'b1;
438             end
439             
440             default:wr_sda <= 1'b1;
441         endcase
442     end
443 end
444 
445 //--------------------wr_done,rd_done--------------------
446 always @(posedge clk)begin
447     if(rst == 1'b1)begin
448         wr_done <= 1'b0;
449         rd_done <= 1'b0;
450     end
451     else if(state==STOP && end_cnt_flag)begin//即将结束本次读写操作的时候,产生完成信号
452         if(wr_req==1'b1)
453             wr_done <= 1'b1;
454         else if(wr_req==1'b0 && rd_req==1'b1)
455             rd_done <= 1'b1;
456     end
457     else begin
458         wr_done <= 1'b0;
459         rd_done <= 1'b0;
460     end
461 end
462 
463 //--------------------ack_flag--------------------
464 //是否接收到ACK或者产生NACK
465 always @(posedge clk)begin
466     if(rst == 1'b1)begin
467         ack_flag <= 1'b0;
468     end
469     else begin
470         case(state)
471             WR_DEV:begin
472                 if(cnt_flag>='d32 && cnt_flag[1:0]=='d1 && drive_flag && sda==1'b0)
473                     ack_flag <= 1'b1;//写完设备地址,并且接收到响应
474                 else if(end_cnt_flag)
475                     ack_flag <= 1'b0;
476             end
477 
478             WR_MEM:begin
479                 if(cnt_flag>='d32 && cnt_flag[1:0]=='d1 && drive_flag && sda==1'b0)
480                     ack_flag <= 1'b1;//写完寄存器地址,接收到响应
481                 else if(end_cnt_flag)
482                     ack_flag <= 1'b0;
483             end
484 
485             WR_DATA:begin
486                 if(cnt_flag>='d32 && cnt_flag[1:0]=='d1 && drive_flag && sda==1'b0)
487                     ack_flag <= 1'b1;//写完数据,并且接收到响应
488                 else if(end_cnt_flag)
489                     ack_flag <= 1'b0;
490             end
491 
492             RD_DEV:begin
493                 if(cnt_flag>='d32 && cnt_flag[1:0]=='d1 && drive_flag && sda==1'b0)
494                     ack_flag <= 1'b1;//读指令发送完毕,接收到响应
495                 else if(end_cnt_flag)
496                     ack_flag <= 1'b0;
497             end
498 
499             RD_DATA:begin
500                 if(cnt_flag>='d32 && cnt_flag[1:0]=='d1 && drive_flag && sda==1'b1)
501                     ack_flag <= 1'b1;//数据全部读完,主机给出NACK
502                 else if(end_cnt_flag)
503                     ack_flag <= 1'b0;
504             end
505 
506             default: ack_flag <= 1'b0;
507         endcase
508     end
509 end
510 
511 //--------------------rd_data--------------------
512 always @(posedge clk)begin
513     if(rst == 1'b1)begin
514         rd_data <= 1'b0;
515     end
516     else if(rd_done)begin//即将结束本次读写操作的时候,产生完成信号
517         rd_data <= data_shift;
518     end
519     else begin
520         rd_data <= rd_data;
521     end
522 end
523 
524 always @(posedge clk)begin
525     if(rst == 1'b1)begin
526         err_flag <= 1'b0;
527     end
528     else if(state==ERROR)begin//即将结束本次读写操作的时候,产生完成信号
529         err_flag <= 1'b1;
530     end
531     else begin
532         err_flag <= 1'b0;
533     end
534 end
535 
536 endmodule

 

 

 

上一篇:OS + CentOS kernel parameter


下一篇:openframeworks 设置不显示控制台窗口