素材来自原子哥
一、HDMI简介
英文全称是High-Definition Multimedia Interface,即高清多媒体接口。
HDMI引脚解析(A型)
HDMI工作连接图
HDMI工作原理
DVI编码输出示意图
二、TMDS编码(最小化差分传输)
TMDS编码框图
TMDS参数表
编码过程
三、并转串、单端转差分原语介绍
原语:英文名称Primitive,是Xilinx针对其器件特征开发的一系列常用模块名称,涵盖了FPGA开发过程中的常用领域,方便用户直接调用FPGA的底层组件。
原语可以看作是库函数,可以直接例化调用,使用方便,功能全面,可以有效提高开发效率。
IO端口组件原语;
IO组件
IOB
OSERDESE2(双沿)
并行转串行原语,可以调用Xilinx 7系列FPGA的IO逻辑资源,其主要功能是将并行数据转换成串行数据。
OSERDESE2级联示意图
OSERDESE2工作时序图(8:1)
OSERDESE2三态时序图(4:1)
OSERDESE2原语调用(并转串)
OSERDESE2 #(
.DATA_RATE_OQ(“DDR”), // DDR, SDR
.DATA_RATE_TQ(“DDR”), // DDR, BUF, SDR
.DATA_WIDTH(4), // 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(4) // 3-state converter width (1,4)
)
OSERDESE2_inst (
.OFB(OFB), // 1-bit output: Feedback path for data
.OQ(OQ), // 1-bit output: Data path output
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1(SHIFTOUT1),
.SHIFTOUT2(SHIFTOUT2),
.TBYTEOUT(TBYTEOUT), // 1-bit output: Byte group tristate
.TFB(TFB), // 1-bit output: 3-state control
.TQ(TQ), // 1-bit output: 3-state control
.CLK(CLK), // 1-bit input: High speed clock
.CLKDIV(CLKDIV), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1(D1),
.D2(D2),
.D3(D3),
.D4(D4),
.D5(D5),
.D6(D6),
.D7(D7),
.D8(D8),
.OCE(OCE), // 1-bit input: Output data clock enable
.RST(RST), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1(SHIFTIN1),
.SHIFTIN2(SHIFTIN2),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1(T1),
.T2(T2),
.T3(T3),
.T4(T4),
.TBYTEIN(TBYTEIN), // 1-bit input: Byte group tristate
.TCE(TCE) // 1-bit input: 3-state clock enable
);
OSERDESE2原语属性配置表
OBUFDS原语(差分)
OBUFDS OBUFDS_inst (
.O(O), // 1-bit output: Diff_p output (connect directly to top-level port)
.OB(OB), // 1-bit output: Diff_n output (connect directly to top-level port)
.I(I) // 1-bit input: Buffer input
);
四、硬件设计
五、试验任务
本章的实验任务是驱动FPGA开发板上的HDMI接口,在显示器上显示480p彩条图案(480p分辨率为800*480,像素时钟频率Vga_clk = 1056x525x60 = 33264000 ≈33.3hz(误差忽略不计))。
六、程序设计
1、整体框架
2、dvi_encoder:编码模块
//
//
// Xilinx, Inc. 2008 www.xilinx.com
//
//
//
// File name : dvi_encoder.v
//
// Description : TMDS encoder
//
// Date - revision : Jan. 2008 - v 1.0
//
// Author : Bob Feng
//
// Copyright 2006 Xilinx, Inc.
// All rights reserved
//
//
`timescale 1 ps / 1ps
module dvi_encoder (
input clkin, // pixel clock input
input rstin, // async. reset input (active high)
input [7:0] din, // data inputs: expect registered
input c0, // c0 input
input c1, // c1 input
input de, // de input
output reg [9:0] dout // data outputs
);
// Counting number of 1s and 0s for each incoming pixel
// component. Pipe line the result.
// Register Data Input so it matches the pipe lined adder
// output
reg [3:0] n1d; //number of 1s in din
reg [7:0] din_q;
//计算像素数据中“1”的个数
always @ (posedge clkin) begin
n1d <=#1 din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7];
din_q <=#1 din;
end
///
// Stage 1: 8 bit -> 9 bit
// Refer to DVI 1.0 Specification, page 29, Figure 3-5
///
wire decision1;
assign decision1 = (n1d > 4'h4) | ((n1d == 4'h4) & (din_q[0] == 1'b0));
wire [8:0] q_m;
assign q_m[0] = din_q[0];
assign q_m[1] = (decision1) ? (q_m[0] ^~ din_q[1]) : (q_m[0] ^ din_q[1]);
assign q_m[2] = (decision1) ? (q_m[1] ^~ din_q[2]) : (q_m[1] ^ din_q[2]);
assign q_m[3] = (decision1) ? (q_m[2] ^~ din_q[3]) : (q_m[2] ^ din_q[3]);
assign q_m[4] = (decision1) ? (q_m[3] ^~ din_q[4]) : (q_m[3] ^ din_q[4]);
assign q_m[5] = (decision1) ? (q_m[4] ^~ din_q[5]) : (q_m[4] ^ din_q[5]);
assign q_m[6] = (decision1) ? (q_m[5] ^~ din_q[6]) : (q_m[5] ^ din_q[6]);
assign q_m[7] = (decision1) ? (q_m[6] ^~ din_q[7]) : (q_m[6] ^ din_q[7]);
assign q_m[8] = (decision1) ? 1'b0 : 1'b1;
/
// Stage 2: 9 bit -> 10 bit
// Refer to DVI 1.0 Specification, page 29, Figure 3-5
/
reg [3:0] n1q_m, n0q_m; // number of 1s and 0s for q_m
always @ (posedge clkin) begin
n1q_m <=#1 q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];
n0q_m <=#1 4'h8 - (q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]);
end
parameter CTRLTOKEN0 = 10'b1101010100;
parameter CTRLTOKEN1 = 10'b0010101011;
parameter CTRLTOKEN2 = 10'b0101010100;
parameter CTRLTOKEN3 = 10'b1010101011;
reg [4:0] cnt; //disparity counter, MSB is the sign bit
wire decision2, decision3;
assign decision2 = (cnt == 5'h0) | (n1q_m == n0q_m);
/
// [(cnt > 0) and (N1q_m > N0q_m)] or [(cnt < 0) and (N0q_m > N1q_m)]
/
assign decision3 = (~cnt[4] & (n1q_m > n0q_m)) | (cnt[4] & (n0q_m > n1q_m));
// pipe line alignment
reg de_q, de_reg;
reg c0_q, c1_q;
reg c0_reg, c1_reg;
reg [8:0] q_m_reg;
always @ (posedge clkin) begin
de_q <=#1 de;
de_reg <=#1 de_q;
c0_q <=#1 c0;
c0_reg <=#1 c0_q;
c1_q <=#1 c1;
c1_reg <=#1 c1_q;
q_m_reg <=#1 q_m;
end
///
// 10-bit out
// disparity counter
///
always @ (posedge clkin or posedge rstin) begin
if(rstin) begin
dout <= 10'h0;
cnt <= 5'h0;
end else begin
if (de_reg) begin
if(decision2) begin
dout[9] <=#1 ~q_m_reg[8];
dout[8] <=#1 q_m_reg[8];
dout[7:0] <=#1 (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];
cnt <=#1 (~q_m_reg[8]) ? (cnt + n0q_m - n1q_m) : (cnt + n1q_m - n0q_m);
end else begin
if(decision3) begin
dout[9] <=#1 1'b1;
dout[8] <=#1 q_m_reg[8];
dout[7:0] <=#1 ~q_m_reg[7:0];
cnt <=#1 cnt + {q_m_reg[8], 1'b0} + (n0q_m - n1q_m);
end else begin
dout[9] <=#1 1'b0;
dout[8] <=#1 q_m_reg[8];
dout[7:0] <=#1 q_m_reg[7:0];
cnt <=#1 cnt - {~q_m_reg[8], 1'b0} + (n1q_m - n0q_m);
end
end
end else begin
case ({c1_reg, c0_reg})
2'b00: dout <=#1 CTRLTOKEN0;
2'b01: dout <=#1 CTRLTOKEN1;
2'b10: dout <=#1 CTRLTOKEN2;
default: dout <=#1 CTRLTOKEN3;
endcase
cnt <=#1 5'h0;
end
end
end
endmodule
3、video_driver:(参考LCD模块框图)
`timescale 1ns / 1ps
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 H_SYNC = 11'd80 ; //行同步
parameter H_BACK = 11'd160 ; //行显示后沿
parameter H_DISP = 11'd800 ; //行有效数据
parameter H_FRONT = 11'd16 ; //行显示前沿
parameter H_TOTAL = 11'd1056; //行扫描周期
parameter V_SYNC = 11'd3 ; //场同步
parameter V_BACK = 11'd16 ; //场显示后沿
parameter V_DISP = 11'd480 ; //场有效数据
parameter V_FRONT = 11'd1 ; //场显示前沿
parameter V_TOTAL = 11'd500 ; //场扫描周期
reg [11:0] cnt_h;
reg [11:0] cnt_v;
reg video_en;
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;
//RGB888数据输出
assign video_rgb = video_en ? pixel_data : 24'd0;
//行计数
always @(posedge pixel_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
cnt_h <= 12'd0;
end
else begin
if (cnt_h < H_TOTAL - 1'b1) begin
cnt_h <= cnt_h + 1'b1;
end
else begin
cnt_h <= 12'd0;
end
end
end
//行计数
always @(posedge pixel_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
cnt_v <= 12'd0;
end
else begin
if (cnt_h == H_TOTAL - 1'b1) begin
if (cnt_v < V_TOTAL - 1'b1) begin
cnt_v <= cnt_v + 1'b1;
end
else begin
cnt_v <= 12'd0;
end
end
end
end
//数据请求信号
always @(posedge pixel_clk or negedge sys_rst_n ) begin
if (!sys_rst_n) begin
data_req <= 1'b0;
end
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)))begin
data_req <= 1'b1;
end
else begin
data_req <= 1'b0;
end
end
//使能RGB数据输入
always @(posedge pixel_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
video_en <= 1'b0;
end
else begin
video_en <= data_req;
end
end
//像素点x坐标
always @(posedge pixel_clk or negedge sys_rst_n ) begin
if (!sys_rst_n) begin
pixel_xpos <= 11'd0;
end
else if(data_req == 1'b1)begin
pixel_xpos <= cnt_h + 2'd2 - H_BACK - H_SYNC;
end
else begin
pixel_xpos <= 11'd0;
end
end
//像素点y坐标
always @(posedge pixel_clk or negedge sys_rst_n ) begin
if (!sys_rst_n) begin
pixel_ypos <= 11'd0;
end
else if((cnt_v >= (V_SYNC + V_BACK)) && (cnt_v < (V_SYNC + V_BACK + V_DISP)))begin
pixel_ypos <= cnt_v + 1'b1 - V_SYNC - V_BACK;
end
else begin
pixel_ypos <= 11'd0;
end
end
endmodule
4、video_display:彩条数据模块(参考LCD框图)
`timescale 1ns / 1ps
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 H_DISP = 11'd800 ;
parameter V_DISP = 11'd480 ;
localparam WHITE = 24'b11111111_11111111_11111111;
localparam BLACK = 24'b00000000_00000000_00000000;
localparam RED = 24'b11111111_00001100_00000000;
localparam GREEN = 24'b00000000_11111111_00000000;
localparam BLUE = 24'b00000000_00000000_11111111;
//给不同区域指定颜色
always @(posedge pixel_clk or negedge sys_rst_n ) begin
if (!sys_rst_n) begin
pixel_data <= 24'd0;
end
else begin
if ((pixel_xpos >= 1'b0) && (pixel_xpos < (H_DISP/5)*1)) begin
pixel_data <= WHITE;
end
else if ((pixel_xpos >= (H_DISP/5)*1) && (pixel_xpos < (H_DISP/5)*2)) begin
pixel_data <= BLACK;
end
else if ((pixel_xpos >= (H_DISP/5)*2) && (pixel_xpos < (H_DISP/5)*3)) begin
pixel_data <= RED;
end
else if ((pixel_xpos >= (H_DISP/5)*3) && (pixel_xpos < (H_DISP/5)*4)) begin
pixel_data <= GREEN;
end
else begin
pixel_data <= BLUE;
end
end
end
endmodule
5、asyn_rst_syn:异步复位,同步释放,并转换成高电平有效
打拍实现
// Descriptions: 异步复位,同步释放,并转换成高电平有效
module asyn_rst_syn(
input clk, //目的时钟域
input reset_n, //异步复位,低有效
output syn_reset //高有效
);
//reg define
reg reset_1;
reg reset_2;
//*****************************************************
//** main code
//*****************************************************
assign syn_reset = reset_2;
//对异步复位信号进行同步释放,并转换成高有效
always @ (posedge clk or negedge reset_n) begin
if(!reset_n) begin
reset_1 <= 1'b1;
reset_2 <= 1'b1;
end
else begin
reset_1 <= 1'b0;
reset_2 <= reset_1;
end
end
endmodule
6、serializer_10_to_1:实现10:1并串转换
//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name: serializer_10_to_1
// Last modified Date: 2020/05/28 20:28:08
// Last Version: V1.0
// Descriptions: 用于实现10:1并串转换
//
//----------------------------------------------------------------------------------------
// Created by: 正点原子
// Created date: 2020/05/28 20:28:08
// Version: V1.0
// Descriptions: The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//
`timescale 1ns / 1ps
module serializer_10_to_1(
input reset, // 复位,高有效
input paralell_clk, // 输入并行数据时钟
input serial_clk_5x, // 输入串行数据时钟
input [9:0] paralell_data, // 输入并行数据
output serial_data_out // 输出串行数据
);
//wire define
wire cascade1; //用于两个OSERDESE2级联的信号
wire cascade2;
//*****************************************************
//** main code
//*****************************************************
//例化OSERDESE2原语,实现并串转换,Master模式
OSERDESE2 #(
.DATA_RATE_OQ ("DDR"), // 设置双倍数据速率
.DATA_RATE_TQ ("SDR"), // DDR, BUF, SDR
.DATA_WIDTH (10), // 输入的并行数据宽度为10bit
.SERDES_MODE ("MASTER"), // 设置为Master,用于10bit宽度扩展 主
.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 (
.CLK (serial_clk_5x), // 串行数据时钟,5倍时钟频率
.CLKDIV (paralell_clk), // 并行数据时钟
.RST (reset), // 1-bit input: Reset
.OCE (1'b1), // 1-bit input: Output data clock enable
.OQ (serial_data_out), // 串行输出数据
.D1 (paralell_data[0]), // D1 - D8: 并行数据输入
.D2 (paralell_data[1]),
.D3 (paralell_data[2]),
.D4 (paralell_data[3]),
.D5 (paralell_data[4]),
.D6 (paralell_data[5]),
.D7 (paralell_data[6]),
.D8 (paralell_data[7]),
.SHIFTIN1 (cascade1), // SHIFTIN1 用于位宽扩展
.SHIFTIN2 (cascade2), // SHIFTIN2
.SHIFTOUT1 (), // SHIFTOUT1: 用于位宽扩展
.SHIFTOUT2 (), // SHIFTOUT2
.OFB (), // 以下是未使用信号
.T1 (1'b0),
.T2 (1'b0),
.T3 (1'b0),
.T4 (1'b0),
.TBYTEIN (1'b0),
.TCE (1'b0),
.TBYTEOUT (),
.TFB (),
.TQ ()
);
//例化OSERDESE2原语,实现并串转换,Slave模式
OSERDESE2 #(
.DATA_RATE_OQ ("DDR"), // 设置双倍数据速率
.DATA_RATE_TQ ("SDR"), // DDR, BUF, SDR
.DATA_WIDTH (10), // 输入的并行数据宽度为10bit
.SERDES_MODE ("SLAVE"), // 设置为Slave,用于10bit宽度扩展 从
.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 (
.CLK (serial_clk_5x), // 串行数据时钟,5倍时钟频率
.CLKDIV (paralell_clk), // 并行数据时钟
.RST (reset), // 1-bit input: Reset
.OCE (1'b1), // 1-bit input: Output data clock enable
.OQ (), // 串行输出数据
.D1 (1'b0), // D1 - D8: 并行数据输入
.D2 (1'b0),
.D3 (paralell_data[8]),
.D4 (paralell_data[9]),
.D5 (1'b0),
.D6 (1'b0),
.D7 (1'b0),
.D8 (1'b0),
.SHIFTIN1 (), // SHIFTIN1 用于位宽扩展
.SHIFTIN2 (), // SHIFTIN2
.SHIFTOUT1 (cascade1), // SHIFTOUT1: 用于位宽扩展
.SHIFTOUT2 (cascade2), // SHIFTOUT2
.OFB (), // 以下是未使用信号
.T1 (1'b0),
.T2 (1'b0),
.T3 (1'b0),
.T4 (1'b0),
.TBYTEIN (1'b0),
.TCE (1'b0),
.TBYTEOUT (),
.TFB (),
.TQ ()
);
endmodule