原创 基于FPGA的图像采集之二 GEN_FRAME(成帧)模块

2015-10-5 16:05 1694 26 26 分类: FPGA/CPLD

距离上次的博客已经有段时间了,这写些日子一直在调SDRAM的模块以及文档的书写,SDRAM的子模块比较多,包括init(初始化模块)、refresh(刷新模块)、write(写模块)、read(读模块),使用起来相比之前的USB控制模块、今天的GEN_FRAME(以下均表示为成帧模块)都稍显复杂一些。好了,接下来介绍我们今天的主角:成帧模块。成帧模块的作用有两个:

1.完成时钟域的转换:将缓存到sdram中的数据读出发送给USB,sdram芯片可以达到的时钟频率范围大致为24MHZ-256MHZ,该时钟由FPGA给出,具体的时钟还要看FPGA稳定工作可以达到的时钟。另一方面,USB控制器的时钟有USB芯片给出,为48MHZ。数据在不同时钟域间的传输就要用到时钟域的转换。
2.给数据加下帧头:发送数据之前,首先给数据加上一行帧头,表明我的一行数据开始发送,该帧头包含了图像的列信息,然后将加了帧头的数据发送给USB控制模块,由它通过USB芯片发给上位机。
 
(一)跨时钟域的转换
下面我们来谈谈今天主角中的主角:跨时钟域的转换
1,不做时钟域的转换有什么危害?2.单bit的信号与多bit的信号的处理方式有何不同?
带着这两个疑问我们来看。我们在做项目的时候不免会遇到两个模块的时钟不同的情况,A用的时钟是48MHZ,B用到的时钟是133MHZ(这里的48跟133只是说明时钟不同)。
单bit的信号为例,都以上升沿采样:
A.现在有一个由133MHZ产生的脉冲信号(一个时钟周期)flag,通过接口传给A(48MHZ),A要检测到它,可是现象是,你133MHZ太快了(太短),A的上升沿根本采不到它(也有概率可以采得到)。
B.反过来呢?A(48MHZ)的信号传给B(133MHZ),由于A的时钟频率比B慢,根本不会存在B采不到A信号的情况,但是还会有问题(就是不能让你好好传),亚稳态。
解释一下亚稳态:a.概念:指触发器无法在某个规定时间段内达到一个可确认的状态。(是不是还是有点不懂,没事看下面)。
b.什么情况会导致亚稳态:在同步系统中,建立时间、保持时间不满足就可能会产生,此时的输出端(Q端)在有效的时钟沿之后比较长时间处于不确定状态,毛刺、振荡或者是一个固定的某一电压(却不是D端的电压),这段时间成为决断时间,之后稳定在0、1上,但是这是随机的,跟输入没有必然的关系。
说了这么多,什么意思?就是每个频率的时钟都有自己的一个规则(建立时间、保持时间),我的地盘听我的,到了我的地盘就要按我的规矩办事,你不按我的规则来可以,后果就是,我随便给你输出一个值,这个值是什么,看心情,用了这个数据出不出问题就不是我的事了。
c.如何解决:1.减低时钟频率。2.将寄存器打两拍再使用。
跨时钟域的处理
      A比较惨,A的情况包含了B,即包含采不到的情况,又存在亚稳态的问题,下面给出A的处理过程。有没有发现今天的图非常少,先上图。
1.gif
  将数据打三拍,一共四个寄存器,通过一个or门,时钟域转换为48MHZ,再延时两拍得到稳定的标志位。通过or门产生的信号会有毛刺,打两拍还可以起到去毛刺的作用。
 
          2.gif
 
另外,多bit同频率,异相位的时钟域切换,使用双口ram进行同步(同频异相),不同频不同相时钟转换使用异步FIFO做同步。成帧模块用到了异步FIFO做处理。
(二)GEN_FRAME模块描述
1模块框图
3.gif
 
       1.SDRAM存储一帧数据后使能read_start信号,GEN_FRAME将帧头发给USB W_FIFO,同时SDRAM向GEN_FRAME的内部FIFO写入一行数据。

2.SDRAM写完一行数据后等待写下一行的命令(read_req),GEN_FRAME继续向USB W_FIFO写入数据(w_flag有效),直到写完一行后等待。当PC将W_FIFO中数据读完,即flag_C==0时,read_req有效。

3.当read_req有效时,下一行开始传输,GEN_FRAME中的FIFO同时进行读写(SDRAM向GEN_FRAME中的FIFO中写,同时将GEN_FRAME中的数据读出到USB W_FIFO)。

4.直到读完一帧图像后(即行计数row_cnt计满),read_req无效,w_flag无效,停止读写。

2接口定义

4.gif

 

3关键信号时序

    A)GEN_frame数据到USB W_FIFO

5.gif

① Sdram存完一帧数据后发送read_start信号,经夸时钟域处理后得到read_start_48,在此信号后检测到flag_C0(即W_FIFO为空),因此要将read_start_48做延展,得到read_start_buf,取它的下降沿为读一帧数据开始。

② 检测到read_start_buf的下降沿后将w_usb_flag_reg拉高,同时w_usb_cnt开始计数,由于数据给出客观上延时一拍才能读到,所以讲使能信号延时一拍发出,即w_usb_flag。该信号为传入下一级的使能信号。

③ 一行数据读出后,继续检测flag_C=0时,F_read_req(GEN FIFO发送读请求)r_fifo_enw_usb_flag一致,同时读出fifo中的数据r_fifo_data

注意:根据同步fifo的经验,这里的r_fifo_en本应该提前数据一拍给出,但上面写到同时读出fifo数据。没错,根据代码发现,异步fifo的读使能r_fifo_en与读数据r_fifo_data居然是同一时刻给出来!!!!!

④ 每读完一行数据我们的行计数gen_cnt_row要加一。这里的行计数是由w_usb_flag_reg的下降沿来触发目的是保证不要丢数据。

⑤ 最终GEN_FRAME输出数据w_data根据行号来选择,gen_cnt_row=0选择zhen_data,否则选择fifo_data

注意:这里面的gen_cnt_row要记到row_cnt+1(帧头)。

B)sdramGEN_FRAME FIFO中写数据

6.gif

 利用sdram时钟检测flag_C的下降沿,产生read_req,并输出到sdram控制模块中。

② 检测到read_req为高时,sdram将数据传入GEN模块,cnt_data开始计数,计数器由SD_data_v使能信号控制(读sdram被刷新打断,数据会被打断),计数到499停止。

③ 写入fifo的数据为51216bit的数据,数据只有500个,所以要补1216bit的数据零,cnt_12cnt_data==499时开始计数,计到11为止。

SD_data_vcnt_12_flag作或操作,时序赋值给w_fifo_en。数据时序赋值给w_fifo_data。分别为写入fifo的使能信号与数据信号。 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
26
关闭 站长推荐上一条 /3 下一条