zoukankan      html  css  js  c++  java
  • 基于Modelsim的视频流仿真

    一、前言

      最近在看牟新刚写的《基于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文件分析,该部分代码主要用于实现图一中视频流的模拟时序包括行/场信号的生成及像素数据的生成。

      1 /*
      2 ***********************************************************************************************************
      3 **    Input file: None
      4 **    Component name: image_src.v
      5 **    Author:    zhengXiaoliang
      6 **  Company: WHUT
      7 **    Description: to simulate dvd stream
      8 ***********************************************************************************************************
      9 */
     10 
     11 `timescale 1ns/1ns
     12 
     13 `define SEEK_SET 0 
     14 `define SEEK_CUR 1
     15 `define SEEK_END 2
     16 
     17 module image_src(
     18     reset_l,        //全局复位
     19     clk,            //同步时钟
     20     src_sel,        //数据源通道选择
     21     test_vsync,        //场同步输出
     22     test_dvalid,     //像素有效输出
     23     test_data,        //像素数据输出
     24     clk_out            //像素时钟输出
     25 );
     26 
     27 parameter iw = 640;        //默认视频宽度
     28 parameter ih = 512;        //默认视频高度
     29 parameter dw = 8;        //默认像素数据位宽
     30 
     31 parameter h_total = 1440;    //行总数
     32 parameter v_total = 600;    //垂直总数
     33 
     34 parameter sync_b = 5;        //场前肩
     35 parameter sync_e = 55;        //场同步脉冲
     36 parameter vld_b = 65;        //场后肩
     37 
     38 //port decleared
     39 input reset_l,clk;
     40 input [3:0] src_sel;    //to select the input file
     41 output test_vsync, test_dvalid,clk_out;
     42 output [dw-1:0] test_data;
     43 
     44 
     45 //variable decleared
     46 reg [dw-1:0] test_data_reg;
     47 reg test_vsync_temp;
     48 reg test_dvalid_tmp;
     49 reg [1:0] test_dvalid_r;
     50 
     51 reg [10:0] h_cnt;
     52 reg [10:0] v_cnt;
     53 
     54 integer fp_r;
     55 integer cnt = 0;
     56 
     57 //输出像素时钟
     58 assign clk_out = clk;    //output the dv clk
     59 
     60 //输出像素数据
     61 assign test_data = test_data_reg; //test data output 
     62 
     63 //当行同步有效时,从文件读取像素数据输出到数据线上
     64 always@(posedge clk or posedge test_vsync_temp)begin
     65     if(((~(test_vsync_temp))) == 1'b0) //场同步清零文件指针
     66         cnt <= 0; //clear file pointer when a new frame comes
     67     else begin
     68         if(test_dvalid_tmp == 1'b1)begin //行同步有效,说明当前时钟数据有效
     69             case(src_sel) //选择不同的数据源
     70                 4'b0000: fp_r = $fopen("E:/Modelsim/image_src/txt_source/test_src3.txt","r");
     71                 4'b0001: fp_r = $fopen("txt_source/test_scr1.txt","r");
     72                 4'b0010: fp_r = $fopen("txt_source/test_scr2.txt","r");
     73                 4'b0011: fp_r = $fopen("txt_source/test_scr3.txt","r");
     74                 4'b0100: fp_r = $fopen("txt_source/test_scr4.txt","r");
     75                 4'b0101: fp_r = $fopen("txt_source/test_scr5.txt","r");
     76                 4'b0110: fp_r = $fopen("txt_source/test_scr6.txt","r");
     77                 4'b0111: fp_r = $fopen("txt_source/test_scr7.txt","r");
     78                 4'b1000: fp_r = $fopen("txt_source/test_scr8.txt","r");
     79                 4'b1001: fp_r = $fopen("txt_source/test_scr9.txt","r");
     80                 4'b1010: fp_r = $fopen("txt_source/test_scr10.txt","r");
     81                 4'b1011: fp_r = $fopen("txt_source/test_scr11.txt","r");
     82                 4'b1100: fp_r = $fopen("txt_source/test_scr12.txt","r");
     83                 4'b1101: fp_r = $fopen("txt_source/test_scr13.txt","r");
     84                 4'b1110: fp_r = $fopen("txt_source/test_scr14.txt","r");
     85                 4'b1111: fp_r = $fopen("txt_source/test_scr15.txt","r");
     86                 default: fp_r = $fopen("txt_source/test_src3.txt","r");
     87             endcase
     88             
     89             $fseek(fp_r,cnt,`SEEK_SET); //查找当前需要读取的文件位置
     90             $fscanf(fp_r,"%02x
    ",test_data_reg); //将数据按指定格式读入test_data_reg寄存器
     91         
     92             cnt <= cnt + 4; //移动文件指针到下一个数据
     93             $fclose(fp_r); //关闭文件
     94             $display("h_cnt = %d,v_cnt = %d, pixdata = %d",h_cnt,v_cnt,test_data_reg); //for debug use    
     95         end    
     96     end
     97 end
     98 
     99 //水平计数器,每来一个时钟就+1,加到h_total置零重新计数
    100 always@(posedge clk or negedge reset_l)begin
    101     if(((~(reset_l))) == 1'b1)
    102         h_cnt <= #1 {11{1'b0}};
    103     else begin
    104         if(h_cnt == ((h_total -1)))
    105             h_cnt <= #1 {11{1'b0}};
    106         else
    107             h_cnt <= #1 h_cnt + 11'b00000000001;
    108     end
    109 end
    110 
    111 //垂直计数器:水平计数器计满后+1,计满后清零
    112 always@(posedge clk or negedge reset_l)begin
    113     if(((~(reset_l))) == 1'b1)
    114         v_cnt <= #1 {11{1'b0}};
    115     else begin
    116         if(h_cnt == ((h_total - 1)))begin
    117             if(v_cnt == ((v_total - 1)))
    118                 v_cnt <= #1 {11{1'b0}};
    119             else
    120                 v_cnt <= #1 v_cnt + 11'b00000000001;
    121         end
    122     end
    123 end
    124 
    125 //场同步信号生成
    126 always@(posedge clk or negedge reset_l)begin
    127     if(((~(reset_l))) == 1'b1)
    128         test_vsync_temp <= #1 1'b1;
    129     else begin
    130         if(v_cnt >= sync_b & v_cnt <= sync_e)
    131             test_vsync_temp <= #1 1'b1;
    132         else
    133             test_vsync_temp <= #1 1'b0;
    134     end
    135 end
    136 
    137 assign test_vsync = (~test_vsync_temp);
    138 
    139 //水平同步信号生成
    140 always@(posedge clk or negedge reset_l)begin
    141     if(((~(reset_l))) == 1'b1)
    142         test_dvalid_tmp <= #1 1'b0;
    143     else begin
    144         if(v_cnt >= vld_b & v_cnt < ((vld_b + ih)))begin
    145             if(h_cnt == 10'b0000000000)
    146                 test_dvalid_tmp <= #1 1'b1;
    147             else if(h_cnt == iw)
    148                 test_dvalid_tmp <= #1 1'b0;    
    149         end
    150         else 
    151             test_dvalid_tmp <= #1 1'b0;
    152     end
    153 end
    154 
    155 //水平同步信号输出
    156 assign test_dvalid = test_dvalid_tmp;
    157 
    158 always@(posedge clk or negedge reset_l)begin
    159     if(((~(reset_l))) == 1'b1)
    160         test_dvalid_r <= #1 2'b00;
    161     else
    162         test_dvalid_r <= #1 ({test_dvalid_r[0],test_dvalid_tmp});
    163 end
    164 
    165 endmodule

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

     1 `timescale 1ns/1ns
     2 
     3 module image_src_tb;
     4 
     5 parameter iw = 640;        //图像宽度
     6 parameter ih = 512;     //图像高度
     7 parameter dvd_dw = 8;    //数据位宽
     8 
     9 //视频时序参数
    10 parameter h_total = 1440;
    11 parameter v_total = 600;
    12 parameter sync_b = 5;
    13 parameter sync_e = 55;
    14 parameter vld_b = 65;
    15 
    16 reg clk;
    17 reg reset_l;
    18 
    19 wire dv_clk;
    20 wire dvsyn;
    21 wire dhsyn;
    22 wire [dvd_dw-1:0] dvd;
    23 
    24 /*根据时序参数例化一个视频源*/
    25 image_src #(iw,ih,dvd_dw,h_total,v_total,sync_b,sync_e,vld_b)
    26 image_src_ins(
    27     .clk(clk),
    28     .reset_l(reset_l),
    29     .src_sel(4'b0000),
    30     .test_data(dvd),
    31     .test_dvalid(dhsyn),
    32     .test_vsync(dvsyn),
    33     .clk_out(dv_clk)
    34 );
    35 
    36 initial begin
    37     clk = 0;
    38     reset_l = 1;
    39     #100;
    40     reset_l = 0;
    41     #100;
    42     reset_l = 1;
    43 end
    44 
    45 //时钟产生:≈51.84MHz
    46 always@(reset_l or clk)begin
    47     if((~(reset_l)) == 1'b1)
    48         clk <= 1'b0;
    49     else
    50         clk <= #9645 (~(clk));
    51 end
    52 
    53 endmodule

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

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

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

     1 #切换至工程目录
     2 cd E:/Modelsim/image_src
     3 
     4 #打开工程
     5 project open E:/Modelsim/image_src
     6 
     7 #编译相关文件(一般情况下为频繁改动的文件)
     8 vlog E:/Modelsim/image_src/image_src.v
     9 vlog E:/Modelsim/image_src/image_src_tb.v
    10 
    11 #开始仿真
    12 vsim -novopt -L altera_lib work.image_src_tb
    13 
    14 #添加顶层所有的信号
    15 add wave *
    16 
    17 #取消警告
    18 set StdArithNoWarnings 1
    19 
    20 #开始运行
    21 run -all

    四、仿真结果

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

     

    初入江湖,天下无敌;再学三年,寸步难行。
  • 相关阅读:
    http://www.cplusplus.com/reference/string/string/find_last_of/

    SQL Server数据库设计表和字段的经验
    AMP产品识别
    水晶头AMP识别
    双绞线的规范和制作经验谈
    VB.net 产生随机验证码
    手把手教您架设Windows2003共享服务器
    使用EasyRecovery Pro 6.04恢复RAW格式硬盘的数据实战
    .NET中各种数据库连接大全
  • 原文地址:https://www.cnblogs.com/huangwei0521/p/12317354.html
Copyright © 2011-2022 走看看