基于FPGA的数字视频信号处理器设计(下)
今天给大侠带来基于FPGA的数字视频信号处理器设计,由于篇幅较长,分三篇。今天带来第三篇,下篇,程序测试与运行。话不多说,上货。
导读
图像是用各种观测系统以不同形式和手段观测客观世界而获得的,可以直接或间接作用于人眼进而产生视知觉的实体。
随着电子技术和计算机技术的飞速发展,数字图像技术近年来得到极大的重视和长足的发展,并在科学研究、工业生产、医疗卫生、通信等方面得到广泛的应用。
视频信号由一系列连续的图像组成。对视频信号的处理已经成为数字图像处理领域中重要的一部分。例如机器人模式识别的过程就是一个视频信号处理的过程,电视制导导弹识别目标就是充分利用视频信号处理技术不断判断目标是否和预先设定目标图像一致。本篇将讲解如何用 FPGA 技术实现基本的视频信号处理。本篇的例子可以作为各位大侠进行视频信号处理时的一个参考,也可以在这个基础上根据需要进行扩展。
第三篇内容摘要:本篇会介绍程序测试与运行,包括测试程序、测试结果以及总结等相关内容。
五、程序测试与运行
由于整个 FPGA 程序包括 3 部分:处于 TOP 的主体程序,控制其他各个部分程序的运行;视频图像数据采集程序,从 SAA7113 获得数字图像数据并保存到 SRAM 中;SRAM 读写程序实现对 SRAM 的数据读写。测试程序需要仿真数据的全部流程。
5.1 测试程序
测试程序代码如下:
代码语言:javascript复制`include "timescale.v"
moduletst_saa7113(error,dsprst,xreset,saareset,ARDY,ED_O,ED_OEN_O,SRAM_1_EA,SRAM_2_EA,SRAM_1_O_ED,SRAM_2_O_ED);
//内部寄存器
reg reset;
reg clk;//50MHz 时钟
reg llck;//SAA7113 的时钟
reg [7:0] vpo;//来自 saa7113 的图像数据
reg capture;//采集数据标志
reg toggle;//总线切换标志
reg [1:0] rst;
//输入
input error;
input dsprst,xreset,saareset;
input ARDY;
input [7:0] ED_O;
input ED_OEN_O;
input [18:0] SRAM_1_EA;
input [7:0] SRAM_1_O_ED;
input [18:0] SRAM_2_EA;
input [7:0] SRAM_2_O_ED;
//来自 dsp 的信号
reg CE3_;
reg ARE_;
reg AWE_;
reg [21:2] EA;
reg [7:0] ED_I;
//TO SRAM
reg [7:0] SRAM_1_IN_ED;
reg [7:0] SRAM_2_IN_ED;
//wires
//from saa7113
wire SRAM_CE_;
wire SRAM_OE_;
wire SRAM_WE_;
wire [18:0] la;
wire [7:0] ld;
//FROM DSP
wire CE_SRAM;
wire WE_SRAM;
wire OE_SRAM;
wire [7:0] ED_SRAM;
wire [18:0] EA_SRAM;
//连接各个子程序
LWBSAA7113 L_SAA7113 (
.reset(reset),
.clk(clk),
.llck(llck),
.vpo(vpo),
.rst(rst),
.capture(capture),
.error(error),
.SRAM_CE_(SRAM_CE_),
.SRAM_OE_(SRAM_OE_),
.SRAM_WE_(SRAM_WE_),
.la(la),
.ld(ld)
);
LWBDECODE L_DECODE (
.reset(reset),
.CE3_(CE3_),
.ARE_(ARE_),
.AWE_(AWE_),
.EA(EA),
.ED_I(ED_I),
.ED_O(ED_O),
.ED_OEN_O(ED_OEN_O),
.ARDY(ARDY),
.EA_SRAM(EA_SRAM),
.ED_SRAM(ED_SRAM),
.CE_SRAM(CE_SRAM),
.WE_SRAM(WE_SRAM),
.OE_SRAM(OE_SRAM),
.dsprst(dsprst),
.xreset(xreset),
.saareset(saareset)
);
LWBBUSCHANGE L_BUSCHANGE (
.EA_SRAM(EA_SRAM),
.ED_SRAM(ED_SRAM),
.CE_SRAM(CE_SRAM),
.WE_SRAM(WE_SRAM),
.OE_SRAM(OE_SRAM),
.la(la),
.ld(ld),
.SRAM_CE_(SRAM_CE_),
.SRAM_WE_(SRAM_WE_),
.SRAM_OE_(SRAM_OE_),
.SRAM_1_IN_ED(SRAM_1_IN_ED),
.SRAM_2_IN_ED(SRAM_2_IN_ED),
.toggle(toggle),
.SRAM_1_EA(SRAM_1_EA),
.SRAM_1_O_ED(SRAM_1_O_ED),
.SRAM_2_EA(SRAM_2_EA),
.SRAM_2_O_ED(SRAM_2_O_ED)
);
//产生时钟信号
always #10 clk=~clk;
always #20 llck = ~llck;
initial
begin
$display("n status : %t TestBench of saa7113 started! nn",$time);
//initial value
clk = 0;
#7;
llck =0;
//reset
reset = 1;
//dsp 初始化
ARE_ = 1;
AWE_ = 1;
CE3_ = 1;
//初始化
capture = 0;
toggle = 1;
#2;
reset = 0;
repeat(20) @(posedge clk);
reset = 1'b1; // negate reset
//dsp 读取数据内容
SRAM_1_IN_ED = 8'h1d;
SRAM_2_IN_ED = 8'h2d;
//dsp 地址总线
EA[21:16] = 6'b000000;
EA[15:7] = 9'b000000000;
EA[6:2]= 5'b00001;
#5;
CE3_ = 0;
ARE_ = 0;
//saa7113 输出内容
capture = 1;
#5;
@(posedge llck) vpo = 8'haa;
@(posedge llck) vpo = 8'hbb;
@(posedge llck) vpo = 8'hcc;
@(posedge llck) vpo = 8'hdd;
@(posedge llck) vpo = 8'hee;
//场同步信号
//1
@(posedge llck) vpo = 8'hff;//begin
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'b00100000;//sav
//2
@(posedge llck) vpo = 8'hff;//begin
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'b00100000;
//数据开始
@(posedge llck) vpo = 8'hff;//begin
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'b00000000;
//data
@(posedge llck) vpo = 8'h01;//Cb
@(posedge llck) vpo = 8'h02;//Yb
@(posedge llck) vpo = 8'h03;//Cr
@(posedge llck) vpo = 8'h04;//Yr--1
@(posedge llck) vpo = 8'h05;//Cb
@(posedge llck) vpo = 8'h06;//Yb
@(posedge llck) vpo = 8'h07;//Cr
@(posedge llck) vpo = 8'h08;//Yr--2
@(posedge llck) vpo = 8'h09;//Cb
@(posedge llck) vpo = 8'h0a;//Yb
@(posedge llck) vpo = 8'h0b;//Cr
@(posedge llck) vpo = 8'h0c;//Yr--3
@(posedge llck) vpo = 8'h0d;//Cb
@(posedge llck) vpo = 8'h0e;//Yb
@(posedge llck) vpo = 8'h0f;//Cr
@(posedge llck) vpo = 8'h10;//Yr--4
@(posedge llck) vpo = 8'h11;//Cb
@(posedge llck) vpo = 8'h12;//Yb
@(posedge llck) vpo = 8'h13;//Cr
@(posedge llck) vpo = 8'h14;//Yr--5
@(posedge llck) vpo = 8'h15;//Cb
@(posedge llck) vpo = 8'h16;//Yb
@(posedge llck) vpo = 8'h17;//Cr
@(posedge llck) vpo = 8'h18;//Yr--6
@(posedge llck) vpo = 8'h19;//Cb
@(posedge llck) vpo = 8'h1a;//Yb
@(posedge llck) vpo = 8'h1b;//Cr
@(posedge llck) vpo = 8'h1c;//Yr--7
@(posedge llck) vpo = 8'h1d;//Cb
@(posedge llck) vpo = 8'h1e;//Yb
@(posedge llck) vpo = 8'h1f;//Cr
@(posedge llck) vpo = 8'h20;//Yr--8
@(posedge llck) vpo = 8'h21;//Cb
@(posedge llck) vpo = 8'h22;//Yb
@(posedge llck) vpo = 8'h23;//Cr
@(posedge llck) vpo = 8'h24;//Yr--9
@(posedge llck) vpo = 8'h25;//Cb
@(posedge llck) vpo = 8'h26;//Yb
@(posedge llck) vpo = 8'h27;//Cr
@(posedge llck) vpo = 8'h28;//Yr--10
@(posedge llck) vpo = 8'h29;//Cb
@(posedge llck) vpo = 8'h3a;//Yb
@(posedge llck) vpo = 8'h3b;//Cr
@(posedge llck) vpo = 8'h3c;//Yr--11
//数据结束
@(posedge llck) vpo = 8'hff;//ff
@(posedge llck) vpo = 8'h00;//00
@(posedge llck) vpo = 8'h00;//00
@(posedge llck) vpo = 8'b01110000;//end of field 1
#20;
ARE_ = 1;
capture = 0;
#200;
//开始切换
toggle = 0;
#100;
ARE_ = 0;
//开始采集数据
capture = 1;
//vertical blanking stage
//1
@(posedge llck) vpo = 8'hff;//begin
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'b00100000;//sav
//2
@(posedge llck) vpo = 8'hff;//begin
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'b00100000;
//data start
@(posedge llck) vpo = 8'hff;//begin
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'h00;
@(posedge llck) vpo = 8'b00000000;
//data
@(posedge llck) vpo = 8'h01;//Cb
@(posedge llck) vpo = 8'h02;//Yb
@(posedge llck) vpo = 8'h03;//Cr
@(posedge llck) vpo = 8'h04;//Yr--1
@(posedge llck) vpo = 8'h05;//Cb
@(posedge llck) vpo = 8'h06;//Yb
@(posedge llck) vpo = 8'h07;//Cr
@(posedge llck) vpo = 8'h08;//Yr--2
@(posedge llck) vpo = 8'h09;//Cb
@(posedge llck) vpo = 8'h0a;//Yb
@(posedge llck) vpo = 8'h0b;//Cr
@(posedge llck) vpo = 8'h0c;//Yr--3
@(posedge llck) vpo = 8'h0d;//Cb
@(posedge llck) vpo = 8'h0e;//Yb
@(posedge llck) vpo = 8'h0f;//Cr
@(posedge llck) vpo = 8'h10;//Yr--4
@(posedge llck) vpo = 8'h11;//Cb
@(posedge llck) vpo = 8'h12;//Yb
@(posedge llck) vpo = 8'h13;//Cr
@(posedge llck) vpo = 8'h14;//Yr--5
@(posedge llck) vpo = 8'h15;//Cb
@(posedge llck) vpo = 8'h16;//Yb
@(posedge llck) vpo = 8'h17;//Cr
@(posedge llck) vpo = 8'h18;//Yr--6
@(posedge llck) vpo = 8'h19;//Cb
@(posedge llck) vpo = 8'h1a;//Yb
@(posedge llck) vpo = 8'h1b;//Cr
@(posedge llck) vpo = 8'h1c;//Yr--7
@(posedge llck) vpo = 8'h1d;//Cb
@(posedge llck) vpo = 8'h1e;//Yb
@(posedge llck) vpo = 8'h1f;//Cr
@(posedge llck) vpo = 8'h20;//Yr--8
@(posedge llck) vpo = 8'h21;//Cb
@(posedge llck) vpo = 8'h22;//Yb
@(posedge llck) vpo = 8'h23;//Cr
@(posedge llck) vpo = 8'h24;//Yr--9
@(posedge llck) vpo = 8'h25;//Cb
@(posedge llck) vpo = 8'h26;//Yb
@(posedge llck) vpo = 8'h27;//Cr
@(posedge llck) vpo = 8'h28;//Yr--10
@(posedge llck) vpo = 8'h29;//Cb
@(posedge llck) vpo = 8'h3a;//Yb
@(posedge llck) vpo = 8'h3b;//Cr
@(posedge llck) vpo = 8'h3c;//Yr--11
//数据结束
@(posedge llck) vpo = 8'hff;//ff
@(posedge llck) vpo = 8'h00;//00
@(posedge llck) vpo = 8'h00;//00
@(posedge llck) vpo = 8'b01110000;//end of field 1
#20;
//结束数据采集
capture = 0;
#200;
//测试程序结束
$finish;
end
endmodule
5.2 测试结果
仿真程序产生的视频图像数据如图 18 所示。开始的“aa bb cc dd ee ff”是无效数据,“ff 00 20”表示场同步信号。
图 18 仿真产生的视频图像数据
经过 FPGA 处理后获得有效图像数据并产生相应的地址信号,如图 19 所示。由于只进行灰度运算,只取亮度信息,因此获得数据为“04 08 0c”,同时产生地址信号“00 01 02”。
图 19 FPGA 采集得到的有效图像数据并产生的地址信号
对 SRAM 的读写控制,如图 20 所示。
图 20 产生的对 SRAM 的读写控制
两块 SRAM 之间的切换,如图 21 所示。
图 21 两块 SRAM 之间的切换
仿真结果表明整个视频信号处理程序完成了预先设定的设计目标。
七、总结
本篇首先介绍了视频信号的基本原理、组成等,然后讲解了进行视频信号处理的基本过程和框架。接下来结合实例讲解用 FPGA 及其他芯片组成视频处理的电路设计和 FPGA 的程序实现。最后用 Modelsim 仿真和测试了程序。本篇为各位大侠提供了一种视频信号处理的设计方案,仅供参考。
本篇到此结束,各位大侠,有缘再见!
完
后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。
江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!