基于FPGA实现PAL视频接口(附代码)

目录

1.PAL制概述

2.PAL和NTSC的区别

3.ITU-RBT.601和ITU-RBT.656的区别

4.​​​​​​PAL制与NTSC制的判定

5.隔行扫描成像(场)

6.场同步和行同步

​​​​​​​7.PAL制国标参数

​​​​​​​8.PAL制行信号采样点计数

​​​​​​​9.信号行场同步头以及消隐信号的具体时间参数

​​​​​​​10.隔行数字分量视频

11.基于FPGA实现PAL制接口代码


之前做项目过程中,需要通过PAL制接口实现图像显示。今天刚好有时间,将实现过程记录一下。

1.PAL制概述

场正程:是指场扫描周期中电子束由上到下的扫描。

场逆程:是指场扫描周期中电子束由下面返回到初始位置。且场正程时间远大于场逆程时间,两者相加为场周期,场周期的倒数是场频。

美国制定电视机标准如下:

1)每一划面525条水平扫描线;

2)每秒30张(Frame);

3)采用交错式扫描(Interlace,"交错式"),每秒60个图场(Field)。

由于制定该标准的是"美国电子工业协会",英文是"Electronics Industry Association"简写就是"EIA",因此黑白电视的美规就叫"EIA"。后来发明了彩色电视,这时候是由"国家电视系统委员会"来制定标准的,英文是"National Television System Committee"简称为"NTSC",因此NTSC是彩色系统中的美规。NTSC制式是1952年美国国家电视标准委员会定义的彩色电视广播标准,称为正交平衡调幅制。525/行帧,30帧/秒(29.97fps,33.37ms/frame);高宽比,电视画面的长宽比(电视为4:3;电影为3:2;高清晰度电视为16:9);隔行扫描,一帧分成2场(field),262.5线/场在每场的开始部分保留20扫描线作为控制信息,因此只有485条线的可视数据;每行63.5μs,水平回扫时间10μs(包含5μs的水平同步脉冲),所以显示时间是53.5μs;颜色模型:YIQ。一帧图像的总行数为525行,分两场扫描。行扫描频率为15750Hz,周期为63.5μs;场扫描频率是60Hz,周期为16.67ms;帧频是30Hz,周期33.33ms。每一场的扫描行数为525/2=262.5行。除了两场的场回扫外,实际传送图像的行数为480行。

欧洲电视标准规格如下:

1)每一划面625条水平扫描线;

2)每秒25张(Frame);

3)采用交错式扫描(Interlace,"交错式"),每秒50个图场(Field)。

制定该标准的是"Committee Consultation International Radio Telecommunique"国际无线通讯咨询委员会,简称"CCIR"。因此CCIR就是欧规的黑白系统。进入彩色时代,由于彩电的原理是在原有黑白讯号上加上彩色系色波(Color Carrier),每条扫描线有一个系色波,用改变相位的方式得到每条线的颜色,在英文上的说法是"Phase Alternate(交替) Line"简写就是PAL,因此PAL就是欧规的彩色系统。由于NTSC制存在相位敏感造成彩色失真的缺点,因此德国于1962年制定了PAL(Phase-Alternative Line)制彩色电视广播标准,称为逐行倒相正交平衡调幅制。625行(扫描线)/帧,25帧/秒(40ms/帧);长宽比(aspectratio):4:3;隔行扫描,2场/帧,312.5行/场;颜色模型:YUV。PAL制式中根据不同的参数细节,又可以进一步划分为G、I、D等制式,其中PAL-D制是中国大陆采用的制式。

一般来讲,EIA代表美规黑白,NTSC代表美规彩色;CCIR代表欧规黑白,PAL代表欧规彩色。但现在大家都把NTSC当做"N制"或美规的意思,所以黑白说NTSC也没啥不对。同样的PAL是"P制"或欧规的意思,把黑白说成PAL也行。其实两种标准中的30、60、25、50都跟交流电有关,当时美国电源频率是60Hz,而欧洲是50Hz。

2.PAL和NTSC的区别

常见的电视信号制式是PAL和NTSC,另外还有SECAM等。NTSC即正交平衡调幅制,PAL为逐行倒像正交平衡调幅制。

(1)PAL电视标准

PAL电视标准,每秒25帧,电视扫描线为625线,奇场在前,偶场在后,标准的数字化PAL电视标准分辨率为720×576,24比特的色彩位深,画面的宽高比为4:3,PAL电视标准用于中国、欧洲等国家和地区。

(2)NTSC电视标准

NTSC电视标准,每秒29.97帧(简化为30帧),电视扫描线为525线,偶场在前,奇场在后,标准的数字化NTSC电视标准分辨率为720×486,24比特的色彩位深,画面的宽高比为4:3。NTSC电视标准用于美、日等国家和地区。

3.ITU-RBT.601和ITU-RBT.656的区别

关于这两种信号的区别:

ITU-RBT.601:16位数据传输,21芯;Y、U、V信号并行传输,并有场频和行频传输线。最后更新的文档代号为:ITU-RBT.601-5。

ITU-RBT.656:8位数据传输,9芯;串行视频传输,不需要同步信号;传输速率是601的2倍。最后更新的文档代号为:ITU-RBT.656-4。

656输出的是串行数据,行场同步信号嵌入在数据流中,601是并行数据,行场同步有单独输出。

656只是数据传输接口而已,可以说是作为601的一个传输方式。简单的说ITU-RBT.601是"演播室数字电视编码参数"标准,而ITU-RBT.656则是ITU-RBT.601附件A中的数字接口标准,用于主要数字视频设备(包括芯片)之间采用27MHz/s并口或243Mb/s串行接口的数字传输接口标准。

4.​​​​​​PAL制与NTSC制的判定

​​​​​​​5.隔行扫描成像(场)

在了解中国电视的相关标准之前,先必需彻底的了解Field(场)概念。场是由电视接收图像信号成像的方式决定的。目前,世界各国的电视都是采用了隔行扫描成像的方式,这和我们使用的电脑显示器成像(逐行扫描)是不一样的。

逐行扫描:每一帧图像都是由一排排的像素构成的,电脑显示器就是从最左侧的第一个像素扫描并显示,扫描完成第一行之后,就会扫描第二行,直到扫描完整个屏幕。如果用电脑全屏播放视频的话,每秒钟显示器能扫描25帧。

隔行扫描:将一个完整的画面分割成两个场,分为上场和下场。先扫描完上场的内容,再扫描下场的内容。两个场都扫描完成后,合成一张完整的画面。这样做的好处是电视内容通过卫星、有线等进行传输的时候,每次发送的内容少了一半,这极大的提高了传输效率。由于每次发送的内容只有一半,因此25fps每秒的图像,需要不断的发送50次才能显示完整的1s内容。这就是我们熟知的电视刷新率为50Hz,说的就是每秒钟能扫描50场的意思。国外使用NTSC制的电视,刷新率为60Hz,代表每秒钟扫描60场。

​​​​​​​6.场同步和行同步

场同步(Vertical Sync):指定新图像从什么时候开始显示。

行同步(Horizontal Sync):指定新扫描线什么时候开始显示。

​​​​​​​7.PAL制国标参数

行场信号的具体长度时间参数:

完整的PAL制视频信号波形:

​​​​​​​8.PAL制行信号采样点计数

9.信号行场同步头以及消隐信号的具体时间参数

10.隔行数字分量视频

11.基于FPGA实现PAL制接口代码

复制代码
----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 2021/10/08 19:57:38
-- Design Name: 
-- Module Name: pal_sync_blank - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;



entity pal_sync_blank is
    generic(
			LINE_NUM            : 			integer := 944		--944
    );
    port(
			clk                 : 	in 		std_logic; --14.75MHz	
			rst               	: 	in 		std_logic;
				
			sync                : 	out 	std_logic;
			blank               : 	out 	std_logic;
			odd_even            :	out 	std_logic;
			rd_rom_en           : 	buffer  std_logic
    );
end pal_sync_blank;

architecture Behavioral of pal_sync_blank is

    constant 	LINE_NUM_HALF        : 	integer := 433;		--432
    constant 	Time_1p5us           : 	integer := 20;
    constant 	Time_2p35us          : 	integer := 32;
    constant 	Time_4p7us           : 	integer := 63;
    constant 	Time_5p8us           : 	integer := 78;
    signal		cnt_h                : 	std_logic_vector(9 downto 0) := (others => '0');
    signal		cnt_v                : 	std_logic_vector(9 downto 0) := (others => '0');
    signal		blank_nx_1           : 	std_logic := '0';
    signal		blank_nx_2           : 	std_logic := '0';
    signal		vsync_nx             : 	std_logic := '0';		
	signal		drow_en				 :	std_logic := '0';
	

begin


    process(rst,clk)
    begin
        if  rst = '1' then
            cnt_h <= (others => '0');
        elsif rising_edge(clk) then
            if cnt_h = LINE_NUM - 1 then     --行周期64us
                cnt_h <= (others => '0');
            else
                cnt_h <= cnt_h + 1;
            end if;
        end if;
    end process;
    
	
    process(rst,clk)
    begin
        if  rst = '1' then
            cnt_v <= (others => '0');
        elsif rising_edge(clk) then
            if cnt_h = LINE_NUM - 1 then
                if cnt_v = 624 then
                    cnt_v <= (others => '0');
                else
                    cnt_v <= cnt_v + 1;
                end if;
            end if;
        end if;
    end process;
    
	
    process(rst,clk)
    begin
        if  rst = '1' then
            blank_nx_1 <= '0';         --同步
        elsif rising_edge(clk) then
            case conv_integer(cnt_v) is
                when 0 | 1 | 313 | 314 =>   --垂直同步脉冲
                    if cnt_h < (LINE_NUM_HALF - Time_4p7us) or (cnt_h > LINE_NUM_HALF and cnt_h <= (LINE_NUM - Time_4p7us)) then
                        blank_nx_1 <= '0';
                    else
                        blank_nx_1 <= '1';
                    end if;
                when 2 =>   --垂直同步脉冲到后均衡脉冲切换
                    if cnt_h < (LINE_NUM_HALF - Time_4p7us) or (cnt_h > LINE_NUM_HALF and cnt_h <= (LINE_NUM_HALF + Time_2p35us)) then
                        blank_nx_1 <= '0';
                    else
                        blank_nx_1 <= '1';
                    end if;
                when 312 => --预均衡脉冲到垂直同步脉冲切换
                    if cnt_h < Time_2p35us or (cnt_h > LINE_NUM_HALF and cnt_h <= (LINE_NUM - Time_4p7us)) then
                        blank_nx_1 <= '0';
                    else
                        blank_nx_1 <= '1';
                    end if;
                when 317 => --后均衡脉冲到行同步切换
                    if cnt_h < Time_2p35us then
                        blank_nx_1 <= '0';
                    else
                        blank_nx_1 <= '1';
                    end if;
                when 622 => --行同步到预均衡脉冲切换
                    -- if cnt_h <= (LINE_NUM - 768 - Time_1p5us) or (cnt_h > LINE_NUM_HALF and cnt_h <= (LINE_NUM_HALF + Time_2p35us)) then
                    if cnt_h < Time_4p7us or (cnt_h > LINE_NUM_HALF and cnt_h <= (LINE_NUM_HALF + Time_2p35us)) then
                        blank_nx_1 <= '0';
                    else
                        blank_nx_1 <= '1';
                    end if;
                when 3 | 4 | 310 | 311 | 315 | 316 | 623 | 624 =>   --预均衡和后均衡脉冲 
                    if cnt_h < Time_2p35us or (cnt_h > LINE_NUM_HALF and cnt_h <= (LINE_NUM_HALF + Time_2p35us)) then
                        blank_nx_1 <= '0';
                    else
                        blank_nx_1 <= '1';
                    end if;
                when others =>  --行同步
                    if cnt_h < Time_4p7us then      --(LINE_NUM - 768 - Time_1p5us - Time_5p8us) then
                        blank_nx_1 <= '0';
                    else
                        blank_nx_1 <= '1';
                    end if;
            end case;
        end if;
    end process;
    
	
    process(rst,clk)
    begin
        if  rst = '1' then
            blank_nx_2 <= '0';        --消隐
        elsif rising_edge(clk) then
            case conv_integer(cnt_v) is 
                when 22 => 
                    if cnt_h >= (LINE_NUM - 384 - Time_1p5us) and cnt_h < (LINE_NUM - Time_1p5us) then
                        blank_nx_2 <= '1';
                    else
                        blank_nx_2 <= '0';
                    end if;
                when 622 => 
                    if cnt_h >= (LINE_NUM - 768 - Time_1p5us) and cnt_h < (LINE_NUM_HALF - Time_1p5us) then
                        blank_nx_2 <= '1';
                    else
                        blank_nx_2 <= '0';
                    end if;
                when others =>
                    if cnt_h >= (LINE_NUM - 768 - Time_1p5us) and cnt_h < (LINE_NUM - Time_1p5us) then
                    -- if cnt_h >= (Time_4p7us + Time_1p5us) and cnt_h < (Time_4p7us + Time_1p5us + 768) then
                        blank_nx_2 <= '1';
                    else
                        blank_nx_2 <= '0';
                    end if;
            end  case;
        end if;
    end process;
    
	
    process(rst,clk)
    begin
        if  rst = '1' then
            vsync_nx <= '0';
        elsif rising_edge(clk) then
            if (cnt_v > 21 and cnt_v < 310) or (cnt_v > 334 and cnt_v < 623) then
                vsync_nx <= '1';
            else
                vsync_nx <= '0';
            end if;
        end if;
    end process;
    
	
    process(rst,clk)
    begin
        if  rst = '1' then
            sync        <= '1';
            blank       <= '1';
        elsif rising_edge(clk) then
            sync        <= blank_nx_1;
            blank       <= blank_nx_2 and vsync_nx;    
        end if;
    end process;
	

	-- process(rst,clk)
	-- begin
		-- if rst = '1' then
			-- drow_en	 <= '0';
		-- elsif rising_edge (clk) then
			-- case conv_integer(cnt_v) is 
                -- when 40 => 									
					-- drow_en	<= '1';
                -- when 296 => 								
					-- drow_en <= '0';
                -- when 353 =>  			
					-- drow_en	<= '1';
                -- when 609 => 			
					-- drow_en	<= '0';
                -- when others =>
					-- drow_en	<= drow_en;
            -- end  case;
		-- end if;	
	-- end process;
	
	process(rst,clk)
	begin
		if rst = '1' then
			drow_en	 <= '0';
		elsif rising_edge (clk) then
			case conv_integer(cnt_v) is 
                when 41 => 									
					drow_en	<= '1';
                when 297 => 								
					drow_en <= '0';
                when 353 =>  			
					drow_en	<= '1';
                when 609 => 			
					drow_en	<= '0';
                when others =>
					drow_en	<= drow_en;
            end  case;
		end if;	
	end process;

	
	process(rst,clk)
	begin
		if rst = '1' then
			rd_rom_en <= '0';
		elsif rising_edge (clk) then
			if drow_en = '1' then
				case conv_integer(cnt_h) is 
					when 168 => 				
						rd_rom_en <= '1';
					when 808 => 
						rd_rom_en <= '0';
					when others =>
						rd_rom_en <= rd_rom_en;
				end case;
			else
				rd_rom_en <= '0';
			end if;
		end if;
	end process;
	
	

    process(rst,clk)
    begin
        if rst = '1' then
            odd_even <= '0';
        elsif rising_edge(clk) then
            if cnt_v < 312 then
                odd_even <= '1';				
            elsif cnt_v = 312 then
                if cnt_h <= LINE_NUM_HALF then
                    odd_even <= '1';			
                else
                    odd_even <= '0';			
                end if;
            else
                odd_even <= '0';
            end if;
        end if;
    end process;



end Behavioral;
相关推荐
国科安芯3 小时前
多相交错并联系统的时钟同步精度与输入纹波抵消效应研究
网络·单片机·嵌入式硬件·fpga开发·性能优化
科恒盛远1 天前
KH919-基于FPGA实现的线性调频卡
fpga开发
Hy行者勇哥2 天前
Seedance 全面解析:定义、使用指南、同类软件与完整攻略
人工智能·学习方法·视频
FPGA小c鸡2 天前
PCIe接口详解:从协议原理到FPGA实现的完整指南
fpga开发
良许Linux2 天前
FPGA原理和应用
stm32·单片机·fpga开发·程序员·嵌入式·编程
Hello.Reader2 天前
Flink External Resource Framework让作业“原生”申请 GPU/FPGA 等外部资源
大数据·fpga开发·flink
嵌入式-老费2 天前
Linux Camera驱动开发(fpga vs soc)
驱动开发·fpga开发
aaaffaewrerewrwer3 天前
2026年好用的 AVIF 转 WebP 在线工具推荐(支持批量转换)
图像处理·安全
太空1号3 天前
SystemVerilog小白入门3,UVM的uvm_object初体验
fpga开发