仿真测试系统所包含的功能:
(1)模拟可配置的视频流(单帧的视频即为一副图像)
(2)模拟视频捕获,生成视频数据
(3)测试系统与testbench及视频流的数据共享
(4)可视化的图像及视频操作
(5)对FPGA的处理结果进行验证
仿真测试系统结构如下图所示:
上面是从书上的截图,这里我将Qt测试程序代替MFC测试程序。
仿真测试系统由Qt平台和Modelsim共同搭建完成。模拟测试的完整过程如下:
1.Qt将一张图片所有的RGB颜色信息存储在文本中。
2.modelsim模拟视频流传输,读取(1)中图像信息生成视频流,并模拟捕获视频流,并将这些图像信息写入另一个文本中。
3.Qt将模拟捕获的图像文本信息读取并生成图像。
通过以上可知,Qt平台与FPGA模拟视频流及处理结果通过文本实现数据共享。
图2-1是一个典型的CMOS视频输出时序图:
图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:场后肩
参考书上的代码,我自己实现了上述视频流的模拟时序(像素数据从文本中得到,一个像素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.
本模块的目的是对上一节产生的视频信号进行捕获并解析
(1) 位宽转换:将八位视频流数据转换成24位数据。这里通过一个深度为1024的fifo来辅助实现
(2) 生成本地帧同步和行同步信号
(3) 将图像数据写入文本中,以供Qt平台读取显示
/************************************************************************ * 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.
假定视频分辨率为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-1是整个系统的仿真情况。图中两根光标所指示的位置是图像的帧同步信号。
图5-1
图5-2是一副图像中的一行数据,两根光标所指示的就是行同步信号。
图5-2
图5-3是将原始图像和经过FPGA处理后的图像经过Qt测试平台显示后的结果
图5-3
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删