关于DE2_115_TV范例的说明
我自从去年开始接触DE2_115开发板,主要研究的是视频处理算法,因此想好好研究一下TV范例,不过限于当时水平有限很多模块的代码,还没有弄的很明白。前几天又用到它了,决定再好好研究一下。经过了2天的研究,收获还是不少的,很多代码终于看明白了,于是决定分享一下我的看法。
首先我觉得大家需要了解一下PAL、NTSC以及ITU-R BT.656。详见:http://www.cnblogs.com/sunev/archive/2012/05/21/2512149.html
1.TD_Detect模块
1 module TD_Detect( 2 oTD_Stable, 3 oNTSC, 4 oPAL, 5 iTD_VS, 6 iTD_HS, 7 iRST_N ); 8 input iTD_VS; 9 input iTD_HS; 10 input iRST_N; 11 output oTD_Stable; 12 output oNTSC; 13 output oPAL; 14 reg NTSC; 15 reg PAL; 16 reg Pre_VS; 17 reg [7:0] Stable_Cont; 18 /********************************************************* 19 垂直同步信号: 20 1 0 1 1 0 1 21 ---|___|------------------------|___|--- 22 消隐 消隐 23 24 在垂直消隐期间(!iTD_VS),对iTD_HS即行数进行计数来判断PAL或NTSC, 25 且结果在{Pre_VS,iTD_VS}==2'b01时完成判断,只要第一次判断出制式, 26 oTD_Stable就一直是1。 27 *********************************************************/ 28 assign oTD_Stable = NTSC || PAL; 29 assign oNTSC = NTSC; 30 assign oPAL = PAL; 31 32 always@(posedge iTD_HS or negedge iRST_N) 33 if(!iRST_N) 34 begin 35 Pre_VS <= 1'b0; 36 Stable_Cont <= 4'h0; 37 NTSC <= 1'b0; 38 PAL <= 1'b0; 39 end 40 else 41 begin 42 Pre_VS <= iTD_VS; 43 if(!iTD_VS) 44 Stable_Cont <= Stable_Cont+1'b1; 45 else 46 Stable_Cont <= 0; 47 //判断是PAL还是NTSC,为了后面的sdram分配存储空间做准备 48 if({Pre_VS,iTD_VS}==2'b01)//通过垂直消隐期间的行数来判断 49 begin 50 if((Stable_Cont>=4 && Stable_Cont<=14)) 51 NTSC <= 1'b1; 52 else 53 NTSC <= 1'b0; 54 55 if((Stable_Cont>=8'h14 && Stable_Cont<=8'h1f)) 56 PAL <= 1'b1; 57 else 58 PAL <= 1'b0; 59 end 60 end 61 62 endmodule
2.Reset_Delay模块
1 module Reset_Delay(iCLK,iRST,oRST_0,oRST_1,oRST_2); 2 input iCLK; 3 input iRST; 4 output reg oRST_0; 5 output reg oRST_1; 6 output reg oRST_2; 7 8 reg [21:0] Cont; 9 10 always@(posedge iCLK or negedge iRST) 11 begin 12 if(!iRST)//TD_Detect 模块的oTD_Stable信号做为复位信号,检测不到正常的格式则复位。 13 begin 14 Cont <= 0; 15 oRST_0 <= 0; 16 oRST_1 <= 0; 17 oRST_2 <= 0; 18 end 19 else 20 begin 21 if(Cont!=22'h3FFFFF) 22 Cont <= Cont+1; 23 if(Cont>=22'h1FFFFF) 24 oRST_0 <= 1; //oRST_0最先恢复正常,sdram、linebuffer等 25 if(Cont>=22'h2FFFFF) 26 oRST_1 <= 1;//oRST_1第二恢复正常,ITU_656 Decoder 27 if(Cont>=22'h3FFFFF) 28 oRST_2 <= 1;//oRST_2最后恢复正常,其他模块 29 end 30 end 31 32 endmodule
3.ITU_656_Decoder模块
1 /***************************************************** 2 本模块实现去除消隐区,并将一行720个像素减为640个 3 详见:http://www.cnblogs.com/sunev/archive/2012/05/21/2512149.html 4 *****************************************************/ 5 module ITU_656_Decoder( // TV Decoder Input 6 iTD_DATA, 7 // Position Output 8 oTV_X, 9 oTV_Y, 10 oTV_Cont, 11 // YUV 4:2:2 Output 12 oYCbCr, 13 oDVAL, 14 // Control Signals 15 iSwap_CbCr, 16 iSkip, 17 iRST_N, 18 iCLK_27 ); 19 input [7:0] iTD_DATA; 20 input iSwap_CbCr; 21 input iSkip; 22 input iRST_N; 23 input iCLK_27; 24 output [15:0] oYCbCr; 25 output [9:0] oTV_X; 26 output [9:0] oTV_Y; 27 output [31:0] oTV_Cont; 28 output oDVAL; 29 30 // For detection 31 reg [23:0] Window; // Sliding window register 32 reg [17:0] Cont; // Counter 33 reg Active_Video; 34 reg Start; 35 reg Data_Valid; 36 reg Pre_Field; 37 reg Field; 38 wire SAV; 39 reg FVAL; 40 reg [9:0] TV_Y; 41 reg [31:0] Data_Cont; 42 43 // For ITU-R 656 to ITU-R 601 串转并 44 reg [7:0] Cb; 45 reg [7:0] Cr; 46 reg [15:0] YCbCr; 47 48 assign oTV_X = Cont>>1; // Cont/2 :像素的位置 49 assign oTV_Y = TV_Y; 50 assign oYCbCr = YCbCr; 51 assign oDVAL = Data_Valid; 52 assign SAV = (Window==24'hFF0000)&(iTD_DATA[4]==1'b0);//iTD_DATA[4] 0:SAV,1:EAV 53 assign oTV_Cont= Data_Cont; 54 55 always@(posedge iCLK_27 or negedge iRST_N) 56 begin 57 if(!iRST_N) 58 begin 59 // Register initial 60 Active_Video<= 1'b0; 61 Start <= 1'b0; 62 Data_Valid <= 1'b0; 63 Pre_Field <= 1'b0; 64 Field <= 1'b0; 65 Window <= 24'h0; 66 Cont <= 18'h0; 67 Cb <= 8'h0; 68 Cr <= 8'h0; 69 YCbCr <= 16'h0; 70 FVAL <= 1'b0; 71 TV_Y <= 10'h0; 72 Data_Cont <= 32'h0; 73 end 74 else 75 begin 76 // Sliding window 77 Window <= {Window[15:0],iTD_DATA}; 78 // Active data counter 79 if(SAV) //SAV区域 80 Cont <= 18'h0; 81 else if(Cont<1440) 82 Cont <= Cont+1'b1;//Cont为YC的个数 83 // Check the video data is active? 84 if(SAV) 85 Active_Video<= 1'b1; 86 else if(Cont==1440) 87 Active_Video<= 1'b0; 88 // Is frame start? 89 Pre_Field <= Field; 90 if({Pre_Field,Field}==2'b10) //奇场———>偶场 91 Start <= 1'b1; 92 // Field and frame valid check 93 if(Window==24'hFF0000) // SAV : FF 00 00 XY 94 /******************************* 95 详见:http://www.cnblogs.com/sunev/archive/2012/05/21/2512149.html 96 表1. 97 iTD_DATA[5]是 垂直同步信号。1:消隐,0:有效数据 98 iTD_DATA[6]是 场同步信号,表示该行数据处于奇场还是偶场。1:奇场,0:偶场 99 *******************************/ 100 begin 101 FVAL <= !iTD_DATA[5]; 102 Field <= iTD_DATA[6]; 103 end 104 105 // ITU-R 656 to ITU-R 601 106 /**************************************** 107 分子:[9:0]接oTV_X, 分母:[3:0],常数9. 108 商:[9:0] 接iSwap_CbCr。余数:[3:0],==? 109 Swap_CbCr除数除以被除数的商,Cont为当前视频行的当前字节数,下面以例子示之。 110 111 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 112 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 113 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 114 YCbCr Y1Cb1 Y2Cr1 Y3Cb2 Y4Cr2 Y5Cb3 Y6Cr3 Y7Cb4 Y8Cr4 Y9Cb5 Y10Cb5 Y11Cr5 Y12Cb6 115 116 ****************************************/ 117 if(iSwap_CbCr) 118 begin 119 case(Cont[1:0]) // Swap,Cont[1:0]=00,01,10,11. 120 0: Cb <= iTD_DATA; 121 1: YCbCr <= {iTD_DATA,Cr}; 122 2: Cr <= iTD_DATA; 123 3: YCbCr <= {iTD_DATA,Cb}; 124 endcase 125 end 126 else //iSwap_CbCr =0 127 begin 128 case(Cont[1:0]) // Normal 129 0: Cb <= iTD_DATA;//Cb 8bit临时寄存器,将8bit iTD_DATA中的Cb保存 130 1: YCbCr <= {iTD_DATA,Cb};//YCbCr 16bit, =iTD_DATA中的Y + Cb 131 2: Cr <= iTD_DATA; 132 3: YCbCr <= {iTD_DATA,Cr}; 133 endcase 134 end 135 // Check data valid 136 if( Start // Frame Start? 137 && FVAL // Frame valid? FVAL==1,即iTD_DATA[5]=0,处于有效数据区!! 138 && Active_Video // Active video? 139 && Cont[0] // Complete ITU-R 601? 140 && !iSkip ) // Is non-skip pixel? 141 Data_Valid <= 1'b1; //有效数据 142 else 143 Data_Valid <= 1'b0; 144 // TV decoder line counter for one field 145 if(FVAL && SAV) 146 TV_Y<= TV_Y+1; 147 if(!FVAL) 148 TV_Y<= 0; 149 // Data counter for one field 150 if(!FVAL) 151 Data_Cont <= 0; 152 if(Data_Valid) 153 Data_Cont <= Data_Cont+1'b1; 154 end 155 end 156 157 endmodule
4.YUV422_to_444模块
1 module YUV422_to_444 ( // YUV 4:2:2 Input 2 iYCbCr, 3 // YUV 4:4:4 Output 4 oY, 5 oCb, 6 oCr, 7 // Control Signals 8 iX, 9 iCLK, 10 iRST_N ); 11 // YUV 4:2:2 Input 12 input [15:0] iYCbCr; 13 // YUV 4:4:4 Output 14 output [7:0] oY; 15 output [7:0] oCb; 16 output [7:0] oCr; 17 // Control Signals 18 input [9:0] iX; 19 input iCLK; 20 input iRST_N; 21 // Internal Registers 22 reg [7:0] mY; 23 reg [7:0] mCb; 24 reg [7:0] mCr; 25 26 assign oY = mY; 27 assign oCb = mCb; 28 assign oCr = mCr; 29 /*********************************** 30 iX[0] 0 1 0 1 0 ... 31 输入: Y Y Y Y Y ... 32 Cb Cr Cb Cr Cb ... 33 输出:mY Y Y Y Y Y ... 34 mCb Cb --- Cb --- Cb ... 35 mCr Cr--- Cr --- ... 36 ************************************/ 37 always@(posedge iCLK or negedge iRST_N) 38 begin 39 if(!iRST_N) 40 begin 41 mY <= 0; 42 mCb <= 0; 43 mCr <= 0; 44 end 45 else 46 begin 47 if(iX[0]) 48 {mY,mCr} <= iYCbCr; 49 else 50 {mY,mCb} <= iYCbCr; 51 end 52 end 53 54 endmodule
5.YCbCr2RGB模块
1 /**************************************************** 2 详见:http://www.cnblogs.com/oomusou/archive/2008/12/09/verilog_ycrcb2rgb.html#commentform 3 R = 1.164(Y-16) + 1.596(Cr-128) 4 G = 1.164(Y-16) - 0.391(Cb-128) - 0.813(Cr-128) 5 B = 1.164(Y-16) + 2.018(Cb-128) 6 ---> 7 R = 1.164Y + 1.596Cr - 222.912 8 G = 1.164Y - 0.391Cb - 0.813Cr + 135.488 9 B = 1.164Y + 2.018Cb - 276.928 10 先放大在缩小,例如放大512倍即2^9---> 11 R << 9 = 596Y + 817Cr - 114131 12 G << 9 = 596Y - 200Cb - 416Cr + 69370 13 B << 9 = 596Y + 1033Cb - 141787 14 ****************************************************/ 15 module YCbCr2RGB ( Red,Green,Blue,oDVAL, 16 iY,iCb,iCr,iDVAL, 17 iRESET,iCLK); 18 // Input 19 input [7:0] iY,iCb,iCr; 20 input iDVAL,iRESET,iCLK; 21 wire iCLK; 22 // Output 23 output [9:0] Red,Green,Blue; 24 output reg oDVAL; 25 // Internal Registers/Wires 26 reg [9:0] oRed,oGreen,oBlue; 27 reg [3:0] oDVAL_d; 28 reg [19:0] X_OUT,Y_OUT,Z_OUT; 29 wire [26:0] X,Y,Z; 30 31 assign Red = oRed; 32 assign Green= oGreen; 33 assign Blue = oBlue; 34 35 always@(posedge iCLK) 36 begin 37 if(iRESET) 38 begin 39 oDVAL<=0; 40 oDVAL_d<=0; 41 oRed<=0; 42 oGreen<=0; 43 oBlue<=0; 44 end 45 else 46 begin 47 // Red 48 if(X_OUT[19])//溢出 49 oRed<=0; 50 else if(X_OUT[18:0]>1023) 51 oRed<=1023; //上界,output [9:0] 是10 bit,最大1023 52 else 53 oRed<=X_OUT[9:0]; 54 // Green 55 if(Y_OUT[19]) 56 oGreen<=0; 57 else if(Y_OUT[18:0]>1023) 58 oGreen<=1023; 59 else 60 oGreen<=Y_OUT[9:0]; 61 // Blue 62 if(Z_OUT[19]) 63 oBlue<=0; 64 else if(Z_OUT[18:0]>1023) 65 oBlue<=1023; 66 else 67 oBlue<=Z_OUT[9:0]; 68 // Control 69 /************************************************ 70 oDVAL_d <= iDVAL; 71 oDVAL <= oDVAL_d;精简写法。 72 因为运算较多,所以希望oDVAL多一个时钟delay 73 ************************************************/ 74 {oDVAL,oDVAL_d}<={oDVAL_d,iDVAL}; 75 end 76 end 77 78 always@(posedge iCLK) 79 begin 80 if(iRESET) 81 begin 82 X_OUT<=0; 83 Y_OUT<=0; 84 Z_OUT<=0; 85 end 86 else 87 /************************************************ 88 X_OUT <= (( X - 114131 ) >> 9) << 2; 89 Y_OUT <= (( Y + 69370 ) >> 9) << 2; 90 Z_OUT <= (( Z - 141787 ) >> 9) << 2; 91 output [9:0] 是10 bit,而input [7:0] 是8 bit,所以<<2 92 ************************************************/ 93 begin 94 X_OUT<=( X - 114131 ) >>7; 95 Y_OUT<=( Y + 69370 ) >>7; 96 Z_OUT<=( Z - 141787 ) >>7; 97 end 98 end 99 100 // Y 596, 0, 817 101 MAC_3 u0( 102 .aclr0(iRESET), 103 .clock0(iCLK), 104 .dataa_0(iY), 105 .dataa_1(iCb), 106 .dataa_2(iCr), 107 .datab_0(17'h00254), 108 .datab_1(17'h00000), 109 .datab_2(17'h00331), 110 .result(X) 111 ); 112 //MAC_3 u0( iRESET, iCLK,iY, iCb, iCr, 113 // 17'h00254, 17'h00000, 17'h00331, 114 // X); 115 // Cb 596, -200, -416 116 MAC_3 u1( 117 .aclr0(iRESET), 118 .clock0(iCLK), 119 .dataa_0(iY), 120 .dataa_1(iCb), 121 .dataa_2(iCr), 122 .datab_0(17'h00254), 123 .datab_1(17'h3FF38), 124 .datab_2(17'h3FE60), 125 .result(Y) 126 ); 127 //MAC_3 u1( iRESET, iCLK,iY, iCb, iCr, 128 // 17'h00254, 17'h3FF38, 17'h3FE60, 129 // Y ); 130 // Cr 596, 1033, 0 131 MAC_3 u2( 132 .aclr0(iRESET), 133 .clock0(iCLK), 134 .dataa_0(iY), 135 .dataa_1(iCb), 136 .dataa_2(iCr), 137 .datab_0(17'h00254), 138 .datab_1(17'h00409), 139 .datab_2(17'h00000), 140 .result(Z) 141 ); 142 //MAC_3 u2( iRESET, iCLK,iY, iCb, iCr, 143 // 17'h00254, 17'h00409, 17'h00000, 144 // Z ); 145 146 endmodule
我觉得以上5个模块可能是难度比较大的模块了,当然除了Sdram_Control_4Port模块以外。具体的解释我都在代码中注释了,另外还加上了一些大神的链接,应该不难理解了。至于Sdram_Control_4Port模块,我也曾研究过一段时间,但是由于时间关系,有很多地方还是不能完全理解,有时间的话我会再仔细研究一下,和大家一块分享。
另外附上我的DE2_115_TV的工程,里面把不需要的模块都精简掉了,看起来比较清爽。加上了Sobel滤波模块和灰度显示,具体可以参考代码中的说明。