HDMI彩条显示

硬件平台
正点原子达芬奇Xilinx A7

软件版本
vivado 2018.3

上板效果
请添加图片描述
程序结构
在这里插入图片描述

时钟生成模块clk_wiz
产生74.25MHz和371.25MHz(74.25 x 5) OSERDESE2使用DDR模式,显示分辨率为1280 x 720

需要注意的是使用PLL IP核时,先产生低频的时钟74.25(实际74.219),再设置5倍频的371.25;
先设置高频时钟,导致低频设置的误差变大(实际73.713),最终显示会闪屏(推测是这个原因)。
在这里插入图片描述
在这里插入图片描述
HDMI数据生成模块
根据之前写的RGB LCD彩条显示修改而来,之前是RGB565的格式,HDMI需要RGB888的格式数据

module lcd_rgb_data #(
		parameter H_VALID = 11'd1280	,
		parameter V_VALID = 11'd720	
	)(
	input				sys_clk		,
	input				sys_rst_n	,
	
	input		[10:0]	lcd_x		,
	input		[10:0]	lcd_y		,
	input				rgb_data_req,
	
	output	reg	[23:0]	rgb_data	

);

localparam	RED     =   24'hFF0000,   //红色
            ORANGE  =   24'hFF8000,   //橙色
            YELLOW  =   24'hFFFF00,   //黄色
            GREEN   =   24'h00FF00,   //绿色
            CYAN    =   24'h00FFFF,   //青色
            BLUE    =   24'h0000FF,   //蓝色
            PURPPLE =   24'h8000FF,   //紫色
            BLACK   =   24'h000000,   //黑色
            WHITE   =   24'hFFFFFF,   //白色
            GRAY    =   24'hC0C0C0;	  //灰色

always@(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		rgb_data <= BLACK;
	else	if(lcd_x >= 11'd0 && (lcd_x < (H_VALID/10)*1))
		rgb_data <= RED;
	else	if(lcd_x >= ((H_VALID/10)*1) && (lcd_x < (H_VALID/10)*2))
		rgb_data <= ORANGE;
	else	if(lcd_x >= ((H_VALID/10)*2) && (lcd_x < (H_VALID/10)*3))
		rgb_data <= YELLOW;
	else	if(lcd_x >= ((H_VALID/10)*3) && (lcd_x < (H_VALID/10)*4))
		rgb_data <= GREEN;
	else	if(lcd_x >= ((H_VALID/10)*4) && (lcd_x < (H_VALID/10)*5))
		rgb_data <= CYAN;
	else	if(lcd_x >= ((H_VALID/10)*5) && (lcd_x < (H_VALID/10)*6))
		rgb_data <= BLUE;
	else	if(lcd_x >= ((H_VALID/10)*6) && (lcd_x < (H_VALID/10)*7))
		rgb_data <= PURPPLE;
	else	if(lcd_x >= ((H_VALID/10)*7) && (lcd_x < (H_VALID/10)*8))
		rgb_data <= BLACK;
	else	if(lcd_x >= ((H_VALID/10)*8) && (lcd_x < (H_VALID/10)*9))
		rgb_data <= WHITE;
	else	if(lcd_x >= ((H_VALID/10)*9) && (lcd_x < (H_VALID/10)*10))
		rgb_data <= GRAY;
	else
		rgb_data <= BLACK;


endmodule

HDMI信号控制模块
该模块将RGB数据、行同步信号、场同步信号、DE数据有效信号设计时序,然后传输给HDMI驱动模块显示。该部分与RGB LCD显示彩条的原理一样的,同样只是修改了部分的参数得到,其中的lcd_clk和bl(LCD背光控制)没有使用。

module lcd_rgb_ctrl #(	
		/* 默认显示器参数1280*720 */
		parameter	H_SYNC 	= 11'd40	,	/* 同步 */
		parameter	H_BACK 	= 11'd220	,	/* 后沿 */	
		parameter	H_VALID	= 11'd1280	,	/* 有效数据 */
		parameter	H_FRONT	= 11'd110	,	/* 前沿 */
		parameter	H_TOTAL	= 11'd1650	,	/* 行周期前四项之和 */
		
		parameter	V_SYNC 	= 11'd5		,	
		parameter	V_BACK 	= 11'd20	,	
		parameter	V_VALID	= 11'd720	,	
		parameter	V_FRONT	= 11'd5		,	
		parameter	V_TOTAL	= 11'd750	
	)(
	input				sys_clk			,
	input				sys_rst_n		,
	
	input		[23:0]	rgb_data		,
	
	output		[10:0]	lcd_x			,	/* 回传当前显示位置,获取RGB数据 */
	output		[10:0]	lcd_y			,
	output				rgb_data_req	,	/* 数据请求信号 */
	
	output		[7:0]	rgb_red		,
	output		[7:0]	rgb_green	,
	output		[7:0]	rgb_blue	,
	output				hsync		,
	output				vsync		,
	output				de			,	/* DE同步信号 */
	output				lcd_clk		,
	output				bl				/* 背光 */
	
);

reg		[10:0]	cnt_h,cnt_v		;	/* 行、场计数器 */
wire			display_valid	;

always@(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		cnt_h <= 11'd0;
	else	if(cnt_h == H_TOTAL - 1'd1)	/* 达到行周期值 */
		cnt_h <= 11'd0;
	else
		cnt_h <= cnt_h + 1'b1;
		
always@(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		cnt_v <= 11'd0;
	else	if((cnt_v == V_TOTAL - 1'd1) && (cnt_h == H_TOTAL - 1'd1))	/* 达到场周期值,且行周期也达到 */
		cnt_v <= 11'd0;
	else	if(cnt_h == H_TOTAL - 1'd1)	/* 行周期结束,场计数加一 */
		cnt_v <= cnt_v + 1'b1;

assign 	hsync = (cnt_h <= H_SYNC - 1)? 1'b0 : 1'b1;	/* 同步阶段为0,其余三个阶段为1 */
assign	vsync = (cnt_v <= V_SYNC - 1)? 1'b0 : 1'b1;

/* 定义有效显示的范围标志800*480以内 */
assign	display_valid = ((cnt_h >= H_SYNC + H_BACK) && (cnt_h < H_SYNC + H_BACK + H_VALID)
					 && (cnt_v >= V_SYNC + V_BACK ) && (cnt_v < V_SYNC + V_BACK + V_VALID))
					 ? 1'b1 : 1'b0; 

/* 数据请求需要比显示有效区域提前一个周期 */
assign 	rgb_data_req = ((cnt_h >= H_SYNC + H_BACK - 1) && (cnt_h < H_SYNC + H_BACK + H_VALID - 1)
					 && (cnt_v >= V_SYNC + V_BACK - 1) && (cnt_v < V_SYNC + V_BACK + V_VALID - 1))
					 ? 1'b1 : 1'b0;       

/* 将传出的坐标信息控制在有效的范围内800*480 */		 
assign 	lcd_x = (rgb_data_req == 1'b1)? (cnt_h - (H_SYNC + H_BACK - 1'b1)) : 11'd0;                                                               
assign 	lcd_y = (rgb_data_req == 1'b1)? (cnt_v - (V_SYNC + V_BACK - 1'b1)) : 11'd0;  

assign	rgb_red   = (display_valid == 1'b1)? rgb_data[23:16] : 8'd0;
assign	rgb_green = (display_valid == 1'b1)? rgb_data[15:8]  : 8'd0;
assign	rgb_blue  = (display_valid == 1'b1)? rgb_data[7:0]   : 8'd0;

assign	lcd_clk = sys_clk;
assign	de = display_valid;
assign	bl = sys_rst_n;	/* 复位完成之后点亮LCD背光 */

endmodule

HDMI驱动模块
此模块需要将收到的RGB 24bit的数据与行同步信号、场同步信号划分传输

HDMI数据通道传输数据种类
D0RGB_B、HSYNC、VSYNC
D1RGB_G
D2RGB_R

在对HDMI差分引脚分配时,需要格外注意,数据是否分配到了对应的HDMI通道上了。
在这里插入图片描述

HDMI代码实现步骤:
①TMDS编码RGB、HSYNC、VSYNC信号
②并转串10:1,使用OSERDESE2原语,级联方式
③OBUFDS原语,单端转差分输出

OSERDESE2原语使用

`timescale 1ns / 1ps
/* 
	并串转换10-->1,调用Xilinx原语 
	串行时钟的频率需要为并行时钟的5倍,使用的是DDR双数据率处理
*/
module deserializer(
	input				serial_clk		,	/* 串行时钟输入 */
	input				parallel_clk	,	/* 并行时钟输入 */
	input				sys_rst			,	
	
	input		[9:0]	parallel_data	,	/* 并行数据输入 */
	output				serial_data			/* 串行数据输出 */
);

wire	shift1,shift2;

//  OSERDESE2  : In order to incorporate this function into the design,
//   Verilog   : the following instance declaration needs to be placed
//  instance   : in the body of the design code.  The instance name
// declaration : (OSERDESE2_inst) and/or the port declarations within the
//    code     : parenthesis may be changed to properly reference and
//             : connect this function to the design.  All inputs
//             : and outputs must be connected.

//  <-----Cut code below this line---->

   // OSERDESE2: Output SERial/DESerializer with bitslip
   //            Artix-7
   // Xilinx HDL Language Template, version 2018.3

   OSERDESE2 #(
      .DATA_RATE_OQ("DDR"),   // DDR, SDR
      .DATA_RATE_TQ("SDR"),   // DDR, BUF, SDR
      .DATA_WIDTH(10),         // Parallel data width (2-8,10,14)	
      .INIT_OQ(1'b0),         // Initial value of OQ output (1'b0,1'b1)
      .INIT_TQ(1'b0),         // Initial value of TQ output (1'b0,1'b1)
      .SERDES_MODE("MASTER"), // MASTER, SLAVE
      .SRVAL_OQ(1'b0),        // OQ output value when SR is used (1'b0,1'b1)
      .SRVAL_TQ(1'b0),        // TQ output value when SR is used (1'b0,1'b1)
      .TBYTE_CTL("FALSE"),    // Enable tristate byte operation (FALSE, TRUE)
      .TBYTE_SRC("FALSE"),    // Tristate byte source (FALSE, TRUE)
      .TRISTATE_WIDTH(1)      // 3-state converter width (1,4)
   )
   OSERDESE2_Master (
      .OFB(),             // 1-bit output: Feedback path for data
      .OQ(serial_data),               // 1-bit output: Data path output
      // SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
      .SHIFTOUT1(),
      .SHIFTOUT2(),
      .TBYTEOUT(),   // 1-bit output: Byte group tristate
      .TFB(),             // 1-bit output: 3-state control
      .TQ(),               // 1-bit output: 3-state control
      .CLK(serial_clk),             // 1-bit input: High speed clock
      .CLKDIV(parallel_clk),       // 1-bit input: Divided clock
      // D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
      .D1(parallel_data[0]),
      .D2(parallel_data[1]),
      .D3(parallel_data[2]),
      .D4(parallel_data[3]),
      .D5(parallel_data[4]),
      .D6(parallel_data[5]),
      .D7(parallel_data[6]),
      .D8(parallel_data[7]),
      .OCE(1'b1),             // 1-bit input: Output data clock enable
      .RST(sys_rst),             // 1-bit input: Reset
      // SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
      .SHIFTIN1(shift1),	/* 连接Slave的扩展输出 */
      .SHIFTIN2(shift2),
      // T1 - T4: 1-bit (each) input: Parallel 3-state inputs
      .T1(1'b0),
      .T2(1'b0),
      .T3(1'b0),
      .T4(1'b0),
      .TBYTEIN(1'b0),     // 1-bit input: Byte group tristate
      .TCE(1'b0)              // 1-bit input: 3-state clock enable
   );


   OSERDESE2 #(
      .DATA_RATE_OQ("DDR"),   // DDR, SDR
      .DATA_RATE_TQ("SDR"),   // DDR, BUF, SDR
      .DATA_WIDTH(10),         // Parallel data width (2-8,10,14)
      .INIT_OQ(1'b0),         // Initial value of OQ output (1'b0,1'b1)
      .INIT_TQ(1'b0),         // Initial value of TQ output (1'b0,1'b1)
      .SERDES_MODE("SLAVE"), // MASTER, SLAVE
      .SRVAL_OQ(1'b0),        // OQ output value when SR is used (1'b0,1'b1)
      .SRVAL_TQ(1'b0),        // TQ output value when SR is used (1'b0,1'b1)
      .TBYTE_CTL("FALSE"),    // Enable tristate byte operation (FALSE, TRUE)
      .TBYTE_SRC("FALSE"),    // Tristate byte source (FALSE, TRUE)
      .TRISTATE_WIDTH(1)      // 3-state converter width (1,4)
   )
   OSERDESE2_Slave (
      .OFB(),             // 1-bit output: Feedback path for data
      .OQ(),               // 1-bit output: Data path output
      // SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
      .SHIFTOUT1(shift1),
      .SHIFTOUT2(shift2),
      .TBYTEOUT(),   // 1-bit output: Byte group tristate
      .TFB(),             // 1-bit output: 3-state control
      .TQ(),               // 1-bit output: 3-state control
      .CLK(serial_clk),             // 1-bit input: High speed clock
      .CLKDIV(parallel_clk),       // 1-bit input: Divided clock
      // D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
      .D1(1'b0),
      .D2(1'b0),
      .D3(parallel_data[8]),
      .D4(parallel_data[9]),
      .D5(1'b0),
      .D6(1'b0),
      .D7(1'b0),
      .D8(1'b0),
      .OCE(1'b1),             // 1-bit input: Output data clock enable
      .RST(sys_rst),             // 1-bit input: Reset
      // SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
      .SHIFTIN1(),
      .SHIFTIN2(),
      // T1 - T4: 1-bit (each) input: Parallel 3-state inputs
      .T1(1'b0),
      .T2(1'b0),
      .T3(1'b0),
      .T4(1'b0),
      .TBYTEIN(1'b0),     // 1-bit input: Byte group tristate
      .TCE(1'b0)              // 1-bit input: 3-state clock enable
   );

   // End of OSERDESE2_inst instantiation


endmodule

OBUFDS原语使用

OBUFDS #(
	.IOSTANDARD("TMDS_33"), // Specify the output I/O standard
	.SLEW("SLOW")           // Specify the output slew rate
	) OBUFDS_inst_r (
	.O	(hdmi_red_p		),     // Diff_p output (connect directly to top-level port)
	.OB	(hdmi_red_n		),   // Diff_n output (connect directly to top-level port)
	.I	(serial_data_r	)      // Buffer input
);

工程链接
链接:https://pan.baidu.com/s/1wNH6RC5WTawiDco1omoEjg
提取码:3hpf
在这里插入图片描述

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值