一、前言

  最近在看牟新刚写的《基于FPGA的数字图像处理原理及应用》,书中关于FPGA数字图像处理的原理的原理写的非常透彻,在网上寻找了很久都没有找到完整的源代码工程,因此尝试自己做了补充/仿真,并与书中结果进行了比对。2020-02-16 15:40:21

二、视频时序模拟

  如图一所示,为参考书中的代码及说明整理出来的时序图,其中仿真视频图像宽度(IW=640),高度(IH=512),sync_b为场前肩参数,sync_e为场同步脉冲参数,vld为场后肩参数。从时序图中可以看出dvsync标记了一副新图像的起始点,书中并没有标记图像传输结束到下一帧图像开始(图像的场前肩)需要多少时间,通过v_total可以计算出有23行图像的时间(不知道实际场景下这个参数是否也是按照v_total来换算)。同理书中也没有标注sync_h(行消隐脉冲的时间),通过计算可知为(h_total-640)=800个像素时钟。

三、代码注解与分析

  (1)image_src.v文件分析,该部分代码主要用于实现图一中视频流的模拟时序包括行/场信号的生成及像素数据的生成。

 /*
***********************************************************************************************************
** Input file: None
** Component name: image_src.v
** Author: zhengXiaoliang
** Company: WHUT
** Description: to simulate dvd stream
***********************************************************************************************************
*/ `timescale 1ns/1ns `define SEEK_SET 0
`define SEEK_CUR
`define SEEK_END module image_src(
reset_l, //全局复位
clk, //同步时钟
src_sel, //数据源通道选择
test_vsync, //场同步输出
test_dvalid, //像素有效输出
test_data, //像素数据输出
clk_out //像素时钟输出
); parameter iw = ; //默认视频宽度
parameter ih = ; //默认视频高度
parameter dw = ; //默认像素数据位宽 parameter h_total = ; //行总数
parameter v_total = ; //垂直总数 parameter sync_b = ; //场前肩
parameter sync_e = ; //场同步脉冲
parameter vld_b = ; //场后肩 //port decleared
input reset_l,clk;
input [:] src_sel; //to select the input file
output test_vsync, test_dvalid,clk_out;
output [dw-:] test_data; //variable decleared
reg [dw-:] test_data_reg;
reg test_vsync_temp;
reg test_dvalid_tmp;
reg [:] test_dvalid_r; reg [:] h_cnt;
reg [:] v_cnt; integer fp_r;
integer cnt = ; //输出像素时钟
assign clk_out = clk; //output the dv clk //输出像素数据
assign test_data = test_data_reg; //test data output //当行同步有效时,从文件读取像素数据输出到数据线上
always@(posedge clk or posedge test_vsync_temp)begin
if(((~(test_vsync_temp))) == 'b0) //场同步清零文件指针
cnt <= ; //clear file pointer when a new frame comes
else begin
if(test_dvalid_tmp == 'b1)begin //行同步有效,说明当前时钟数据有效
case(src_sel) //选择不同的数据源
'b0000: fp_r = $fopen("E:/Modelsim/image_src/txt_source/test_src3.txt","r");
'b0001: fp_r = $fopen("txt_source/test_scr1.txt","r");
'b0010: fp_r = $fopen("txt_source/test_scr2.txt","r");
'b0011: fp_r = $fopen("txt_source/test_scr3.txt","r");
'b0100: fp_r = $fopen("txt_source/test_scr4.txt","r");
'b0101: fp_r = $fopen("txt_source/test_scr5.txt","r");
'b0110: fp_r = $fopen("txt_source/test_scr6.txt","r");
'b0111: fp_r = $fopen("txt_source/test_scr7.txt","r");
'b1000: fp_r = $fopen("txt_source/test_scr8.txt","r");
'b1001: fp_r = $fopen("txt_source/test_scr9.txt","r");
'b1010: fp_r = $fopen("txt_source/test_scr10.txt","r");
'b1011: fp_r = $fopen("txt_source/test_scr11.txt","r");
'b1100: fp_r = $fopen("txt_source/test_scr12.txt","r");
'b1101: fp_r = $fopen("txt_source/test_scr13.txt","r");
'b1110: fp_r = $fopen("txt_source/test_scr14.txt","r");
'b1111: fp_r = $fopen("txt_source/test_scr15.txt","r");
default: fp_r = $fopen("txt_source/test_src3.txt","r");
endcase $fseek(fp_r,cnt,`SEEK_SET); //查找当前需要读取的文件位置
$fscanf(fp_r,"%02x\n",test_data_reg); //将数据按指定格式读入test_data_reg寄存器 cnt <= cnt + ; //移动文件指针到下一个数据
$fclose(fp_r); //关闭文件
$display("h_cnt = %d,v_cnt = %d, pixdata = %d",h_cnt,v_cnt,test_data_reg); //for debug use
end
end
end //水平计数器,每来一个时钟就+1,加到h_total置零重新计数
always@(posedge clk or negedge reset_l)begin
if(((~(reset_l))) == 'b1)
h_cnt <= # {{'b0}};
else begin
if(h_cnt == ((h_total -)))
h_cnt <= # {{'b0}};
else
h_cnt <= # h_cnt + 'b00000000001;
end
end //垂直计数器:水平计数器计满后+1,计满后清零
always@(posedge clk or negedge reset_l)begin
if(((~(reset_l))) == 'b1)
v_cnt <= # {{'b0}};
else begin
if(h_cnt == ((h_total - )))begin
if(v_cnt == ((v_total - )))
v_cnt <= # {{'b0}};
else
v_cnt <= # v_cnt + 'b00000000001;
end
end
end //场同步信号生成
always@(posedge clk or negedge reset_l)begin
if(((~(reset_l))) == 'b1)
test_vsync_temp <= # 'b1;
else begin
if(v_cnt >= sync_b & v_cnt <= sync_e)
test_vsync_temp <= # 'b1;
else
test_vsync_temp <= # 'b0;
end
end assign test_vsync = (~test_vsync_temp); //水平同步信号生成
always@(posedge clk or negedge reset_l)begin
if(((~(reset_l))) == 'b1)
test_dvalid_tmp <= # 'b0;
else begin
if(v_cnt >= vld_b & v_cnt < ((vld_b + ih)))begin
if(h_cnt == 'b0000000000)
test_dvalid_tmp <= # 'b1;
else if(h_cnt == iw)
test_dvalid_tmp <= # 'b0;
end
else
test_dvalid_tmp <= # 'b0;
end
end //水平同步信号输出
assign test_dvalid = test_dvalid_tmp; always@(posedge clk or negedge reset_l)begin
if(((~(reset_l))) == 'b1)
test_dvalid_r <= # 'b00;
else
test_dvalid_r <= # ({test_dvalid_r[],test_dvalid_tmp});
end endmodule

  (2)视频流仿真代码image_src_tb.v的补充编写。

 `timescale 1ns/1ns

 module image_src_tb;

 parameter iw = ;        //图像宽度
parameter ih = ; //图像高度
parameter dvd_dw = ; //数据位宽 //视频时序参数
parameter h_total = ;
parameter v_total = ;
parameter sync_b = ;
parameter sync_e = ;
parameter vld_b = ; reg clk;
reg reset_l; wire dv_clk;
wire dvsyn;
wire dhsyn;
wire [dvd_dw-:] dvd; /*根据时序参数例化一个视频源*/
image_src #(iw,ih,dvd_dw,h_total,v_total,sync_b,sync_e,vld_b)
image_src_ins(
.clk(clk),
.reset_l(reset_l),
.src_sel('b0000),
.test_data(dvd),
.test_dvalid(dhsyn),
.test_vsync(dvsyn),
.clk_out(dv_clk)
); initial begin
clk = ;
reset_l = ;
#;
reset_l = ;
#;
reset_l = ;
end //时钟产生:≈51.84MHz
always@(reset_l or clk)begin
if((~(reset_l)) == 'b1)
clk <= 'b0;
else
clk <= # (~(clk));
end endmodule

  (3)视频码流文件的生成,由于书中并没有描述如何生成视频码流的文件,因此用Maltab编写了一个rgb2txt文件,生成了一份码流文件经过测试可用。

 %将256位的BMP灰度图像128*128大小生成TXT文档;
clc
close all I_rgb = imread('lena_512x512.jpg');
subplot(1,3,1),imshow(I_rgb),title('lena-rgb') I_gray = rgb2gray(I_rgb);
subplot(1,3,2),imshow(I_gray),title('lena-gray') %% 改变图像尺寸
I_resize = imresize(I_gray,[640 512],'nearest');%nearest(默认值) 最近邻插值 ‘bilinear’双线性插值 ‘bicubic’ 双三次插值
% I = imresize(I_gray,0.25);
% subplot(1,3,3),imshow(I),title('lena-qtr') fid = fopen('./lena_640x512_hex.txt','wt');
for i = 1:size(I_resize,1)
for j = 1:size(I_resize,2)
fprintf(fid,'%2x\n',I_resize(i,j));%每个数据之间用空格分开
end
%fprintf(fid,'\n');
end fid = fclose(fid);
I_data = load('./lena_640x512.txt');

  (4)用于Modelsim仿真的.do文件的编写,image_src.do代码如下:

 #切换至工程目录
cd E:/Modelsim/image_src #打开工程
project open E:/Modelsim/image_src #编译相关文件(一般情况下为频繁改动的文件)
vlog E:/Modelsim/image_src/image_src.v
vlog E:/Modelsim/image_src/image_src_tb.v #开始仿真
vsim -novopt -L altera_lib work.image_src_tb #添加顶层所有的信号
add wave * #取消警告
set StdArithNoWarnings #开始运行
run -all

四、仿真结果

  如图二所示,为测试仿真结果与书中仿真结果图像一致。

基于Modelsim的视频流仿真的更多相关文章

  1. 基于Modelsim的直方图统计算法仿真

    一.前言 本篇主要针对牟新刚编著<基于FPGA的数字图像处理及应用>第六章第五节中直方图统计相关类容进行总结,包括代码实现及 基于Modelsim的仿真.书读百遍,其意自现. 2020-0 ...

  2. Modelsim使用流程---基于TCL命令的仿真

    Modelsim使用流程---基于TCL命令的仿真 本文使用的Modelsim版本为Modelsim SE-64 10.1.c 1.File -> new -> Project 2.添加或 ...

  3. 基于modelsim-SE的简单仿真流程—下

    基于modelsim-SE的简单仿真流程—下 编译 在 WorkSpace 窗口的 counter_tst.v上点击右键,如果选择Compile selected 则编译选中的文件,Compile A ...

  4. 基于modelsim-SE的简单仿真流程—上

    基于modelsim-SE的简单仿真流程 编写RTL功能代码 要进行功能仿真,首先得用需要仿真的模块,也就是RTL功能代码,简称待测试的模块,该模块也就是在设计下载到FPGA的电路.一个电路模块想要有 ...

  5. 通过文件读写方式实现Matlab和Modelsim的联合仿真

    虽然Modelsim的功能非常强大,仿真的波形可以以多种形式进行显示,但是当涉及到数字信号处理的算法的仿真验证的时候,则显得有点不足.而进行数字信号处理是Matlab的强项,不但有大量的关于数字信号处 ...

  6. vivado和modelsim联合调试仿真

    vivado和modelsim联合调试仿真 0赞 发表于 2017/5/10 19:10:59 阅读(881) 评论(0) 使用vivado和modelsim联合调试仿真时,在破解完modelsim后 ...

  7. Modelsim SE自动化仿真——如何将.do文件中自定义的库链接到testbench顶层模块

    我们用Modelsim SE进行仿真时,为了方便,一般会编写.do文件来启动当前仿真.关于.do文件的编写,一般网上都有成型的模板,我们只要稍微改几个参数,就可以符合我们的仿真需求了.但是如果仿真时需 ...

  8. 用Modelsim SE 直接仿真 Altera(Intel PSG) IP核 需要注意的问题

    如果我们直接用Modelsim SE仿真 Altera IP核,首先会进入Quartus II目录下找到IP核对应的仿真库源文件,然后在Modelsim SE中进行编译,添加到Modelsim SE的 ...

  9. vivado与modelsim的联合仿真(二)

     最近在做Zynq的项目,曾经尝试使用ISE+PlanAhead+XPS+SDK组合和Vivado+SDK来搭建工程,使用中发现前者及其不方便后者有诸多不稳定.近期得闻Xilinx退出Vivado20 ...

随机推荐

  1. python 的头文件包含问题

    一个python项目中一个文件需要引用另一个文件中的类,遇到的几个问题,总结如下: 0x01 情况一:在同一目录下 project |--a.py |--b.py |--main.py 在main.p ...

  2. js和jsp中怎么去获取后台 model.addAttribute()存入的list<。。。>对象

    java 后台List productionGroupList =getProductionGroupList(); model.addAttribute("productionGroupL ...

  3. HttpClient的CircularRedirectException解决办法

    解决方法: HttpGet httpGet = new HttpGet(" http://XXXX.XXX"); httpGet.getParams().setParameter( ...

  4. python基础之函数,递归,内置函数

    一.数学定义的函数与python中的函数 初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因 ...

  5. Python函数基础进阶

    函数参数的另一种使用方式 def print_info(name,age): print("Name: %s" %name) print("age: %d" % ...

  6. MAC Address-Table Move Update Feature

    MAC Address-Table Move Update The MAC address-table move update feature allows the switch to provide ...

  7. PS绘制Logo

    1. 2. 3. 4. 5. 6. 第2步点击“圆1”应点击图层左边的缩览图才能获取选区 7. 8. 9. 10. 11. 12.

  8. POJ 1061 青蛙的约会(exgcd)

    嗯... 题目链接:http://poj.org/problem?id=1061 两只青蛙相遇时肯定满足:x+k*m≡y+k*n(mod L) x+k*m-(y+k*n)=L*s k*(n-m)-s* ...

  9. 页面弹窗toast和加载loading

    create-at 2019-04-04 都采用单例模式,原生js实现 兼容老版本浏览器内核,请将用es6语法的地方作修改 loading 加载 代码: 样式全部通过js创建style标签注入head ...

  10. 实现一个简易的Unity网络同步引擎——netgo

    实现一个简易的Unity网络同步引擎Netgo 目前GOLANG有大行其道的趋势,尤其是在网络编程方面.因为和c/c++比较起来,虽然GC占用了一部分机器性能,但是出错概率小了,开发效率大大提升,而且 ...