FPGA视频仿真技术应用

1.仿真测试系统框架

仿真测试系统所包含的功能:

(1)模拟可配置的视频流(单帧的视频即为一副图像)

(2)模拟视频捕获,生成视频数据

(3)测试系统与testbench及视频流的数据共享

(4)可视化的图像及视频操作

(5)对FPGA的处理结果进行验证

仿真测试系统结构如下图所示:

FPGA视频仿真_视频流

上面是从书上的截图,这里我将Qt测试程序代替MFC测试程序。

仿真测试系统由Qt平台和Modelsim共同搭建完成。模拟测试的完整过程如下:

1.Qt将一张图片所有的RGB颜色信息存储在文本中。

2.modelsim模拟视频流传输,读取(1)中图像信息生成视频流,并模拟捕获视频流,并将这些图像信息写入另一个文本中。

3.Qt将模拟捕获的图像文本信息读取并生成图像。

通过以上可知,Qt平台与FPGA模拟视频流及处理结果通过文本实现数据共享。


2 视频时序模拟


2.1 基本视频时序

图2-1是一个典型的CMOS视频输出时序图:

FPGA视频仿真_sed_02

图2-1

下面是上面时序各个信号的说明:

(1)HSYNC:行同步信号

(2)FILED:场信号,表示当前的场是奇数场还是偶数场

(3)VSYNC:帧同步信号

(4)CLK:像素时钟即PCLK

(5)DATA:有效像素数据,仅在行同步有效时才有效

(6)h_totol:一行的总像素个数

(7)v_totol:一副图像总的行数

(8)sync_h:行消隐

(9)sync_v:场同步脉冲

(10)torch_f:场前肩

(11)torch_b:场后肩


2.2 Verilog示例代码

参考书上的代码,我自己实现了上述视频流的模拟时序(像素数据从文本中得到,一个像素RGB各占一行)

这里自定义模拟视频流的参数信息如下:

图像有效宽度iw = 640;

图像有效高度ih = 480;

一行总像素个数h_total = 2000;

总行数v_total = 600 ;

场前肩torch_f = 5;

场同步脉冲sync_v = 20;

场后肩torch_b = 20;


/************************************************************************ * Author        : Ye Qiang * Email         : 1247836708@qq.com * Create time   : 2019-03-22 11:12 * Last modified : 2019-03-25 15:51 * Filename      : image_src.v * Description   :  * *********************************************************************/module  image_src(        input                   clk                             ,//系统时钟        input                   rst_n                           ,//系统复位        input         [ 3: 0]   src_sel                         ,//图像选择          output  wire            pclk                            ,//像素时钟        output  wire            Vsync                           ,//帧同步        output  reg             Hsync                           ,//行同步        output  wire  [ 7: 0]   img_data                         //8位图像数据);//======================================================================\//************** Define Parameter and Internal Signals *****************//======================================================================///图像大小为640x480,RGB格式parameter       iw              =       640*3                   ;//1920parameter       ih              =       480                     ;parameter       h_total         =       2000                    ;parameter       v_total         =       600                     ;parameter       torch_f         =       5                       ;//场前肩parameter       sync_v          =       20                      ;//场同步脉冲parameter       torch_b         =       20                      ;//场后肩parameter       sync_b          =       torch_f                 ;parameter       sync_e          =       sync_b+sync_v           ;parameter       vld_b           =       sync_e+torch_b          ;parameter       sync_h          =       h_total-iw              ;reg     [10: 0]                 h_cnt                           ;wire                            add_h_cnt                       ;wire                            end_h_cnt                       ;reg     [ 9: 0]                 v_cnt                           ;wire                            add_v_cnt                       ;wire                            end_v_cnt                       ;reg                             Hsync_temp                      ;reg                             Vsync_temp                      ;wire                            h_flag                          ;integer                         p_cnt = 0                       ;integer                         fp_r                            ;reg     [ 7: 0]                 test_data_reg                   ;//======================================================================\//**************************** Main Code *******************************//======================================================================/assign  pclk        =           clk                             ;//h_cntalways @(posedge clk or negedge rst_n)begin     if(!rst_n)begin        h_cnt <= 0;    end    else if(add_h_cnt)begin        if(end_h_cnt)            h_cnt <= 0;        else            h_cnt <= h_cnt + 1;    endendassign  add_h_cnt        =       1'b1;assign  end_h_cnt        =       add_h_cnt && h_cnt == h_total-1;//v_cnt  行计数always @(posedge clk or negedge rst_n)begin    if(!rst_n)begin        v_cnt <= 0;    end    else if(add_v_cnt)begin        if(end_v_cnt)            v_cnt <= 0;        else            v_cnt <= v_cnt + 1;    endendassign  add_v_cnt        =       end_h_cnt;assign  end_v_cnt        =       add_v_cnt && v_cnt ==  v_total;//Vsync_tempalways  @(posedge clk or negedge rst_n)begin    if(!rst_n)begin        Vsync_temp <=  1'b1;    end    else if(v_cnt >= sync_b && v_cnt <= sync_e )begin        Vsync_temp <=  1'b0;    end    else begin        Vsync_temp <=  1'b1;    endendassign Vsync = Vsync_temp;//h_flagassign h_flag = (v_cnt >= vld_b) && (v_cnt < (vld_b+ih))        ;//Hsync_tempalways  @(posedge clk or negedge rst_n)begin    if(!rst_n)begin        Hsync_temp <=  1'b0;    end    else if(h_flag)begin        if(h_cnt == 0)begin            Hsync_temp <=  1'b1;          end        else if(h_cnt == iw)            Hsync_temp <=  1'b0;    end    else begin        Hsync_temp <=  1'b0;    endend//Hsyncalways  @(posedge clk or negedge rst_n)begin    if(!rst_n)begin        Hsync  <=  1'b0;    end    else begin        Hsync  <=  Hsync_temp;    endend//当行同步有效时,从文件读取像素数据输出到数据线上always  @(posedge clk or negedge rst_n)begin    if(!rst_n)begin        p_cnt   <=  0;        test_data_reg   <=  {8{1'b0}};    end    else if(Vsync_temp == 1'b0)begin        p_cnt   <=  0;    end    else begin        if(Hsync_temp)begin            case(src_sel)                4'b0000 :fp_r   =   $fopen("txt_source/test_src0.txt", "r");                4'b0001 :fp_r   =   $fopen("txt_source/test_src1.txt", "r");                4'b0010 :fp_r   =   $fopen("txt_source/test_src2.txt", "r");                4'b0011 :fp_r   =   $fopen("txt_source/test_src3.txt", "r");                4'b0100 :fp_r   =   $fopen("txt_source/test_src4.txt", "r");                4'b0101 :fp_r   =   $fopen("txt_source/test_src5.txt", "r");                4'b0110 :fp_r   =   $fopen("txt_source/test_src6.txt", "r");                4'b0111 :fp_r   =   $fopen("txt_source/test_src7.txt", "r");                4'b1000 :fp_r   =   $fopen("txt_source/test_src8.txt", "r");                4'b1001 :fp_r   =   $fopen("txt_source/test_src9.txt", "r");                4'b1010 :fp_r   =   $fopen("txt_source/test_src10.txt", "r");                4'b1011 :fp_r   =   $fopen("txt_source/test_src11.txt", "r");                4'b1100 :fp_r   =   $fopen("txt_source/test_src12.txt", "r");                4'b1101 :fp_r   =   $fopen("txt_source/test_src13.txt", "r");                4'b1110 :fp_r   =   $fopen("txt_source/test_src14.txt", "r");                4'b1111 :fp_r   =   $fopen("txt_source/test_src15.txt", "r");                default :fp_r   =   $fopen("txt_source/test_src0.txt", "r" );            endcase        $fseek(fp_r, p_cnt, 0);//查找当前需要读取的文件位置        $fscanf(fp_r, "%02x\n", test_data_reg);//将数据按指定格式读入test_data_reg寄存器        p_cnt <=  p_cnt + 4;//移动文件指针到下一个数据        $fclose(fp_r);//关闭文件        //$display("%02x", test_data_reg);        end    endendassign  img_data   =   test_data_reg                            ;endmodule1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.135.136.137.138.139.140.141.142.143.144.145.146.147.148.149.150.151.152.153.154.155.156.157.158.159.160.161.162.163.164.165.166.167.168.169.170.171.172.173.174.175.176.177.178.



3 视频捕获模拟

本模块的目的是对上一节产生的视频信号进行捕获并解析


3.1 完成内容

(1) 位宽转换:将八位视频流数据转换成24位数据。这里通过一个深度为1024的fifo来辅助实现

(2) 生成本地帧同步和行同步信号

(3) 将图像数据写入文本中,以供Qt平台读取显示


3.2 Verilog代码设计


/************************************************************************ * Author        : Ye Qiang * Email         : 1247836708@qq.com * Create time   : 2019-03-25 15:55 * Last modified : 2019-03-27 16:58 * Filename      : video_cap.v * Description   : video_cap * *********************************************************************/module  video_cap(        input                   pclk                            ,//像素时钟        input                   rst_n                           ,//系统复位        input                   Vsync                           ,//帧同步        input                   Hsync                           ,//行同步        input         [ 7: 0]   img_data                        ,//八位图像数据        input                   cap_clk                         ,//本地时钟        output  wire            cap_Vsync                       ,//本行帧同步        output  reg             cap_Hsync                       ,//本地行同步        output  wire  [23: 0]   cap_img_data                     //捕获的24位图像数据);//======================================================================\//************** Define Parameter and Internal Signals *****************//======================================================================/parameter       iw      =       10'd640                         ;parameter       ih      =       9'd480                          ;reg     [ 2: 0]                 cap_Vsync_r                     ;wire                            cap_Vsync_pos                   ;wire                            cap_Vsync_neg                   ;reg     [23: 0]                 fifo_in_data                    ;reg                             rdreq                           ;reg                             wrreq                           ;wire    [23: 0]                 fifo_out_data                   ;wire                            rdempty                         ;wire    [ 9: 0]                 rdusedw                         ;wire                            wrfull                          ;wire    [ 9: 0]                 wrusedw                         ;reg     [ 1: 0]                 pix_cnt                         ;wire                            add_pix_cnt                     ;wire                            end_pix_cnt                     ;reg     [ 9: 0]                 rdata_cnt                       ;wire                            add_rdata_cnt                   ;wire                            end_rdata_cnt                   ;//======================================================================\//**************************** Main Code *******************************//======================================================================///bit width conversion 8 to 24//pix_cntalways @(posedge pclk or negedge rst_n)begin    if(!rst_n)begin        pix_cnt <= 0;    end    else if(add_pix_cnt)begin        if(end_pix_cnt)            pix_cnt <= 0;        else            pix_cnt <= pix_cnt + 1;    endendassign  add_pix_cnt     =       Vsync && Hsync;       assign  end_pix_cnt     =       add_pix_cnt && pix_cnt == 3-1;   //fifo_in_dataalways  @(posedge pclk or negedge rst_n)begin    if(!rst_n)begin        fifo_in_data    <=  {24{1'b0}};    end    else if(add_pix_cnt)begin        fifo_in_data    <=  {fifo_in_data[15:0], img_data};    endend//wrreqalways  @(posedge pclk or negedge rst_n)begin    if(!rst_n)begin        wrreq   <=  1'b0;    end    else if(!wrfull && end_pix_cnt)begin        wrreq   <=  1'b1;    end    else begin        wrreq   <=  1'b0;    endend//rdreqalways  @(posedge cap_clk or negedge rst_n)begin    if(!rst_n)begin        rdreq   <=  1'b0;    end    else if(wrusedw == iw)begin        rdreq   <=  1'b1;    end    else if(end_rdata_cnt)begin        rdreq   <=  1'b0;    endend//cap_Vsync_ralways  @(posedge cap_clk or negedge rst_n)begin    if(!rst_n)begin        cap_Vsync_r <=  {3{1'b1}};    end    else begin        cap_Vsync_r <=  {cap_Vsync_r[1:0], Vsync};    endendassign  cap_Vsync   =   cap_Vsync_r[2]                          ;assign  cap_Vsync_neg   =   cap_Vsync_r[2] && ~cap_Vsync_r[1]   ;assign  cap_Vsync_pos   =   ~cap_Vsync_r[2] && cap_Vsync_r[1]   ;//cap_Hsyncalways  @(posedge cap_clk or negedge rst_n)begin    if(!rst_n)begin        cap_Hsync   <=  1'b0;    end    else begin        cap_Hsync   <=  rdreq;    endend//rdata_cntalways @(posedge cap_clk or negedge rst_n)begin    if(!rst_n)begin        rdata_cnt <= 0;    end    else if(add_rdata_cnt)begin        if(end_rdata_cnt)            rdata_cnt <= 0;        else            rdata_cnt <= rdata_cnt + 1;    endendassign  add_rdata_cnt       =       rdreq;       assign  end_rdata_cnt       =       add_rdata_cnt && rdata_cnt == iw-1;   //cap_img_dataassign  cap_img_data        =       fifo_out_data               ;//将图像数据写入文本integer             fp_w                                        ;integer             p_cnt                                       ;reg     [ 3: 0]                 v_pos_cnt                       ;wire                            add_v_pos_cnt                   ;wire                            end_v_pos_cnt                   ;//v_pos_cntalways @(posedge cap_clk or negedge rst_n)begin    if(!rst_n)begin        v_pos_cnt <= 0;    end    else if(add_v_pos_cnt)begin        if(end_v_pos_cnt)            v_pos_cnt <= 0;        else            v_pos_cnt <= v_pos_cnt + 1;    endendassign  add_v_pos_cnt     =       cap_Vsync_pos;       assign  end_v_pos_cnt     =       add_v_pos_cnt && v_pos_cnt == 4-1;   //当行同步有效时,从文件读取像素数据输出到数据线上always  @(posedge cap_clk or negedge rst_n)begin    if(!rst_n)begin        p_cnt   <=  0;    end    else if(cap_Vsync_pos)begin        p_cnt   <=  0;        case(v_pos_cnt)            4'd0:   fp_w   =   $fopen("txt_result/imgDataOut0.txt", "w");            4'd1:   fp_w   =   $fopen("txt_result/imgDataOut1.txt", "w");            4'd2:   fp_w   =   $fopen("txt_result/imgDataOut2.txt", "w");            4'd3:   fp_w   =   $fopen("txt_result/imgDataOut3.txt", "w");            4'd4:   fp_w   =   $fopen("txt_result/imgDataOut4.txt", "w");            4'd5:   fp_w   =   $fopen("txt_result/imgDataOut5.txt", "w");            4'd6:   fp_w   =   $fopen("txt_result/imgDataOut6.txt", "w");            4'd7:   fp_w   =   $fopen("txt_result/imgDataOut7.txt", "w");            4'd8:   fp_w   =   $fopen("txt_result/imgDataOut8.txt", "w");            4'd9:   fp_w   =   $fopen("txt_result/imgDataOut9.txt", "w");            4'd10:  fp_w   =   $fopen("txt_result/imgDataOut10.txt", "w");            4'd11:  fp_w   =   $fopen("txt_result/imgDataOut11.txt", "w");            4'd12:  fp_w   =   $fopen("txt_result/imgDataOut12.txt", "w");            4'd13:  fp_w   =   $fopen("txt_result/imgDataOut13.txt", "w");            4'd14:  fp_w   =   $fopen("txt_result/imgDataOut14.txt", "w");            4'd15:  fp_w   =   $fopen("txt_result/imgDataOut15.txt", "w");            default:fp_w   =   $fopen("txt_result/imgDataOut0.txt", "w");        endcase    end    else if(cap_Vsync_neg)begin        $fclose(fp_w);//关闭文件,写完一帧再关闭,否则仿真速度会很慢        p_cnt   <=  0;    end    else if(cap_Hsync)begin        $fseek(fp_w, p_cnt, 0);//查找当前需要读取的文件位置        $fwrite(fp_w, "%06x\n", fifo_out_data);//将图像数据按指定格式写入文本中        p_cnt <=  p_cnt + 8;//移动文件指针到下一个数据   一个字符占一个字节,回车占两个字符6+2=8        end    end//例化myFifo myFifo_inst(    .data(fifo_in_data),    .rdclk(cap_clk),    .rdreq(rdreq),    .wrclk(pclk),    .wrreq(wrreq),    .q(fifo_out_data),    .rdempty(rdempty),    .rdusedw(rdusedw),    .wrfull(wrfull),    .wrusedw(wrusedw));endmodule1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.135.136.137.138.139.140.141.142.143.144.145.146.147.148.149.150.151.152.153.154.155.156.157.158.159.160.161.162.163.164.165.166.167.168.169.170.171.172.173.174.175.176.177.178.179.180.181.182.183.184.185.186.187.188.189.190.191.192.193.194.195.196.197.198.199.200.201.202.203.204.205.206.207.208.209.210.211.212.213.214.215.216.217.218.219.220.221.222.223.224.225.226.227.



4 激励文件


4.1 捕获要求

假定视频分辨率为64048024Bit RGB数据,传输数据位宽为8位,扫描为60Hz,每一帧的有效像素数为:

pixel_total = 3640480*60

本地的图像数据位数为24位,如果我们要完全捕获视频流,我们要求

本地像素时钟频率>模拟像素输出时钟频率/3

这里,自定义模拟像素输出时钟周期为10ns,本地像素时钟周期为24ns

下面是Verilog代码


`timescale      1ns/1nsmodule  tb_top;//=====================================================================\// ********** Define Parameter and Internal Signals *************//=====================================================================/reg                             clk                             ;       reg                             rst_n                           ;       reg     [ 3: 0]                 src_sel                         ;wire                            Vsync                           ;wire                            Hsync                           ;wire    [ 7: 0]                 img_data                        ;reg                             cap_clk                         ;wire                            cap_Vsync                       ;wire                            cap_Hsync                       ;wire    [23: 0]                 cap_img_data                    ;//======================================================================// ***************      Main    Code    ****************//======================================================================always  #5      clk     =   ~clk                                ;always  #12     cap_clk =   ~cap_clk                            ;initial begin    clk         <=  1'b1;    cap_clk     <=  1'b1;    rst_n       <=  1'b0;    src_sel     <=  4'd0;    #100    rst_n       <=  1'b1;    #11000000    src_sel     <=  4'd1;end//例化image_src   image_src_inst(        .clk                    (clk                            ),        .rst_n                  (rst_n                          ),        .src_sel                (src_sel                        ),        .pclk                   (pclk                           ),        .Vsync                  (Vsync                          ),        .Hsync                  (Hsync                          ),        .img_data               (img_data                       ));video_cap   video_cap_inst(        .pclk                   (pclk                           ),        .rst_n                  (rst_n                          ),        .Vsync                  (Vsync                          ),        .Hsync                  (Hsync                          ),        .img_data               (img_data                       ),        .cap_clk                (cap_clk                        ),        .cap_Vsync              (cap_Vsync                      ),        .cap_Hsync              (cap_Hsync                      ),        .cap_img_data           (cap_img_data                   ));endmodule1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.



5 仿真结果

图5-1是整个系统的仿真情况。图中两根光标所指示的位置是图像的帧同步信号。

FPGA视频仿真_数据_03

                        图5-1

                        

图5-2是一副图像中的一行数据,两根光标所指示的就是行同步信号。

FPGA视频仿真_FPGA学习_04

                       图5-2

图5-3是将原始图像和经过FPGA处理后的图像经过Qt测试平台显示后的结果

FPGA视频仿真_视频流_05

                        图5-3

免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删

QR Code
微信扫一扫,欢迎咨询~

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 155-2731-8020
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

手机不正确

公司不为空