你是程序猿对吗?会写代码的那种?
紧接上次的VS2设计(一),今天学习模块设计和结果分析
3. 模块设计
3.1 模块检测
3.1.1 模块功能
对输入的视频源进行帧频检测(包括小数帧频),分辨率检测。
3.1.2 接口设计
图3-1 检测模块顶层框图
检测模块的实现顶层框图如图3-1所示,其接口描述如下:
detection detectionInst
(
.Clk50M ( MAINCLK50M ),
.DVIIN1_VS ( DVIIN1_VS ),
.DVIIN1_HS ( DVIIN1_HS ),
.DVIIN1_DE ( DVIIN1_DE ),
.DVIIN1_DCLK ( DVIIN1_DCLK ),
.HorCnt ( HorCnt1 ),
.VerCnt ( VerCnt1 ),
.Frame ( Frame1 ),
.HsNum ( HsNum1 ),
.VsNum ( VsNum1 ),
.FrameNum ( FrameNum1 ),
.stable ( stable )
);
3.1.3 实现方式
DVIIN1_CLK为输入视频源的随路时钟,用于检测分辨率的时钟,行分辨率的检测从视频源的数据有效信号DVIIN1_DE的上升沿开始计数,直到DVIIN1_DE的下降沿对HsNum锁存输出。列分辨率的检测的是一个DVIIN1_HS有效期间检测DVIIN1_DE的上升沿或者下降沿个数(实现方式如下),然后在DVIIN1_HS的下降沿将VsNum锁存输出。
assign DePosedge = DVIIN1_DE&&(~DVIIN1_DE_N) ;//下降沿脉冲信号
assign DeNegedge = (~DVIIN1_DE)&&DVIIN1_DE_N ;//上升沿脉冲信号
检测帧频需要使用外部晶振,时钟频率为50MHz,产生一个1秒的计数器,然后计算DVIIN1_VS的上升沿或者下降沿个数,然后输出帧频FrameNum1。如果需要检测小数帧频,本设计是计算100秒内DVIIN1_VS的上升沿或者下降沿个数,然后除以100就可以得到小数帧频。
3.1.4 技术难点
● 检测帧频的1秒计数器必须使用精确的时钟,如果使用随路时钟会产生计数器不精确,或者PLL倍频出来的时钟也必须使用实际值,不能只是用理论值
● 可以将输入视频源的场信号VS,行信号HS,数据有效信号DE和数据进行打拍,保证稳定检测和输出。
3.2 DDR读写模块
DDR读写模块是为了将输入的视频数据存储在DDR中,然后再输出,图3-2为DDR读写模块的顶层框图。主要包括数据源输入、DDR接口、数据读出等接口。
图3-2 DDR读写模块顶层框图
如图3-3所示,DDR读写模块内部的模块主要由写配置模块、写数据模块、Top层模块、MIG核模块、读配置模块、读数据模块等。
图3-3 DDR读写模块内部框图
3.2.1 写模块
3.2.1.1 模块功能
将待输入的视频源数据写入DDR中。
3.2.1.2 接口设计
图3-4 写模块顶层框图
写模块顶层框图如图3-4所示,其接口描述如下:
PingPangWr
#
(
.DATAINWIDTH ( DATAINWIDTH ),
.ADDRINWIDTH ( ADDRINWIDTH ),
.DATAOUTWIDTH( DATAOUTWIDTH),
.ADDROUTWIDTH( ADDROUTWIDTH)
)
PingPangwrite0
(
.clka ( PixelClk ),
.clkb ( Clk200M ),
.ena ( wr_ena ),
.enb ( wr_enb ),
.sel ( wr_sel ), //select address to write or read
.Din ( wr_RamDin ),
.raddr ( wr_raddr ),
.Dout ( wr_RamDout )
);
3.2.1.3 实现方式
写模块采用乒乓RAM操作实现,输入时钟为输入视频的像素时钟DVIIN1_DCLK,输入使能信号为输入视频的数据有效信号DVIIN1_DE,奇数行数据存入RAM的低地址字段,偶数行数据存入RAM的高地址字段(使用检测模块的VerCnt的最低比特位进行选择)。输入的视频源数据为24bits,所以将高8bits补0组成32bits,然后输入该BRAM。
BRAM的读时钟使用DDR的User Clock,本设计中为200MHz。输出使能信号由Top层的写数据请求有效使能。输出的数据为512bits交给Top层写入DDR。
3.2.1.4 技术难点
● 乒乓操作的地址产生
● BRAM的输出勾选Output Registers,将输出数据再延迟一拍
3.2.2 写参数配置模块
3.2.2.1 模块功能
为写模块提供输入参数配置。
3.2.2.2 接口设计
图3-5 写参数配置模块顶层框图
写参数配置顶层框图如图3-5所示,其接口描述如下:
wrchannel
#
( .DATAINWIDTH ( DATAINWIDTH ) ,
.ADDRINWIDTH ( ADDRINWIDTH ) ,
.DATAOUTWIDTH( DATAOUTWIDTH ) ,
.ADDROUTWIDTH( ADDROUTWIDTH ) ,
.DDRADDRWIDTH( DDRADDRWIDTH ) ,
.WRLENWIDTH ( WRLENWIDTH ) ,
.COL_WIDTH ( COL_WIDTH ) ,
.DATALENGTH ( DATALENGTH )
)
wrchannel0
(
.wr_clk ( wr_clk ) ,
.DE ( DE ) ,
.wr_sel ( wr_sel ) ,
.wr_burst_begin ( wr_burst_begin ) ,
.wr_len ( wr_len ) ,
.wr_addr ( wr_addr ) ,
.wr_buf_sel ( wr_buf_sel ) ,
.wr_buf_base ( wr_buf_base )
);
3.2.2.3 实现方式
输入时钟为输入视频源的像素时钟,wr_sel为写请求从外部写通道ram取数的最高位地址。wr_burst_begin表示一次写请求(最大支持16个连续的wr_burst_begin高电平),采用DVIIN1_DE的下降沿产生一个高电平脉冲信号。wr_len表示写入数据的长度(数据宽度为512bits),而视频源的数据位宽为32bits,为了保证可以存入一行,所以本设计对行像素除以16得到写数据长度,计算公式为wr_len =HorPix>>4。由于DDR的一页为2KB,而1080P的视频一行最少也需要7.5KB,也就是说至少需要4页来保存。wr_addr的最低位10bits为0,表示一页的存储容量,每存储一行,将wr_addrcnt加一,然后左移2位就可以实现递增为4页地址的目的,计算公式为wr_addr={(wr_addrcnt<<2),10'b0}。wr_buf_sel即乒乓操作的地址最高位。wr_buf_base写请求从写通道ram取数据的起始地址,本设计中可以使之默认值0x00。
3.2.2.4 技术难点
● 写长度的计算
● 写DDR地址的计算,可以提高DDR的效率
3.2.3 读模块
3.2.3.1 模块功能
从DDR读出视频数据。
3.2.3.2 接口设计
图3-6 读模块顶层框图
读模块顶层框图如图3-6所示,其接口描述如下:
PingPangRd
#
(
.DATAINWIDTH ( DATAINWIDTH ),
.ADDRINWIDTH ( ADDRINWIDTH ),
.DATAOUTWIDTH( DATAOUTWIDTH),
.ADDROUTWIDTH( ADDROUTWIDTH)
)
PingPangread0
(
.clka ( Clk200M ),
.clkb ( rd_data_clk ),
.ena ( rd_ena ),
.enb ( DE ),
.Din ( rd_RamDin ),
.waddr ( rd_raddr ),
.Dout ( rd_RamDout ),
.valid ( rd_valid )
);
3.2.3.3 实现方式
User Clock,本设计中为200MHz。输入数据有效使能,由Top层控制。输入的数据为512bits,输入地址为9位,也是由Top层控制。
读模块的输出数据时钟为PLL将视频源随路时钟1比1倍频出来的时钟,因为本设计采用写一行读一行的设计,所以读模块的输出使能需要将写使能延迟行像素个时钟周期。读模块的地址为13位,每读取一行,都从地址0开始重新读。输出的数据为32bits,valid为数据的输出有效信号。
3.2.3.4 技术难点
● 输出数据时钟的选择
● 读数据地址的控制,因为未采用乒乓操作,所以每次读完之后也要从地址0开始
3.2.4 读参数配置模块
3.2.4.1 模块功能
为读模块提供输入参数配置。
3.2.4.2 接口设计
图3-7 读参数配置模块顶层框图
读参数配置模块顶层框图如图3-6所示,其接口描述如下:
rdchannel
#
(
.DDRADDRWIDTH ( DDRADDRWIDTH ) ,
.RDLENWIDTH ( RDLENWIDTH ) ,
.COL_WIDTH ( COL_WIDTH ) ,
.RDOPTWIDTH ( RDOPTWIDTH ) ,
.DATALENGTH ( DATALENGTH )
)
rdchannel0
(
.rd_clk ( rd_clk ) ,
.DE ( DE ) ,
.rd_burst_begin( rd_burst_begin ) ,
.rd_len ( rd_len ) ,
.rd_addr ( rd_addr ) ,
.rd_opt ( rd_opt )
);
3.2.4.3 实现方式
读参数配置模块的输入时钟为DDR的User Clock,rd_burst_begin表示读请求有效信号,一个rd_clk的高电平代表一次读请求。最大支持16个连续的rd_burst_begin高电平。因为读请求需要在写请求之后,所以这里将DE的下降沿高脉冲延迟一个时钟周期就可以实现。rd_len表示读出数据的长度(数据宽度为512bits),与写数据长度类似,也是使用行像素除以16得到。rd_addr表示从DDR中读数据的地址,与写DDR地址对应,地址计算公式为rd_addr = {(rd_addrcnt<<2),10'b0}。rd_opt为预留信号,这里不作阐述。
3.2.4.4 技术难点
● 读请求的产生,必须在写请求之后,因为Top层的读请求优先,必须保证先写后读
3.2.5 TOP模块
使用已有的模块,对MIG核再次进行了封装,详细参考ddr_top使用介绍。
3.2.6 MIG接口模块
3.2.6.1 MIG核的时钟模块
如图3-8所示,MIG核有一对差分的输入系统时钟SYSCKN和SYSCKP,经过内部的PLL倍频出来FPGA内部的逻辑时钟、写通道IO逻辑时钟、读通道IO逻辑时钟和延迟逻辑,另外MIG核还有一个IDELAY的参考时钟,本设计在IP选择时候勾选的参考时钟使用User Clock。
图3-8 MIG核的时钟网络
3.2.6.2 接口设计
对于使用IP的开发人员来说,不需要关注mem_infc与DDR的物理层实现,只需要了解ui_top和mem_infc之间的连接关系。
图3-9 MIG核的接口
1)app_addr:操作地址,按照结构从高位到低位是rank + bank + row + column。
2)app_cmd:操作命令, 3'b000表示写入,3'b001表示读出(注意:要和操作地址同时出现才有效)。
3)app_en:操作地址app_addr的使能,只有它拉高的时候,对应的app_addr才是有效的。
4)app_rdy:表示可以接收命令进行响应。
5)app_wdf_data:写入的数据接口。
6)app_wdf_end:表示输入的最后一个数据为高脉冲。
7)app_wdf_wren:写入的数据接口app_wdf_data的使能,只有它拉高的时候,对应的app_wdf_data才是有效的。
3.3 输出模块
3.3.1 模块功能
将内部视频输出到显示器。
3.3.2 实现方式
输入时钟Clk148M5是PLL将输入时钟进行1比1倍频出来的,Clk148M5Drg90是将Clk148M5进行了90°相位移动。DVIIN1_VS、DVIIN1_HS、DVIIN1_DE、DVIIN1_DATA都是从DDR中输出的。DVIOUT1_DCLK是通过ODDR原语将输入的Clk148M5Drg90双倍速率作为输出视频的时钟。DVIOUT_VS、DVIOUT_HS、DVIOUT_DE、DVIOUT_DATA是通过ODDR原语将DVIIN1_VS、DVIIN1_HS、DVIIN1_DE、DVIIN1_DATA在时钟Clk148M5的边沿双倍速率输出信号。
3.3.3 接口设计
图3-10 输出模块顶层框图
输出模块的实现顶层框图如图3-9所示,其DVI输出接口描述如下:
3.3.4 技术难点
● 输出的时钟不是精确的148.5MHz,因为有一个90°偏移的相位关系,所以会导致VCO锁存输出时钟的时候的真实值不是148.5MHz
● ODDR的对齐方式为Same Edge,同步接口设计
4. 结果分析
检测模块的结果如图4-1所示,视频源推送的是59.94Hz的1024x768分辨率的视频,可以正常检测出来结果。
图4-1 检测模块
不同分辨率不同帧频的视频源输出结果如图4-2(a)(b)(c)所示
图4-2 (a)800x600@75Hz (b)1280x720@60Hz (c)1920x1080@60Hz
表4-1列出了各个模块的资源利用情况。
表4-1 资源利用率