FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持

目录

  • 1、前言
  • 2、模拟视频概述
  • 3、模拟视频颜色空间
  • 4、逐行与隔行
  • 5、BT656数据与解码
    • BT656数据格式
    • BT656数据解码
  • 6、TW2867芯片解读与配置
    • TW2867芯片解读
    • TW2867芯片配置
    • TW2867时序分析
  • 7、设计思路与框架
  • 8、vivado工程详解
  • 9、上板调试验证
  • 10、福利:工程代码的获取

1、前言

大自然的信号都是模拟的,视频信号也不例外。视频信号是指电视信号、静止图象信号和可视电视图像信号。视频信号分为三种制式:PAL、NTSC 和 SECAM。既然 PAL、NTSC、SECAM 都是模拟信号,FPGA 处理的是数字信号(有些 FPGA内部自带 AD,可以处理模拟信号,例如 Altera 的 MAX10),因此中间需要一个芯片做转换,也就是一个 ADC,学名叫做视频解码芯片。
本设计使用TW2867作为视频解码芯片,TW2867可输出PAL或者NTSC,代码中设置了配置参数,可任意选择其一,TW2867解码出4路BT656视频,BT656解码、图像缩放、视频去隔行、图像缓存后HDMI输出。

本文详细描述了FPGA实现模拟视频解码输出的设计方案,工程代码编译通过后上板调试验证,文章末尾有演示视频,可直接项目移植,适用于在校学生、研究生项目开发,也适用于在职工程师做项目开发,可应用于医疗、军工等行业的数字成像和图像传输领域;
提供完整的、跑通的工程源码和技术支持;
工程源码和技术支持的获取方式放在了文章末尾,请耐心看到最后;

2、模拟视频概述

大自然的信号都是模拟的,视频信号也不例外。视频信号是指电视信号、静止图象信号和可视电视图像信号。视频信号分为三种制式:PAL、NTSC 和 SECAM,接下来简单介绍一下这对于后期调试电路很有帮助。
PAL 制又称为帕尔制。PAL 是英文 Phase Alteration Line 的缩写,意思是逐行倒相,也属于同时制。“PAL”有时亦被用来指 625 线,每秒 25 格,隔行扫描,PAL 色彩编码的电视制式。NTSC 是 National Television Standards Committee 的缩写,意思是“(美国)国家电视标准委员会”。NTSC 负责开发一套美国标准电视广播传输和接收协议。SECAM 制式,又称塞康制,SECAM 是法文 Sequentiel Couleur A Memoire 缩写,意为“按顺序传送彩色与存储”,是一个首先用在法国模拟彩色电视系统。这只是简单的概述,关于 PAL、NTSC 和 SECAM 更详细的资料请参考视频技术手册。
既然 PAL、NTSC、SECAM 都是模拟信号,FPGA 处理的是数字信号(有些 FPGA内部自带 AD,可以处理模拟信号,例如 Altera 的 MAX10),因此中间需要一个芯片做转换,也就是一个 ADC,学名叫做视频解码芯片,本设计使用TW2867作为视频解码芯片。

3、模拟视频颜色空间

颜色空间也就是颜色的集合。有 3 个最常用的模型:RGB(计算机图形学)、YUV/YCbCr(视频系统)和 CMYK(打印系统)。在此只介绍 RGB 和 YUV/YCbCr。RGB 就是 red、green、blue 的缩写,也就是三原色,常用于计算机图像学中。常用的 RGB 格式有 RGB555、RGB565、RGB888 等。RGB565 含义是 red 占 5bit,green 占6bit,blue 占 5biit,一个占 16bit,颜色深度为 65536 色,常见的存储器有 8bit、16bit等,RGB565 的显示系统非常适合使用这种存储器。
在 YUV/YCbCr 空间中,Y 表示明亮度(Luminance、Luma)信号,U 表示色度(Chrominance)信号,V 表示浓度(Chroma)信号,只是对颜色空间另一种表示方法。常见的 YUV 格式有 YUV422、YUV444 等。YUV444 格式如下图所示,每一个像素分别用24bit 量化,分别量化成 Y、Cb、Cr,各占 8bit,从另一个方面说 YUV444 相当于RGB888,数据量是一样的,YUV444 格式如下图所示:
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第1张图片
YUV422 格式如下图所示,它相当于在 YUV444 基础之上丢掉 Cb 和 Cr 数据,2 个像素量化成 32bit 数据,包括 2 个 Y,1 个 Cb,1 个 Cr,相当于 1 个像素需要 16bit 表示,相当于 RGB565 数据量。
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第2张图片
TW2867输出的是YUV422 格式。

4、逐行与隔行

先简单区分一个概念,隔行扫描(Interlace scan)和逐行扫描(Progressive scan)。如下图所示,这是隔行扫描示意图,也就是先显示奇数行,然后再显示偶数行,这只是其中一种隔行扫描的方式,用途比较广泛,除此之外还有隔 2 行、隔 3 行扫描。
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第3张图片
如下图所示,这是逐行扫描示意图,也就从第一行扫描,一直扫描到最后一行。目前显示器是逐行扫描的。
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第4张图片
隔行转逐行是通过 DDR3 内存实现的,详细内容请参考工程代码。

5、BT656数据与解码

BT656数据格式

BT656 是一种视频输出格式,TW2867 视频输出是 BT656 格式,只有一小部分不一样,BT656 格式时钟是 27MHz,输出视频格式是 YUV422,隔行输出。
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第5张图片
如上图所示是一行 BT656 数据结构,分成 4 段:EAV(4-byte)、BLANKING(280-byte)、SAV(4-byte)和有效数据(1440-byte),接下来分别介绍。BLANKING:280-byte,0x80 和 0x10 交替出现。有效数据:1440-byte,一共 720 个像素,Y 占 720 个数据,Cb 和 Cr 分别占 360 个数据。EAV 和 SAV:分别占 4-byte,前三个字节相同,是 0XFF,0X00,0X00,最后一个不同,根据这个字节进行解码。
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第6张图片
EAV 和 SAV 的结构如上图所示,其中 F、V、H 含义:
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第7张图片
F 是场信号,0 表示场 1,1 表示场 2,也就是奇偶场。V 表示场有效,0 表示场数据有效,1 表示是垂直消隐。H 区分 EAV 和 SAV 信号。P3-P0 只是校验保护位,由 F、V、H 进行异或运算得到。如下图所示,这是一帧 BT656 数据格式,一共包括 625 行,每行 1728 个字节,有效数据大小是 720x576,分成 2 场,每场 720x288,其余行是消隐信号。
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第8张图片
BT656 规定一行有 1728 个字节,一帧有 625 行,每秒传输 25 帧数据,8bit 总线并行传输。1728x625x25=27000000=27M,经过计算就知道 27MHz 的来历了。在这 625行中有用的数据是 576 行,在 BT656 视频格式中有效视频大小是 720x576,其余的当做消隐处理。

BT656数据解码

压力来了,怎样才能做好 BT656 解码来适应不同的模块呢?根据BT656数据格式,解析并丢弃EAV(4-byte)、BLANKING(280-byte)、SAV(4-byte),保留有效数据(1440-byte),同时恢复行同步、场同步、奇偶场号、数据有效以及像素数据,详细内容请参考工程代码。

6、TW2867芯片解读与配置

TW2867芯片解读

本次设计使用的是专用模拟视频解码芯片 TW2867,支持 4 路模拟视频输入,4 路模拟音频输入,1 路音频输出,视频输出是标准 BT656 格式。由于 FPGA 引脚限制,MIS603 音频部分没有做;TW2867输入 4 路模拟视频信号,输出YUV422数字视频流,每路视频流是 BT656 格式,BT656 视频时钟 27MHz,4 路复合 =27MHzx4=108MHz,视频接口连接到 FPGA。
TW2867视频输出引脚说明如下:
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第9张图片
对于 4 路复合视频时钟 108MHz,对硬件要求很高,数据线和时钟线等长布线。

TW2867芯片配置

TW2867 内部有很多寄存器,在此给出几个常用的寄存器及其含义,更多的内容请参考 TW2867 数据手册。
输出使能控制和时钟输出控制:
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第10张图片
在这个寄存器中主要关心bit6配置为1,输出使能;bit3-2配置为0,CLKNO1输出27MHz时钟,bit1-0 配置为 2,CLKPO1 输出108MHz 时钟,通过这 2 个时钟可以把 4 路视频信号分开。这个寄存器配置为 0x42。
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第11张图片
Bit6:配置为 1,标准 ITU-R656 格式。
Bit5-4:选择视频复合后输出引脚,配置为 1,从 CHID1 输出。
Bit3:配置为 0,正常 ITU-R656 格式。
Bit2:配置为 0,输出视频中有 EAV-SAV 信号。
Bit1:配置为 1,bit7-4 是 EAV/SAV 编码。
Bit0:配置为 0,奇数场和偶数场行数相等。
综上,这个寄存器配置为 0x52。
视频通道输出控制:
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第12张图片
这个寄存器配置为 0x02,4 路视频通过时分复用到 VD1[7:0]输出,硬件设计连接到 VD1。
视频功能控制:
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第13张图片
Bit7:配置为 0,视频视频数据输出限制到 0-254。
Bit6:配置为 1,ACKG 的输入参考是 ASYNP。
Bit5:配置为 0,输出格式是 YUV422 格式。
Bit4:配置为 1。
Bit3:配置为 0,仅用于测试。
Bit2:配置为 0,消隐时数据输出 0x80 和 0x10。
Bit1:配置为 0,ITU-R BT656 同步信号在消隐部分。
Bit0:配置为 1,HACTIVE 在垂直消隐期间使能。
这个寄存器配置为 0x51。

TW2867时序分析

之前介绍了 BT656 格式时钟 27MHz 的来源,TW2867 支持 4 路实时 BT656 视频,采样时分复用,最大时钟频率是 108MHz,因此需要一个 108MHz 的时钟输入引脚,考虑到方便解调出每路视频信号增加了一个 27MHz 的时钟输入信号,再加上 8 根数据,这样 10 根线就可以输入 4 路视频信号,在硬件设计上大大简化,降低了布线的复杂度。
如下图所示,TW2867 在 4 路视频复合时的时序图,那就是 4 个通道视频轮流输出,即通道 1 视频数据、通道 2 视频数据、通道 3 视频数据、通道 4 视频数据,然后重复。
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第14张图片
通过了解视频数据复合方式,那解复合程序就可以设计了,那面说说思路。采用时分复用,每个通道数据轮流输出,那就需要一个计数器实现把每个通道的数据分离,即将 108MHz 时钟数据分成 4 个 27MHz 时钟数据。由于是 4 路视频,需要产生一个模长为 4 的计数器,根据计数器的数据把数据分配到 4 个视频通道上。详细内容请参考工程代码。

7、设计思路与框架

设计思路与框架如下:
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第15张图片
图像输入:
4路PAL摄像头;
4路视频通道分离:
将4路复合视频分离出4路独立的视频通路;
BT656解码:
解码BT656,恢复出行、场、de、数据,BT656输出的是YUV422,这里直接提取数据输出YUV444;
颜色空间转换:
YUV444转RGB888,很简单,不多说;
图像缓存去隔行:
BT656分辨率是 720x576,写入DDR前,现将一行像素缩小至320;
在前面的教程中分析过隔行与逐行的区别,由于一行数据需要 2 次写入 DDR 才能写完,因此需要一个计数器,这样写入了 1 行数据,留出的空间是 2 行的空间,为另一场数据写入流出了空间,在留出的空间中写入数据,从而组成一帧完整的数据。详细内容请参考工程代码。
从DDR读出数据,然后将场方向缩小至280,这样视频从输入的720x576变为了320x240,刚好在640x480的屏幕上能放下4路图像;
图像输出:
输出HDMI视频,很简单,不多说。

8、vivado工程详解

开发板:Xilinx Artix7-100T
开发环境:vivado2019.1;
输入:4路PAL摄像头;
输出:HDMI,640x480;
工程代码架构如下:
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第16张图片
顶层源码如下:

//                                                    
// Module Name   : Video_TW2867.v                                    
// Project Name  : Video_TW2867                                                                 
// Target Devices: XC7A100T-2FGG484                                                               
// Tool Versions : vivado2019.1                                                              
// Description   :                                                                                                                                                
// Dependencies  :                                                                                                                                                                                                                     
// Revision      :1.0 - File Created                                                     
// Additional Comments:                                                                                       
//
`timescale 1ns / 1ps
`include "system_parameter.h"                 
module  Video_TW2867 (
    //************************clock  port**********************//
    input                i_clk             //25MHz   
    //************************DDR ports*************************//
   ,inout      [31:0] io_ddr3_dq
   ,inout      [3:0]  io_ddr3_dqs_n
   ,inout      [3:0]  io_ddr3_dqs_p
   ,output     [13:0] o_ddr3_addr
   ,output     [2:0]  o_ddr3_ba
   ,output            o_ddr3_ras_n
   ,output            o_ddr3_cas_n
   ,output            o_ddr3_we_n
   ,output            o_ddr3_reset_n
   ,output            o_ddr3_ck_p
   ,output            o_ddr3_ck_n
   ,output            o_ddr3_cke
   ,output            o_ddr3_cs_n
   ,output     [3:0]  o_ddr3_dm
   ,output            o_ddr3_odt
   //************************TW2867 ports*************************//
   ,output            o_TW2867_i2c_scl      
   ,inout             io_TW2867_i2c_sda
   ,output            o_TW2867_rst_n 
   ,input             i_video_clk_108m
   ,input             i_video_clk_27m
   ,input     [7:0]   i_video_data  
   //************************HDMI ports***************************//
   ,output            o_tmds_clk_p              
   ,output            o_tmds_clk_n 
   ,output    [2:0]   o_tmds_data_p
   ,output    [2:0]   o_tmds_data_n 	
   ,output            o_hdmi_en 	 
    );   
    
    //signal for clock and reset 
    wire                 w_clk_25MHz               ;
    wire                 w_clk_125MHz              ;
    wire                 w_clk_100MHz              ;    
    wire                 w_clk_200MHz              ;
    wire                 w_clk_200MHz_loeked       ;
    wire                 w_sys_rst_n               ;
    wire                 w_sys_clk                 ; 
                                                   
    //signal for TW2867                            
    wire                 w_tw2867_init_done        ;           
    wire                 w_ID_error                ;       
    reg      [9:0]       r_TW2867_init_cnt         ;
    reg                  r_TW2867_init_en          ; 
    //video CH1 data                               
    wire                 w_ch1_axis_tvalid         ;
    wire                 w_ch1_axis_tready         ;
    wire     [31: 0]     w_ch1_axis_tdata          ;
    wire     [3 : 0]     w_ch1_axis_tkeep          ;
    wire                 w_ch1_axis_tlast          ;
    wire     [3 : 0]     w_ch1_axis_tuser          ;
    //video CH2 data                                
    wire                 w_ch2_axis_tvalid         ;
    wire                 w_ch2_axis_tready         ;
    wire     [31: 0]     w_ch2_axis_tdata          ;
    wire     [3 : 0]     w_ch2_axis_tkeep          ;
    wire                 w_ch2_axis_tlast          ;
    wire     [3 : 0]     w_ch2_axis_tuser          ;
    //video CH3 data                               
    wire                 w_ch3_axis_tvalid         ;
    wire                 w_ch3_axis_tready         ;
    wire     [31: 0]     w_ch3_axis_tdata          ;
    wire     [3 : 0]     w_ch3_axis_tkeep          ;
    wire                 w_ch3_axis_tlast          ;
    wire     [3 : 0]     w_ch3_axis_tuser          ;
    //video CH4 data                                
    wire                 w_ch4_axis_tvalid         ;
    wire                 w_ch4_axis_tready         ;
    wire     [31: 0]     w_ch4_axis_tdata          ;
    wire     [3 : 0]     w_ch4_axis_tkeep          ;
    wire                 w_ch4_axis_tlast          ;
    wire     [3 : 0]     w_ch4_axis_tuser          ; 
    //signal for Write DDR
    wire     [31 : 0]    w_DDR_wr_dma_baseaddr     ;           
    wire     [15 : 0]    w_DDR_wr_dma_vsize        ;       
    wire     [15 : 0]    w_DDR_wr_dma_hsize        ;       
    wire     [15 : 0]    w_DDR_wr_dma_stridesize   ;       
    wire                 w_DDR_wr_dma_start        ;       
    wire                 w_DDR_wr_dma_pause        ;       
    wire                 w_DDR_wr_dma_force_stop   ;       
    wire                 w_DDR_wr_dma_busy         ;       
    wire                 w_DDR_wr_dma_done         ;       
    wire     [1 : 0]     w_DDR_wr_dma_inter_err    ;       
    wire                 w_DDR_wr_axi_noack_err    ;       
    wire     [3 : 0]     w_DDR_wr_dma_parameter_err;       
    wire     		 	 w_DDR_wr_clk              ;     
    wire     		 	 w_DDR_wr_en               ;     
    wire     [31:0]		 w_DDR_wr_din              ;      
    wire   			 	 w_DDR_wr_full             ;      
    wire          	     w_DDR_wr_almost_full      ;        
    wire     [10:0]	     w_DDR_wr_wr_data_count    ;            
    //signal for DDR 
    wire                 w_ddr_init_done           ;
    //signal for read image from ddr
    wire                 w_rd_vsync                ;
    wire                 w_rd_hsync                ;
    wire                 w_rd_active               ; 
    wire     [31:0]      w_image_data              ;
    wire     [15:0]      w_DDR_rd_dma_hsize        ; 
    wire     [15:0]      w_DDR_rd_dma_vsize        ;
    wire     [15:0]      w_DDR_rd_dma_stridesize   ;
    wire                 w_DDR_rd_dma_start        ;
    wire     [31:0]      w_DDR_rd_dma_base_addr    ;
    wire                 w_DDR_rd_dma_busy         ;
    wire                 w_DDR_rd_dma_done         ;
    wire     [1:0]       w_ch1_frame_cnt           ;
    wire     [1:0]       w_ch2_frame_cnt           ;
    wire     [1:0]       w_ch3_frame_cnt           ;
    wire     [1:0]       w_ch4_frame_cnt           ;
    wire                 w_frame_start             ;
    //signal for HDMI display 
    wire     [23:0]      w_HDMI_data               ;
   
   //*****************************************************************************// 
   //part: Clock and Reset                                                                   
   //*****************************************************************************// 
    
    Clock_Unit_v1_0 helai_Clock_Unit (
     .i_clk              (i_clk              )//25MHz外部时钟
    ,.o_clk_25MHz        (w_clk_25MHz        )//for VGA
    ,.o_clk_125MHz       (w_clk_125MHz       )            
    ,.o_clk_100MHz       (                   )
    ,.o_clk_200MHz       (w_clk_200MHz       )//for DDR
    ,.o_clk_200MHz_loeked(w_clk_200MHz_loeked)//for DDR
    );      
    //*****************************************************************************//
    //part: TW2867 初始化                                                           
    //*****************************************************************************// 

    //控制启动TW2867的初始化启动时间,等复位稳定后即可启动
     always @ (posedge w_sys_clk )  begin
     	  if(w_sys_rst_n == 1'b0) r_TW2867_init_cnt <= 10'd0;
     	  else if(r_TW2867_init_cnt == 10'd1000) r_TW2867_init_cnt <= r_TW2867_init_cnt;
     	  else r_TW2867_init_cnt <= r_TW2867_init_cnt + 1'b1;
     end 
     
     always @ (posedge w_sys_clk )  begin
		if(r_TW2867_init_cnt == 16'd800) r_TW2867_init_en <= 1'b1 ;
		else  r_TW2867_init_en <= 1'b0 ;
     end
        
     TW2867_Init_Top_v1_0 #(
      .P_SYS_CLK        (100_000_000       )	  
     ,.P_I2C_CLK	    (200_000           )//200KHz
     ,.P_ID_WR_ADDR     (8'h50             )
     ,.P_ID_RD_ADDR     (8'h51             )
     ,.P_SIMULATION     (1'b0              )
     )helai_TW2867_Init(                        
      .i_sys_clk		(w_sys_clk         )  
     ,.i_reset_n		(w_sys_rst_n       )
     ,.i_init_en        (r_TW2867_init_en  )                     
     ,.o_i2c_sclk	    (o_TW2867_i2c_scl  )
     ,.io_i2c_sdat      (io_TW2867_i2c_sda )
     ,.o_tw2867_rst_n   (o_TW2867_rst_n    )
     ,.o_ch_status_valid(                  )//通道状态数据有效 
     ,.o_ch_number      (                  )//通道号           
     ,.o_ch_status      (                  )//通道状态数据        
     ,.o_init_done      (w_tw2867_init_done)
     ,.o_ID_error       (w_ID_error        )
     ,.o_bir_en         (                  ) 
     );      
          
    //*****************************************************************************// 
    //part: TW2867 视频解码、采集                                                             
    //*****************************************************************************//     
    
     TW2867_Decode_v1_0 helai_TW2867_Decode (
      .i_clk_108M         (i_video_clk_108m  )//w_video_clk_108MHz
     ,.i_clk_27M          (i_video_clk_27m   )//w_video_clk_27MHz 
     ,.i_rst_n            (w_tw2867_init_done)//w_sys_rst_n 
     ,.i_mux_data         (i_video_data      )
     //------------------video CH1------------------   
     ,.i_ch1_s_aresetn    (w_sys_rst_n       )  
     ,.i_ch1_m_aclk       (w_sys_clk         )  
     ,.o_ch1_m_axis_tvalid(w_ch1_axis_tvalid )  
     ,.i_ch1_m_axis_tready(w_ch1_axis_tready )  
     ,.o_ch1_m_axis_tdata (w_ch1_axis_tdata  )  
     ,.o_ch1_m_axis_tkeep (w_ch1_axis_tkeep  )  
     ,.o_ch1_m_axis_tlast (w_ch1_axis_tlast  )
     ,.o_ch1_m_axis_tuser (w_ch1_axis_tuser  )
     //------------------video CH2------------------   
     ,.i_ch2_s_aresetn    (w_sys_rst_n       )
     ,.i_ch2_m_aclk       (w_sys_clk         )
     ,.o_ch2_m_axis_tvalid(w_ch2_axis_tvalid )
     ,.i_ch2_m_axis_tready(w_ch2_axis_tready )
     ,.o_ch2_m_axis_tdata (w_ch2_axis_tdata  )
     ,.o_ch2_m_axis_tkeep (w_ch2_axis_tkeep  )
     ,.o_ch2_m_axis_tlast (w_ch2_axis_tlast  )
     ,.o_ch2_m_axis_tuser (w_ch2_axis_tuser  )
     //------------------video CH3------------------   
     ,.i_ch3_s_aresetn    (w_sys_rst_n       )
     ,.i_ch3_m_aclk       (w_sys_clk         )
     ,.o_ch3_m_axis_tvalid(w_ch3_axis_tvalid )
     ,.i_ch3_m_axis_tready(w_ch3_axis_tready )
     ,.o_ch3_m_axis_tdata (w_ch3_axis_tdata  )
     ,.o_ch3_m_axis_tkeep (w_ch3_axis_tkeep  )
     ,.o_ch3_m_axis_tlast (w_ch3_axis_tlast  )
     ,.o_ch3_m_axis_tuser (w_ch3_axis_tuser  )
     //------------------video CH4------------------
     ,.i_ch4_s_aresetn    (w_sys_rst_n       )
     ,.i_ch4_m_aclk       (w_sys_clk         )
     ,.o_ch4_m_axis_tvalid(w_ch4_axis_tvalid )
     ,.i_ch4_m_axis_tready(w_ch4_axis_tready )
     ,.o_ch4_m_axis_tdata (w_ch4_axis_tdata  )
     ,.o_ch4_m_axis_tkeep (w_ch4_axis_tkeep  )
     ,.o_ch4_m_axis_tlast (w_ch4_axis_tlast  )
     ,.o_ch4_m_axis_tuser (w_ch4_axis_tuser  )
     ); 
    
    //*******************************************************************************
    //part: DDR
    //*******************************************************************************
    
     WR_Frame_Buffer_Ctl_v1_0 helai_WR_FBC(
      .i_axi_rst_n           (w_sys_rst_n               )   
     ,.i_axi_clk             (w_sys_clk                 )
     //--------------CH1 AXIS Port ----------------------/ 
     ,.i_ch1_s_axis_tvalid   (w_ch1_axis_tvalid         )
     ,.o_ch1_s_axis_tready   (w_ch1_axis_tready         )
     ,.i_ch1_s_axis_tdata    (w_ch1_axis_tdata          )
     ,.i_ch1_s_axis_tkeep    (w_ch1_axis_tkeep          )
     ,.i_ch1_s_axis_tlast    (w_ch1_axis_tlast          )
     ,.i_ch1_s_axis_tuser    (w_ch1_axis_tuser          )
     //--------------CH2 AXIS Port ----------------------/  
     ,.i_ch2_s_axis_tvalid   (w_ch2_axis_tvalid         ) 
     ,.o_ch2_s_axis_tready   (w_ch2_axis_tready         ) 
     ,.i_ch2_s_axis_tdata    (w_ch2_axis_tdata          ) 
     ,.i_ch2_s_axis_tkeep    (w_ch2_axis_tkeep          ) 
     ,.i_ch2_s_axis_tlast    (w_ch2_axis_tlast          ) 
     ,.i_ch2_s_axis_tuser    (w_ch2_axis_tuser          ) 
     //--------------CH3 AXIS Port ----------------------/   
     ,.i_ch3_s_axis_tvalid   (w_ch3_axis_tvalid         ) 
     ,.o_ch3_s_axis_tready   (w_ch3_axis_tready         ) 
     ,.i_ch3_s_axis_tdata    (w_ch3_axis_tdata          ) 
     ,.i_ch3_s_axis_tkeep    (w_ch3_axis_tkeep          ) 
     ,.i_ch3_s_axis_tlast    (w_ch3_axis_tlast          ) 
     ,.i_ch3_s_axis_tuser    (w_ch3_axis_tuser          ) 
     //--------------CH4 AXIS Port ----------------------//  
     ,.i_ch4_s_axis_tvalid   (w_ch4_axis_tvalid         ) 
     ,.o_ch4_s_axis_tready   (w_ch4_axis_tready         ) 
     ,.i_ch4_s_axis_tdata    (w_ch4_axis_tdata          ) 
     ,.i_ch4_s_axis_tkeep    (w_ch4_axis_tkeep          ) 
     ,.i_ch4_s_axis_tlast    (w_ch4_axis_tlast          ) 
     ,.i_ch4_s_axis_tuser    (w_ch4_axis_tuser          )
     //--------------Write DDR port --------------------//
     ,.o_wr_dma_baseaddr     (w_DDR_wr_dma_baseaddr     ) 
     ,.o_wr_dma_vsize        (w_DDR_wr_dma_vsize        )
     ,.o_wr_dma_hsize        (w_DDR_wr_dma_hsize        )
     ,.o_wr_dma_stridesize   (w_DDR_wr_dma_stridesize   )
     ,.o_wr_dma_start        (w_DDR_wr_dma_start        )
     ,.o_wr_dma_pause        (w_DDR_wr_dma_pause        )
     ,.o_wr_dma_force_stop   (w_DDR_wr_dma_force_stop   )
     ,.i_wr_dma_busy         (w_DDR_wr_dma_busy         )
     ,.i_wr_dma_done         (w_DDR_wr_dma_done         )
     ,.i_wr_dma_inter_err    (w_DDR_wr_dma_inter_err    )
     ,.i_wr_axi_noack_err    (w_DDR_wr_axi_noack_err    )
     ,.i_wr_dma_parameter_err(w_DDR_wr_dma_parameter_err)
     ,.o_wr_en               (w_DDR_wr_en               )
     ,.o_wr_din              (w_DDR_wr_din              )
     ,.i_wr_full             (w_DDR_wr_full             )
     ,.i_wr_almost_full      (w_DDR_wr_almost_full      )
     ,.i_wr_wr_data_count    (w_DDR_wr_wr_data_count    )
     ,.o_ch1_frame_cnt       (w_ch1_frame_cnt           )
     ,.o_ch2_frame_cnt       (w_ch2_frame_cnt           )
     ,.o_ch3_frame_cnt       (w_ch3_frame_cnt           )
     ,.o_ch4_frame_cnt       (w_ch4_frame_cnt           )
     );

     DDR_Top_v1_0 helai_DDR_Top(
     //globle signal
      .i_rst                 (~w_clk_200MHz_loeked      )                   
     ,.i_ddr_clk_i           (w_clk_200MHz              )                 
     ,.o_sys_clk             (w_sys_clk                 )//目前是100MHz
     ,.o_sys_rst             (                          )
     // DDR port                                        
     ,.ddr3_dq               (io_ddr3_dq                )  
     ,.ddr3_dqs_n            (io_ddr3_dqs_n             )  
     ,.ddr3_dqs_p            (io_ddr3_dqs_p             )  
     ,.ddr3_addr             (o_ddr3_addr               )  
     ,.ddr3_ba               (o_ddr3_ba                 )  
     ,.ddr3_ras_n            (o_ddr3_ras_n              )  
     ,.ddr3_cas_n            (o_ddr3_cas_n              )  
     ,.ddr3_we_n             (o_ddr3_we_n               )  
     ,.ddr3_reset_n          (o_ddr3_reset_n            )  
     ,.ddr3_ck_p             (o_ddr3_ck_p               )  
     ,.ddr3_ck_n             (o_ddr3_ck_n               )  
     ,.ddr3_cke              (o_ddr3_cke                )  
     ,.ddr3_cs_n             (o_ddr3_cs_n               )  
     ,.ddr3_dm               (o_ddr3_dm                 )  
     ,.ddr3_odt              (o_ddr3_odt                )  
     ,.init_calib_complete   (w_ddr_init_done           )
     // Read port                                       
     ,.i_rd_dma_start        (w_DDR_rd_dma_start        )       
     ,.i_rd_dma_base_addr    (w_DDR_rd_dma_base_addr    )
     ,.o_rd_dma_busy         (w_DDR_rd_dma_busy         )
     ,.o_rd_dma_done         (w_DDR_rd_dma_done         )
     ,.i_rd_dma_hsize        (w_DDR_rd_dma_hsize        )         
     ,.i_rd_dma_vsize        (w_DDR_rd_dma_vsize        )        
     ,.i_rd_dma_stridesize   (w_DDR_rd_dma_stridesize   )
     ,.i_rd_frame_start      (w_frame_start             )                
     ,.i_rd_clk              (w_clk_25MHz               )
     ,.i_rd_en               (w_rd_active               )
     ,.o_rd_data_out         (w_image_data              )
     ,.o_rd_data_valid       (                          )
     ,.o_rd_empty            (                          )
     ,.o_rd_almost_empty     (                          )
     ,.o_rd_rd_data_count    (                          )
     ,.o_rd_fifo_wcount      (                          )
     //Write port                                
     ,.i_wr_dma_baseaddr     (w_DDR_wr_dma_baseaddr     ) 
     ,.i_wr_dma_vsize        (w_DDR_wr_dma_vsize        ) 
     ,.i_wr_dma_hsize        (w_DDR_wr_dma_hsize        ) 
     ,.i_wr_dma_stridesize   (w_DDR_wr_dma_stridesize   ) 
     ,.i_wr_dma_start        (w_DDR_wr_dma_start        ) 
     ,.i_wr_dma_pause        (w_DDR_wr_dma_pause        ) 
     ,.i_wr_dma_force_stop   (w_DDR_wr_dma_force_stop   ) 
     ,.o_wr_dma_busy         (w_DDR_wr_dma_busy         ) 
     ,.o_wr_dma_done         (w_DDR_wr_dma_done         )   
     ,.o_wr_dma_inter_err    (w_DDR_wr_dma_inter_err    )     
     ,.o_wr_axi_noack_err    (w_DDR_wr_axi_noack_err    ) 
     ,.o_wr_dma_parameter_err(w_DDR_wr_dma_parameter_err)                              
     ,.i_wr_clk              (w_sys_clk                 ) 
     ,.i_wr_en               (w_DDR_wr_en               ) 
     ,.i_wr_din              (w_DDR_wr_din              ) 
     ,.o_wr_full             (w_DDR_wr_full             ) 
     ,.o_wr_almost_full      (w_DDR_wr_almost_full      ) 
     ,.o_wr_wr_data_count    (w_DDR_wr_wr_data_count    ) 
     );
     
     assign   w_sys_rst_n  = w_ddr_init_done  ; //DDR 初始化完成后,系统其它部分再开始工作   
     
    //*******************************************************************************/ 
    //part: 读DDR                                                                      
    // ******************************************************************************/ 
                                
     //从DDR中读取图像
     Image_Output_IF_Timing_v2_2 #(                     
      .P_H_FRONT_PORCH (`P_VGA_H_FRONT	       )
     ,.P_H_SYNC_PULSE  (`P_VGA_H_SYNC 	       )
     ,.P_H_BACK_PORCH  (`P_VGA_H_BACK 	       )
     ,.P_H_ACT_SIZE    (`P_VGA_H_ACTIVE        )
     ,.P_V_FRONT_PORCH (`P_VGA_V_FRONT	       )
     ,.P_V_SYNC_PULSE  (`P_VGA_V_SYNC 	       )
     ,.P_V_BACK_PORCH  (`P_VGA_V_BACK 	       )
     ,.P_V_ACT_SIZE    (`P_VGA_V_ACTIVE        ) 
     ,.P_FIFO_RCW      (12                     )
     ) helai_read_Image(                       
      .i_clk           (w_clk_25MHz            )//w_sys_clk 
     ,.i_resetn        (w_clk_200MHz_loeked    ) 
                                                       
     ,.i_timing_en     (w_clk_200MHz_loeked    ) 
     ,.o_frame_start   (w_frame_start          )          
     ,.o_frame_done    (                       )                  
     ,.o_vsync         (w_rd_vsync             )          
     ,.o_hsync         (w_rd_hsync             )          
     ,.o_active        (w_rd_active            )     
     ,.o_fvld          (                       )     
     ,.o_sol           (                       ) 
												
     ,.i_axi_clk       (w_sys_clk              )
     ,.i_axi_rst_n     (w_sys_rst_n            )
     ,.o_dma_start     (w_DDR_rd_dma_start     )
     ,.o_dma_base_addr (w_DDR_rd_dma_base_addr )
     ,.o_dma_hsize     (w_DDR_rd_dma_hsize     )
     ,.o_dma_vsize     (w_DDR_rd_dma_vsize     )
     ,.o_dma_stridesize(w_DDR_rd_dma_stridesize)
     ,.i_rd_dma_busy   (w_DDR_rd_dma_busy      )
     ,.i_rd_dma_done   (w_DDR_rd_dma_done      )
     ,.i_ch1_frame_cnt (w_ch1_frame_cnt        )
     ,.i_ch2_frame_cnt (w_ch2_frame_cnt        )
     ,.i_ch3_frame_cnt (w_ch3_frame_cnt        )
     ,.i_ch4_frame_cnt (w_ch4_frame_cnt        )
     ); 
     
    //*******************************************************************************/  
    //part: HDMI display                                                                      
    // ******************************************************************************/    
     rgb2dvi #(                                                              
      .kGenerateSerialClk(1'b0)                              
     ,.kClkRange		 (1   )                                    
     ,.kRstActiveHigh	 (1'b1)                                 
     )helai_HDMI(		                                                          
      // DVI 1.0 TMDS video interface		                                 
      .TMDS_Clk_p (o_tmds_clk_p )                          
     ,.TMDS_Clk_n (o_tmds_clk_n )                          
     ,.TMDS_Data_p(o_tmds_data_p)                         
     ,.TMDS_Data_n(o_tmds_data_n)                             		                                                                     
      //Auxiliary signals 		                                           
     ,.aRst	     (1'b0          )                                      
     ,.aRst_n    (1'b1          )                                        		                                                                     
     // Video in		                                                         
     ,.vid_pData (w_HDMI_data   )//RBG {8'd255,8'd0,8'd0}       
     ,.vid_pVDE	 (w_rd_active   )                                 
     ,.vid_pHSync(w_rd_hsync    )                               
     ,.vid_pVSync(w_rd_vsync    )                               
     ,.PixelClk	 (w_clk_25MHz   )                                                                                                    
     ,.SerialClk (w_clk_125MHz  )// 5x PixelClk            
     );  
     
     //assign  w_HDMI_data  = {w_image_data[23:16],w_image_data[7:0],w_image_data[15:8]};//RBG888输出模式
     assign  w_HDMI_data  = {w_image_data[23:19],w_image_data[21:19],  //上位机显示的图像是由RGB565转换成的RGB888,此处为了做一样的颜色补偿,
                             w_image_data[7:3]  ,w_image_data[5:3]  ,  //采用了这种输出显示的方式                                            
                             w_image_data[15:10],w_image_data[11:10]};
                                                                      
     assign  o_hdmi_en    = 1'b1 ;                                                               
    
endmodule

资源消耗和功耗预估如下:
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第17张图片

9、上板调试验证

由于某些保密因素,暂无法展示输出,请见谅。。。
FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持_第18张图片

10、福利:工程代码的获取

福利:工程代码的获取
代码太大,无法邮箱发送,以某度网盘链接方式发送,
资料获取方式:私,或者文章末尾的V名片。
网盘资料如下:
在这里插入图片描述

你可能感兴趣的:(菜鸟FPGA图像处理专题,PAL/NTSC视频解码,FPGA视频拼接叠加融合,fpga开发,PAL,BT656,TW2867)