zoukankan      html  css  js  c++  java
  • 【转】DE2_TV例程的几点说明

    转自:http://www.cnblogs.com/sunev/archive/2012/05/21/2512149.html

    一、摘要

      对DE2_TV例程做了分析,并阐明了相关概念。

    二、实验平台

      硬件平台:DIY_DE2

      软件平台:Quartus II 9.0 

    三、一些概念及说明

    1、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电视标准用于美、日等国家和地区。

      下面重点说一下PAL制式。PAL一帧的数据行格式如图1所示。

    图1 一帧图像数据行格式

    对于有效数据行的格式,如图2所示

    图2 有效视频行的数据格式

        如上图所示,EAV和SAV为嵌入式控制字,分别表示有效视频的终点和起点。EAV和SAV均为4个字节构成,前3个字节FF、00、00为固定头,“XY”为控制字。“XY”的8个bit含义如下:

    • Bit7(Const),常数,总为1。
    • Bit6(F),场同步信号,表示该行数据处于奇场还是偶场。
    • Bit5(V),垂直同步信号,表示处于场消隐区间还是正程区间(有效数据行)。
    • Bit4(H),水平同步信号,表示是“SAV”还是“EAV”。
    • Bit3-0(P3P2P1P0),纠错位。P3=V(XOR)H;P2=F(XOR)H;P1=F(XOR)V;P0=F(XOR)V(XOR)H。

    EAV与SAV的详细定义如表1所示。

    表1

    Bit7

    Bit6

    Bit5

    Bit4

    Bit3-0(P3P2P1P0)

    Hex

    Description

    1

    0

    0

    0

    0000

    0x80

    Even,Active,SAV

    1

    0

    0

    1

    1101

    0x9d

    Even, Active,EAV

    1

    0

    1

    0

    1011

    0xab

    Even,Blank, SAV

    1

    0

    1

    1

    0110

    0xb6

    Even, Blank, EAV

    1

    1

    0

    0

    0111

    0xc7

    Odd, Active, SAV

    1

    1

    0

    1

    1010

    0xda

    Odd, Active, EAV

    1

    1

    1

    0

    1100

    0xec

    Odd, Blank, SAV

    1

    1

    1

    1

    0001

    0xf1

    Odd, Blank, EAV

      Blanking为水平消隐区,通常由80H/10H来填充。

      对于图2中的Valid data(有效数据)区,其数据排列顺序如图3所示。即Y : Cb : Cr=4 : 2 : 2。从图像的像素点上来理解,就是每个像素点有一个单独的Y值,而相邻的两个像素点的CbCr数据是一样的。

    图3 数据排列顺序

    2、ITU-R BT.601和ITU-R BT.656的区别

      关于这两种信号的区别: 
      ITU-R BT.601: 16位数据传输,21芯;Y、U、V信号并行传输,并有场频和行频传输线。最后更新的文档代号为:ITU-R  BT.601-5。
      ITU-R BT.656: 8位数据传输,9芯;串行视频传输,不需要同步信号;传输速率是601的2倍。最后更新的文档代号为:ITU-R  BT.656-4。

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

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

    3、关于DIY_DE2的视频部分的说明

      DE2视频解码芯片是SAA7181,DIY_DE2采用的视频解码芯片是SAA7113,两种芯片都支持ITU-R BT.656和ITU-R BT.601两种信号接口。SAA7113采用的外部晶振为24.576MHz,经过内部锁相环之后,像素时钟为27MHz,亮度信号时钟为13.5MHz,色差信号时钟为6.75MHz。

      DE2_TV例程是针对NTSC制式的摄像头,而我这里是用的PAL制式的摄像头,视频信号为隔行扫描,奇场在前,偶场在后。使用的视频接口为ITU-R BT.656因此对例程做了些修改。

    四、DE2_TV例程分析

    1、IIC配置视频解码芯片

      具体配置方法上篇博文中已经说明,这里给出配置参数。

    SET_VIDEO+0:    LUT_DATA    <=    16'h0108;
            SET_VIDEO+1:    LUT_DATA    <=    16'h02C3;//default C0
            SET_VIDEO+2:    LUT_DATA    <=    16'h0333;//default 33
            SET_VIDEO+3:    LUT_DATA    <=    16'h0400;//default 00
            SET_VIDEO+4:    LUT_DATA    <=    16'h0500;//default 00
            SET_VIDEO+5:    LUT_DATA    <=    16'h06e9;
            SET_VIDEO+6:    LUT_DATA    <=    16'h070d;
            SET_VIDEO+7:    LUT_DATA    <=    16'h0898;
            SET_VIDEO+8:    LUT_DATA    <=    16'h0901;
            SET_VIDEO+9:    LUT_DATA    <=    16'h0a80;
          
            SET_VIDEO+10:    LUT_DATA    <=    16'h0b47;
            SET_VIDEO+11:    LUT_DATA    <=    16'h0c40;
            SET_VIDEO+12:    LUT_DATA    <=    16'h0d00;
            SET_VIDEO+13:    LUT_DATA    <=    16'h0e01;
            SET_VIDEO+14:    LUT_DATA    <=    16'h0f2a;
            SET_VIDEO+15:    LUT_DATA    <=    16'h1000;
            SET_VIDEO+16:    LUT_DATA    <=    16'h110c;
            SET_VIDEO+17:    LUT_DATA    <=    16'h12b7;
            SET_VIDEO+18:    LUT_DATA    <=    16'h1300;
            SET_VIDEO+19:    LUT_DATA    <=    16'h1500;
          
            SET_VIDEO+20:    LUT_DATA    <=    16'h1600;
            SET_VIDEO+21:    LUT_DATA    <=    16'h1700;
            SET_VIDEO+22:    LUT_DATA    <=    16'h4002;
            SET_VIDEO+23:    LUT_DATA    <=    16'h41ff;
            SET_VIDEO+24:    LUT_DATA    <=    16'h42ff;
            SET_VIDEO+25:    LUT_DATA    <=    16'h43ff;
            SET_VIDEO+26:    LUT_DATA    <=    16'h44ff;
            SET_VIDEO+27:    LUT_DATA    <=    16'h45ff;
            SET_VIDEO+28:    LUT_DATA    <=    16'h46ff;
            SET_VIDEO+29:    LUT_DATA    <=    16'h47ff;
          
            SET_VIDEO+30:    LUT_DATA    <=    16'h48ff;
            SET_VIDEO+31:    LUT_DATA    <=    16'h49ff;
            SET_VIDEO+32:    LUT_DATA    <=    16'h4aff;
            SET_VIDEO+33:    LUT_DATA    <=    16'h4bff;
            SET_VIDEO+34:    LUT_DATA    <=    16'h4cff;
            SET_VIDEO+35:    LUT_DATA    <=    16'h4dff;
            SET_VIDEO+36:    LUT_DATA    <=    16'h4eff;
            SET_VIDEO+37:    LUT_DATA    <=    16'h4fff;
            SET_VIDEO+38:    LUT_DATA    <=    16'h50ff;
            SET_VIDEO+39:    LUT_DATA    <=    16'h51ff;
            SET_VIDEO+40:    LUT_DATA    <=    16'h52ff;
          
            SET_VIDEO+41:    LUT_DATA    <=    16'h53ff;
            SET_VIDEO+42:    LUT_DATA    <=    16'h54ff;
            SET_VIDEO+43:    LUT_DATA    <=    16'h55ff;
            SET_VIDEO+44:    LUT_DATA    <=    16'h56ff;
            SET_VIDEO+45:    LUT_DATA    <=    16'h57ff;
            SET_VIDEO+46:    LUT_DATA    <=    16'h5800;
            SET_VIDEO+47:    LUT_DATA    <=    16'h5954;
            SET_VIDEO+48:    LUT_DATA    <=    16'h5a07;
            SET_VIDEO+49:    LUT_DATA    <=    16'h5b83;
            SET_VIDEO+50:    LUT_DATA    <=    16'h5e00;

    2、视频采集、解码及视频裁剪部分

      由于采用PAL制式的摄像机,其视频画面的有效分辨率为720*576,即总共576行(分奇偶两场,各占288行),每行720个像素点,由于是8位串行输出,因此每行总共有1440个字节。

      视频解码文件完成的任务就是:通过判断SAV信号,来判断接下来的数据是否为有效视频数据,如果是,则进一步分离出有效数据的同步信号oDVAL和有效数据Y、Cb、Cr。

      视频的裁剪是通过一个除法器辅助完成的,主要是对每行视频数据进行裁剪,从720个像素裁剪到640像素。除数为当前视频行的当前字节数右移1位,被除数为9。也就是说,每9个像素中,有一个像素点被裁剪掉,即720-720/9=640。具体代码如下。

     if(iSwap_CbCr)
            begin
                case(Cont[1:0])        //    Swap
                0:    Cb        <=     iTD_DATA;
                1:    YCbCr    <=    {iTD_DATA,Cr};
                2:    Cr        <=     iTD_DATA;
                3:    YCbCr    <=    {iTD_DATA,Cb};
                endcase
            end
            else
            begin
                case(Cont[1:0])        //    Normal
                0:    Cb        <=     iTD_DATA;
                1:    YCbCr    <=    {iTD_DATA,Cb};
                2:    Cr        <=     iTD_DATA;
                3:    YCbCr    <=    {iTD_DATA,Cr};
                endcase
            end

    上述代码中,iSwap_CbCr除数除以被除数的商,Cont为当前视频行的当前字节数,下面以例子示之。

     

    Cont[1:0]         00  01  10  11  00  01  10  11  00  01  10  11  00  01  10  11  00  01  10  11  00  01  10  11

    iSwap_CbCr       0    0   0    0    0    0    0    0    0    0    0    0    0   0    0    0    0    0    1    1    1    1    1    1

    iTD_DATA         Cb1 Y1 Cr1 Y2 Cb2 Y3 Cr2 Y4 Cb3 Y5 Cr3 Y6  Cb4 Y7 Cr4 Y8 Cb5 Y9 Cr5 Y10 Cb6 Y11 Cr6 Y12

    YCbCr                Y1Cb1  Y2Cr1  Y3Cb2  Y4Cr2  Y5Cb3  Y6Cr3   Y7Cb4  Y8Cr4  Y9Cb5  Y10Cb5  Y11Cr5  Y12Cb6

     

      从上述例子可以看出,每4个时钟周期输出2个像素值,即输出像素值的频率减小了一半,这与分离出来的同步信号oDVAL的时钟频率一样,同为13.5MHz

      另外,裁剪部分,由于Y9Cb5与Y10Cb5有很大的相似性,这里应该是将Y9Cb5剔除,但是具体在什么位置剔除,却不得而知。莫非是分析错误?求解。

    3、视频数据存取

       存储在SDRAM采用的是1入2出的模式,即一个端口写入,2个端口读出。存取数据的代码如下:

    //    SDRAM frame buffer
    Sdram_Control_4Port    u6    (    //    HOST Side
                                .REF_CLK(CLOCK_50),
                                //.CLK_18(AUD_CTRL_CLK),
                                .RESET_N(1'b1),
                                //    FIFO Write Side 1
                                .WR1_DATA(YCbCr),
                                .WR1(TV_DVAL),
                                .WR1_FULL(WR1_FULL),
                                .WR1_ADDR(0),
                                .WR1_MAX_ADDR(640*576),        //    525-18
                                .WR1_LENGTH(9'h80),
                                .WR1_LOAD(!DLY0),
                                .WR1_CLK(PPI_CLK),
                                //    FIFO Read Side 1
                                .RD1_DATA(m1YCbCr),
                                .RD1(m1VGA_Read),
                                .RD1_ADDR(640*12),            //    Read odd field and bypess blanking
                                .RD1_MAX_ADDR(640*252),
                                .RD1_LENGTH(9'h80),
                                .RD1_LOAD(!DLY0),
                                .RD1_CLK(PPI_CLK),
                                //    FIFO Read Side 2
                                .RD2_DATA(m2YCbCr),
                                .RD2(m2VGA_Read),
                                .RD2_ADDR(640*300),            //    Read even field and bypess blanking
                                .RD2_MAX_ADDR(640*540),
                                .RD2_LENGTH(9'h80),
                                .RD2_LOAD(!DLY0),
                                .RD2_CLK(PPI_CLK),
                                //    SDRAM Side
                                .SA(DRAM0_A),
                                .BA(DRAM0_BA),
                                .CS_N(DRAM0_CS),
                                .CKE(DRAM0_CKE),
                                .RAS_N(DRAM0_RAS),
                                .CAS_N(DRAM0_CAS),
                                .WE_N(DRAM0_WE),
                                .DQ(DRAM0_D),
                                .DQM(DRAM0_DQM),
                                .SDR_CLK(DRAM0_CLK)    );

    经过裁剪后的视频分辨率为640*576。

      写入SDRAM中时,是将640*576个像素全部写入进去,由于是奇场数据在前,偶场数据在后,因此前640*288行数据为奇场数据,后 640*288行数据为偶场数据。

      读取视频数据时,采用乒乓操作,先后读取奇偶场的数据,各240行,组成一幅完整的画面,读取方法如下:

    1

    ……

    11

    读取12到251行,共240行

    252

    ……

    288

    以上为奇数场数据,以下为偶数场数据

    289

    ……

    299

    读取300到539行,共240行

    540

    ……

    576

      其中,1~288行为奇数场数据,289~576为偶数场数据。上述数据是从11~251,300~539读取的,当然也可以从1~240,289~529读取,只要满足奇偶场的起始行为相邻行,且保证奇数场的数据行在前即可。

      因此,最后得到的视频分辨率为640*480.

    4、色彩空间转换

       进行色彩空间转换之前,对视频行数据进行了简单的算法处理,代码如下:

    //    Line buffer, delay one line
    Line_Buffer u10    (    .clken(VGA_Read),
                        .clock(PPI_CLK),
                        .shiftin(mYCbCr_d),
                        .shiftout(m3YCbCr));
    
    Line_Buffer u11    (    .clken(VGA_Read),
                        .clock(PPI_CLK),
                        .shiftin(m3YCbCr),
                        .shiftout(m4YCbCr));
    
    wire    [15:0]    m4YCbCr;
    wire    [15:0]    m5YCbCr;
    wire    [8:0]    Tmp1,Tmp2;
    wire    [7:0]    Tmp3,Tmp4;
    
    assign    Tmp1    =    m4YCbCr[7:0]+mYCbCr_d[7:0];
    assign    Tmp2    =    m4YCbCr[15:8]+mYCbCr_d[15:8];
    assign    Tmp3    =    Tmp1[8:2]+m3YCbCr[7:1];
    assign    Tmp4    =    Tmp2[8:2]+m3YCbCr[15:9];
    assign    m5YCbCr    =    {Tmp4,Tmp3};

    对视频行进行了加和及数乘运算。最后将YUV 4:2:2先转换为YUV4:4:4的形式,之后再通过公式转换成RGB色彩空间,最后通过VGA显示在显示器上。

  • 相关阅读:
    获取程序的当前启动路径
    SuspendLayout,ResumeLayout,Layout,PerformLayout
    序列化反序列化的简单例子
    简单的异步编程入门例子
    ClickOnce的更新策略
    ubuntu update(国内升级源)
    为AptGet设置代理
    如何启用 Ubuntu 中的 root 帐号
    The Great Tunnel Debate: PBT vs TMPLS
    Traffic engineering for Ethernet: PBT vs. TMPLS
  • 原文地址:https://www.cnblogs.com/woshitianma/p/3045284.html
Copyright © 2011-2022 走看看