1.简介
本节主要讲解如何基于ZYNQ7020搭建一个视频流接收以及显示的数据通路。为后续的算法图像验证提供基础。
2.项目框架
整个项目简略框架如图,img_gen负责产生图像像素点,给到video in to AXI_Stream模块后转化为AXI_Stream数据流给到VDMA,VDMA采用三帧缓存的方式向ARM控制的DDR3写入像数据据并读出像素数据,读出的数据给到AXI4_Stream to Video Out模块,AXI4_Stream to Video Out同时接收Vide Time Controller模块产生的VGA时序,并将VGA时序与像素点信息全部给到VGA to DVI模块,然后交由HDMI显示屏显示。项目完成后的详细信息如下:
3.部分源码
3.1 img_gen
其中img_gen用于产生像素信息,这里我们采用黑白渐变像素。源码如下
`timescale 1ns / 1ps
module img_gen
#(
parameter ACTIVE_IW = 800 ,
parameter ACTIVE_IH = 480 ,
parameter TOTAL_IW = 1057 ,
parameter TOTAL_IH = 506 ,
parameter H_START = 216 ,
parameter V_START = 24
)
(
input clk ,
input rst_n ,
output reg vs ,
output reg de ,
output reg [7:0] data
);
reg [7:0] raw_array [ACTIVE_IW*ACTIVE_IH-1:0];
integer i;
initial begin
for (i=0; i<ACTIVE_IW*ACTIVE_IH; i=i+1)
raw_array[i] = 0;
end
/* initial begin
$readmemh("F:/lesson/lesson1/data/pre.txt",raw_array);
end */
reg [31:0] cnt_delay ;
reg [15:0] hcnt ;
reg [15:0] vcnt ;
reg h_de ;
reg v_de ;
reg index_de ;
reg [7:0] index ;
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_delay <= 'd0;
else if(cnt_delay==100000000*5-1)
cnt_delay <= cnt_delay;
else
cnt_delay <= cnt_delay + 1'b1;
always@(posedge clk or negedge rst_n)
if(!rst_n)
hcnt <= 'd0;
else if(hcnt==TOTAL_IW-1)
hcnt <= 'd0;
else if(cnt_delay==100000000*5-1)
hcnt <= hcnt + 1'b1;
else
hcnt <= hcnt;
always@(posedge clk or negedge rst_n)
if(!rst_n)
vcnt <= 'd0;
else if(hcnt==TOTAL_IW-1&&vcnt==TOTAL_IH-1)
vcnt <= 'd0;
else if(hcnt==TOTAL_IW-1)
vcnt <= vcnt + 1'b1;
else
vcnt <= vcnt;
always@(posedge clk or negedge rst_n)
if(!rst_n)
vs <= 1'b0;
else if(vcnt>=2)
vs <= 1'b1;
else
vs <= 1'b0;
always@(posedge clk or negedge rst_n)
if(!rst_n)
h_de <= 1'b0;
else if(hcnt>=H_START&&hcnt<H_START+ACTIVE_IW)
h_de <= 1'b1;
else
h_de <= 1'b0;
always@(posedge clk or negedge rst_n)
if(!rst_n)
v_de <= 1'b0;
else if(vcnt>=V_START&&vcnt<V_START+ACTIVE_IH)
v_de <= 1'b1;
else
v_de <= 1'b0;
always@(posedge clk or negedge rst_n)
if(!rst_n)
index_de <= 1'b0;
else if(h_de==1'b1&&v_de==1'b1)
index_de <= 1'b1;
else
index_de <= 1'b0;
always@(posedge clk or negedge rst_n)
if(!rst_n)
index <= 'd0;
else if(index_de==1'b1)
index <= index + 1'b1;
else
index <= 'd0;
always@(posedge clk or negedge rst_n)
if(!rst_n)
de <= 1'b0;
else
de <= index_de;
always@(posedge clk)
if(index_de==1'b1)
data <= index;
else
data <= 0;
endmodule
3.2 top
顶层模块负责连接block design与一些外部模块
`timescale 1ns / 1ps
module top(
input wire sys_clk ,
inout wire [14:0] DDR_addr ,
inout wire [2:0] DDR_ba ,
inout wire DDR_cas_n ,
inout wire DDR_ck_n ,
inout wire DDR_ck_p ,
inout wire DDR_cke ,
inout wire DDR_cs_n ,
inout wire [3:0] DDR_dm ,
inout wire [31:0] DDR_dq ,
inout wire [3:0] DDR_dqs_n ,
inout wire [3:0] DDR_dqs_p ,
inout wire DDR_odt ,
inout wire DDR_ras_n ,
inout wire DDR_reset_n ,
inout wire DDR_we_n ,
inout wire FIXED_IO_ddr_vrn ,
inout wire FIXED_IO_ddr_vrp ,
inout wire [53:0] FIXED_IO_mio ,
inout wire FIXED_IO_ps_clk ,
inout wire FIXED_IO_ps_porb ,
inout wire FIXED_IO_ps_srstb ,
output wire tmds_clk_p ,
output wire tmds_clk_n ,
output wire [ 2:0] tmds_data_p ,
output wire [ 2:0] tmds_data_n
);
wire clk_200M ;
wire rst_n ;
wire pre_vs ;
wire pre_de ;
wire [7:0] pre_data ;
wire video_clk ;
wire video_clk5 ;
wire video_vs ;
wire video_hs ;
wire video_de ;
wire [23:0] video_data ;
clk_global u1_clk_global (
.clk_in1 (sys_clk ),
.clk_200M (clk_200M ),
.locked (rst_n )
);
//1920*1080 60fps
img_gen
#(
.ACTIVE_IW (1920),
.ACTIVE_IH (1080),
.TOTAL_IW (2200),
.TOTAL_IH (1111),
.H_START (5 ),
.V_START (5 )
)
u1_img_gen
(
.clk (clk_200M ),
.rst_n (rst_n ),
.vs (pre_vs ),
.de (pre_de ),
.data (pre_data )
);
cpu_wrapper u1_cpu_wrapper (
.DDR_addr (DDR_addr ),
.DDR_ba (DDR_ba ),
.DDR_cas_n (DDR_cas_n ),
.DDR_ck_n (DDR_ck_n ),
.DDR_ck_p (DDR_ck_p ),
.DDR_cke (DDR_cke ),
.DDR_cs_n (DDR_cs_n ),
.DDR_dm (DDR_dm ),
.DDR_dq (DDR_dq ),
.DDR_dqs_n (DDR_dqs_n ),
.DDR_dqs_p (DDR_dqs_p ),
.DDR_odt (DDR_odt ),
.DDR_ras_n (DDR_ras_n ),
.DDR_reset_n (DDR_reset_n ),
.DDR_we_n (DDR_we_n ),
.FIXED_IO_ddr_vrn (FIXED_IO_ddr_vrn ),
.FIXED_IO_ddr_vrp (FIXED_IO_ddr_vrp ),
.FIXED_IO_mio (FIXED_IO_mio ),
.FIXED_IO_ps_clk (FIXED_IO_ps_clk ),
.FIXED_IO_ps_porb (FIXED_IO_ps_porb ),
.FIXED_IO_ps_srstb (FIXED_IO_ps_srstb ),
.clk_200M (clk_200M ),
.rst_n (rst_n ),
.pre_clk (clk_200M ),
.pre_vs (pre_vs ),
.pre_de (pre_de ),
.pre_data (pre_data ),
.video_clk (video_clk ),
.video_clk5 (video_clk5 ),
.video_vs (video_vs ),
.video_hs (video_hs ),
.video_de (video_de ),
.video_data (video_data )
);
DVI_Transmitter u_DVI_Transmitter (
.pclk (video_clk ),
.pclk_x5 (video_clk5 ),
.reset_n (rst_n ),
.video_din (video_data ),
.video_hsync (video_hs ),
.video_vsync (video_vs ),
.video_de (video_de ),
.tmds_clk_p (tmds_clk_p ),
.tmds_clk_n (tmds_clk_n ),
.tmds_data_p (tmds_data_p ),
.tmds_data_n (tmds_data_n ),
.tmds_oen ( )
);
wire [99:0] probe0;
assign probe0 = {
video_vs,
video_hs,
video_de,
video_data
};
ila_vga u1_ila_vga(
.clk (video_clk ),
.probe0 (probe0 )
);
endmodule
main.c
main.c主要负责配置vdma模块
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "xil_printf.h"
#include "xil_io.h"
#define VDMA_BASEADDR XPAR_AXI_VDMA_0_BASEADDR
//三帧缓存中每一帧的首地址
#define VIDEO_BASEADDR0 0x01000000
#define VIDEO_BASEADDR1 0x02000000
#define VIDEO_BASEADDR2 0x03000000
#define H_ACTIVE 1920
#define V_ACTIVE 1080
#define H_STRIDE 1920
int main()
{
Xil_Out32((VDMA_BASEADDR + 0x030), 0x108B); // enable circular mode
Xil_Out32((VDMA_BASEADDR + 0x0AC), VIDEO_BASEADDR0); // start address
Xil_Out32((VDMA_BASEADDR + 0x0B0), VIDEO_BASEADDR1); // start address
Xil_Out32((VDMA_BASEADDR + 0x0B4), VIDEO_BASEADDR2); // start address
Xil_Out32((VDMA_BASEADDR + 0x0A8), (H_STRIDE*1)); // h offset 1280 bytes
Xil_Out32((VDMA_BASEADDR + 0x0A4), (H_ACTIVE*1)); // h size 1280 bytes
Xil_Out32((VDMA_BASEADDR + 0x0A0), V_ACTIVE); // v size 1024
/*****************从DDR读数据设置**********************/
Xil_Out32((VDMA_BASEADDR + 0x000), 0x8B); // enable circular mode
Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0); // start address
Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR1); // start address
Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR2); // start address
Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*1)); // h offset 1280 bytes
Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*1)); // h size 1280 bytes
Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE); // v size 1024
while (1) ;
return 0;
}
4.现象
本次的图像为1080P,考虑到资源问题,本次的像素信息实时生成,最终上板测试的图像为黑白渐变条纹。在1080P显示屏上显示如下图。