赞
踩
HDMI( High-Definition Multimedia Interface),即高清多媒体接口。它能够同时传输视频和音频,简化了设备的接口和连线;同时提供了更高的数据传输带宽, 可以传输无压缩的数字音频及高分辨率视频信号。 HDMI 接口在物理层使用 TMDS 标准传输音视频数据。
点亮液晶显示屏需要按照一定的时序,示意图如下。使用FPGA驱动LCD屏幕时,是按照一行一行的形式点亮屏幕的,一个像素时钟点亮一个像素。其中,黑色部分传输控制数据或者其他数据,白色部分传输有效的像素数据。以下图为例,传输一幅图像的过程为:1.VSYNC拉高表示开始传输;;2. 等待VBP行的扫描时间;3.进入有效显示区域,HSYNC拉高开始一行数据的扫描,这一行的时间包括三个部分的:HBP+DE+HFP;4.扫完600行,即完成有效区域的显示,然后等待VFP行的扫描时间结束一帧的扫描。
LCD 行显示时序
在有效数据区域,LCD行显示时序如下图,其中参数有:
.HSYNC:行同步信号,当此信号有效的时候就表示开始显示新的一行数据,图示为低电平有效。
HSPW:行同步间隔,也就是 HSYNC 信号持续时间。行与行之间不是连续的,中间有间隔。单位是像素时钟。
HBP::行显示后沿(或后肩),单位是 像素时钟。
HOZVAL:行有效显示区域,即显示一行数据所需的时间,假如屏幕分辨率为 1024*600,那么 HOZVAL就是 1024,单位为像素时钟。
LCD 帧显示时序
传输一整幅图像的时序如下图,其中参数有:
VSYNC:帧(场)同步信号,当此信号有效的时候就表示开始显示新的一帧数据。图示为低电平有效。
VSPW:帧同步信号宽度,也就是 VSYNC 信号持续时间,单位为 1 行的时间。
VBP:帧显示后沿(或后肩),单位为 1 行的时间。
LINE:帧有效显示区域,即显示一帧数据所需的时间,假如屏幕分辨率为 1024*600,那么 LINE 就是600 行的时间。
VFP:帧显示前沿(或前肩),单位为 1 行的时间。
因此,显示一帧的总时间就可以计算为:VSPW+VBP+LINE+VFP 个行时间,总的时间T:T = (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)(含义就是行乘列个像素时钟)
首先我们需要明确一定,使用HDMI接口传输数据时,数据以TMDS的电平标准传输,实际上它是一种串行的数据格式。但是在FPGA中处理的数据是以RGB888的形式的并行数据,所以需要进行并串转换。在转换之前,需要将RGB888数据进8b/10b编码,这么做的目的主要是为了避免连续出现0或者1,来保证DC平衡。同时,每个编码后的 10-bit字符中状态跳转(“由 1 到 0”或者“由 0 到 1” ) 的次数将被限制在五次以内。
8b/10b编码
对于8b/10b编码,XILINX官方提供了编码模块流程以及代码,不过多解释了:
并串转换
并串转换使用XILINX FPGA提供的并转串的IO逻辑资源OSERDES,调用方式是使用原语OSERDESE2。一个OSERDES只能实现8:1的并串转换,若要实现10:1的并串转换则需要使用两个OSERDES级联实现。需要注意的是,两个OSERDES级联时,第二个OSERDES输入数据端口只能从D3开始,D1、D2不可用。
差分输出
经过并转串的数据并不能直接输出,还需要转为差分形式的信号。这时候需要使用到FPGA的IO资源中的IOB,两个IOB可以配置成差分信号输出,调用方法是使用原语OBUFDS。
工程的整体框图如下,主要由四个模块组成,分别是分频模块、视频显示模块、视频驱动模块、数据传输模块。分频模块产生像素时钟和五倍的像素时钟用于其他模块;视频显示模块主要完成ROM中图片数据的读取,由视频驱动模块驱动并输出RGB888数据给视频驱动模块;视频驱动模块完成LCD扫描的过程以及将读取的像素数据输出给数据传输模块;数据传输模块完成8b/10b编码、并转串输出和差分信号的形成。
视频显示模块
视频显示模块主要完成要显示图片的像素数据输出。图片数据存于例化的单端ROM中,单个数据位宽为24bit,图片大小200*200一共40000像素。LCD使用的是1280×720的分辨率,因此除了显示图片的地方外,其他位置显示白色。该模块代码如下:
module video_display( input pixel_clk, input sys_rst_n, input [10:0] pixel_xpos, //像素点横坐标 input [10:0] pixel_ypos, //像素点纵坐标 output reg [23:0] pixel_data //像素点数据 ); //parameter define parameter H_DISP = 11'd1280; //分辨率——行 parameter V_DISP = 11'd720; //分辨率——列 localparam WHITE = 24'b11111111_11111111_11111111; //RGB888 白色 //***************************************************** //** main code //***************************************************** wire ena; wire [23:0]rom_out; reg [15:0]cnt; assign ena = 1; always @(posedge pixel_clk or negedge sys_rst_n ) begin if (!sys_rst_n) cnt <= 'b0; else if(pixel_ypos == 460) cnt <= 'b0; else if((pixel_xpos >= 537) && (pixel_xpos < 737) && (pixel_ypos >= 260) && (pixel_ypos < 460)) //让图片显示在屏幕中央 cnt <= cnt + 16'b1; end always @(posedge pixel_clk ) begin if (!sys_rst_n) pixel_data <= 'b0; else if((pixel_xpos >= 539) && (pixel_xpos < 740) && (pixel_ypos >= 260) && (pixel_ypos < 460)) pixel_data <= rom_out; else pixel_data <= WHITE; end blk_mem_gen_0 your_instance_name ( .clka(pixel_clk), // input wire clka .ena(ena), // input wire ena .addra(cnt), // input wire [15 : 0] addra .douta(rom_out) // output wire [23 : 0] douta ); endmodule
视频驱动模块
视频驱动模块一方面产生像素点的坐标用于读取视频显示模块中的像素数据,一方面输出像素数据和行场同步信号给编码模块。此外,显示屏分辨率参数是1280*720。模块代码如下:
module video_driver( input pixel_clk , input sys_rst_n , //RGB接口 output video_hs , //行同步信号 output video_vs , //场同步信号 output video_de , //数据使能 output [23:0] video_rgb , //RGB888颜色数据 output reg data_req , input [23:0] pixel_data , //像素点数据 output reg [10:0] pixel_xpos , //像素点横坐标 output reg [10:0] pixel_ypos //像素点纵坐标 ); //parameter define //1280*720 分辨率时序参数 parameter H_SYNC = 11'd40; //行同步 parameter H_BACK = 11'd220; //行显示后沿 parameter H_DISP = 11'd1280; //行有效数据 parameter H_FRONT = 11'd110; //行显示前沿 parameter H_TOTAL = 11'd1650; //行扫描周期 parameter V_SYNC = 11'd5; //场同步 parameter V_BACK = 11'd20; //场显示后沿 parameter V_DISP = 11'd720; //场有效数据 parameter V_FRONT = 11'd5; //场显示前沿 parameter V_TOTAL = 11'd750; //场扫描周期 //reg define reg [11:0] cnt_h; reg [11:0] cnt_v; reg video_en; //***************************************************** //** main code //***************************************************** assign video_de = video_en; assign video_hs = ( cnt_h < H_SYNC ) ? 1'b0 : 1'b1; //行同步信号赋值 assign video_vs = ( cnt_v < V_SYNC ) ? 1'b0 : 1'b1; //场同步信号赋值 //使能RGB数据输出 always @(posedge pixel_clk or negedge sys_rst_n) begin if(!sys_rst_n) video_en <= 1'b0; else video_en <= data_req; end //RGB888数据输出 assign video_rgb = video_de ? pixel_data : 24'd0; //请求像素点颜色数据输入 always @(posedge pixel_clk or negedge sys_rst_n) begin if(!sys_rst_n) data_req <= 1'b0; else if(((cnt_h >= H_SYNC + H_BACK - 2'd2) && (cnt_h < H_SYNC + H_BACK + H_DISP - 2'd2)) && ((cnt_v >= V_SYNC + V_BACK) && (cnt_v < V_SYNC + V_BACK+V_DISP))) data_req <= 1'b1; else data_req <= 1'b0; end //像素点x坐标 always@ (posedge pixel_clk or negedge sys_rst_n) begin if(!sys_rst_n) pixel_xpos <= 11'd0; else if(data_req) pixel_xpos <= cnt_h + 2'd2 - H_SYNC - H_BACK ; else pixel_xpos <= 11'd0; end //像素点y坐标 always@ (posedge pixel_clk or negedge sys_rst_n) begin if(!sys_rst_n) pixel_ypos <= 11'd0; else if((cnt_v >= (V_SYNC + V_BACK)) && (cnt_v < (V_SYNC + V_BACK + V_DISP))) pixel_ypos <= cnt_v + 1'b1 - (V_SYNC + V_BACK) ; else pixel_ypos <= 11'd0; end //行计数器对像素时钟计数 always @(posedge pixel_clk or negedge sys_rst_n) begin if (!sys_rst_n) cnt_h <= 11'd0; else begin if(cnt_h < H_TOTAL - 1'b1) cnt_h <= cnt_h + 1'b1; else cnt_h <= 11'd0; end end //场计数器对行计数 always @(posedge pixel_clk or negedge sys_rst_n) begin if (!sys_rst_n) cnt_v <= 11'd0; else if(cnt_h == H_TOTAL - 1'b1) begin if(cnt_v < V_TOTAL - 1'b1) cnt_v <= cnt_v + 1'b1; else cnt_v <= 11'd0; end end endmodule
数据传输模块
编码模块将输入的并行数据编码、并转串数据和差分输出。
编码框图如下所示,主要完成RGB888的8b/10b编码,同时行场同步信号HSYNC、VSYNC由蓝色通道进行编码,表示控制信号,接在蓝色通道的C0、C1端口,在传输数据的消隐期传送。其余通道的控制信号未使用到,均赋值为0。
并转串使用OSERDESE2原语实现。HDMI接口中传输四路数据,分别是R、G、B和时钟,因此需要四路并转串。OSERDESE2使用DDR模式,也就是每个时钟可以转换2个数据,因此OSERDESE2转换10bit数据只需要五个时钟,这就是要用PLL产生5倍像素时钟的原因。时钟的并转串采用硬编码的形式,直接输入10‘b11111_00000的数据。最后由OBUFDS产生四差分信号输出。该部分的整体框图如下:
做了一个低电平复位转高电平复位的逻辑,原因是这些原语都是使用的高电平复位,但是其他模块都是低电平复位。
结果展示
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。