用FPGA设计HDMI

介绍:高清多媒体接口(High Definition Multimedia Interface,HDMI [1])是一种全数字视频声音发送接口,可以发送未压缩音频视频信号。

原理:

下面是对HDMI接口各引脚的简单介绍

引脚

定义

引脚

定义

1

数据2+ (TMDS Data2+)

11

时钟屏蔽 (TMDS Clock Shield)

2

数据2屏蔽 (TMDS Data2 Shield)

12

时钟- (TMDS Clock–)

3

数据2- ( TMDS Data2-)

13

CEC

4

数据1+ (TMDS Data1+)

14

保留

5

数据1屏蔽 (TMDS Data1 Shield)

15

DDC时钟线(SCL)

6

数据1- ( TMDS Data1-)

16

DDC数据线(SDA)

7

数据0+ (TMDS Data0+)

17

DDC/CEC地 (DDC/CEC GND)

8

数据0屏蔽 (TMDS Data0 Shield)

18

+5V电源 (Power)

9

数据0- ( TMDS Data0-)

19

热插拔检测 (Hot Plug Detect)

10

时钟+ (TMDS Clock+)

运用:

        结构框图:

TMDS差分传动技术是一种利用2个引脚间电压差来传送信号的技术。

HDMI 线缆和连接器提供四个差分线对,组成TMDS数据和时钟通道

HDMI中的TMDS 传输系统如下:

要实现TMDS通道传输,首先要将传入的8 位的并行数据进行编码、并/串转换,添加第9位编码

实验目的:可以将 “TFTLCD屏幕彩条显示” 通过HDMI接口正常显示在屏幕上

注意:ftf时钟与hdim传输时钟为10倍关系,在本实验中,ftf控制时钟为25Mhz,即像素时钟为25Mhz,根据计算公式 “单通道速率 = 像素时钟 × 10”  得到 hdim传输信号速率为250Mhz。

应该满足-hdim传输信号速率\geqslant像素时钟频率*10

(本实验参考了野火的hdmi显示器驱动设计与验证)

链接:​​​​​​12. hdmi显示器驱动设计与验证 — [野火]FPGA Verilog开发实战指南——基于Altera EP4CE10 征途Pro开发板 文档

模块框图:

模块代码

tft_colorbar模块代码,见我的这一篇文章:用FPGA设计TFTLCD液晶屏幕_基于fpga的tft液晶屏驱动电路-优快云博客

par_to_ser模块代码:

`timescale 1ns/1ps

module par_to_ser (
    input wire clk_x5,        // 5倍系统时钟
    input wire [9:0] par_data,// 10位并行数据输入
    output wire ser_data_p,   // 串行差分输出正端
    output wire ser_data_n    // 串行差分输出负端
);

// 数据预处理:提取上升沿和下降沿数据位
wire [4:0] data_rise = {par_data[8], par_data[6], par_data[4], par_data[2], par_data[0]};
wire [4:0] data_fall = {par_data[9], par_data[7], par_data[5], par_data[3], par_data[1]};

// 移位寄存器控制逻辑
reg [4:0] data_rise_s = 5'b0;
reg [4:0] data_fall_s = 5'b0;
reg [2:0] cnt = 3'b0;

reg data_h_p, data_l_p;  // 正端寄存器
reg data_h_n, data_l_n;  // 负端寄存器

always @(posedge clk_x5) begin
    cnt <= (cnt == 3'b100) ? 3'b0 : cnt + 1;
    
    if (cnt == 3'b100) begin
        // 加载新数据
        data_rise_s <= data_rise;
        data_fall_s <= data_fall;
    end 
    else begin
        // 右移操作
        data_rise_s <= {1'b0, data_rise_s[4:1]};
        data_fall_s <= {1'b0, data_fall_s[4:1]};
    end
end

// 正端数据处理
always @(posedge ~clk_x5) data_h_p <= data_rise_s[0]; // 上升沿锁存
always @(negedge ~clk_x5) data_l_p <= data_fall_s[0]; // 下降沿锁存

// 负端数据处理(取反实现差分)
always @(posedge ~clk_x5) data_h_n <= ~data_rise_s[0]; // 上升沿锁存反相
always @(negedge ~clk_x5) data_l_n <= ~data_fall_s[0]; // 下降沿锁存反相

// 组合输出选择
assign ser_data_p = ~clk_x5 ? data_h_p : data_l_p;
assign ser_data_n = ~clk_x5 ? data_h_n : data_l_n;

endmodule

encode模块代码:

`timescale 1ns/1ns

module encode (
    input   wire            sys_clk,
    input   wire            sys_rst_n,
    input   wire    [7:0]   data_in,
    input   wire            c0,
    input   wire            c1,
    input   wire            de,
    output  reg     [9:0]   data_out
);

// 参数定义
parameter   DATA_OUT0 = 10'b1101010100,
            DATA_OUT1 = 10'b0010101011,
            DATA_OUT2 = 10'b0101010100,
            DATA_OUT3 = 10'b1010101011;

// 内部信号声明
wire            condition_1, condition_2, condition_3;
wire    [8:0]   q_m;
reg     [3:0]   data_in_n1;
reg     [7:0]   data_in_reg;
reg     [3:0]   q_m_n1, q_m_n0;
reg     [4:0]   cnt;
reg             de_reg1, de_reg2;
reg             c0_reg1, c0_reg2, c1_reg1, c1_reg2;
reg     [8:0]   q_m_reg;

// 同步逻辑:计算输入数据中1的个数
always @(posedge sys_clk or negedge sys_rst_n)
    if (!sys_rst_n) data_in_n1 <= 4'd0;
    else data_in_n1 <= data_in[0] + data_in[1] + data_in[2] + data_in[3] +
                       data_in[4] + data_in[5] + data_in[6] + data_in[7];

// 输入数据打拍
always @(posedge sys_clk or negedge sys_rst_n)
    if (!sys_rst_n) data_in_reg <= 8'b0;
    else data_in_reg <= data_in;

// 生成条件1:决定编码模式
assign condition_1 = (data_in_n1 > 4'd4) || 
                    ((data_in_n1 == 4'd4) && !data_in_reg[0]);

// 生成q_m[8:0](完全展开的逻辑)
assign q_m[0] = data_in_reg[0];
assign q_m[1] = condition_1 ? (q_m[0] ~^ data_in_reg[1]) : (q_m[0] ^ data_in_reg[1]);
assign q_m[2] = condition_1 ? (q_m[1] ~^ data_in_reg[2]) : (q_m[1] ^ data_in_reg[2]);
assign q_m[3] = condition_1 ? (q_m[2] ~^ data_in_reg[3]) : (q_m[2] ^ data_in_reg[3]);
assign q_m[4] = condition_1 ? (q_m[3] ~^ data_in_reg[4]) : (q_m[3] ^ data_in_reg[4]);
assign q_m[5] = condition_1 ? (q_m[4] ~^ data_in_reg[5]) : (q_m[4] ^ data_in_reg[5]);
assign q_m[6] = condition_1 ? (q_m[5] ~^ data_in_reg[6]) : (q_m[5] ^ data_in_reg[6]);
assign q_m[7] = condition_1 ? (q_m[6] ~^ data_in_reg[7]) : (q_m[6] ^ data_in_reg[7]);
assign q_m[8] = condition_1 ? 1'b0 : 1'b1;

// 计算q_m中1和0的个数(完全展开的逻辑)
always @(posedge sys_clk or negedge sys_rst_n)
    if (!sys_rst_n) begin
        q_m_n1 <= 4'd0;
        q_m_n0 <= 4'd0;
    end else begin
        q_m_n1 <= q_m[0] + q_m[1] + q_m[2] + q_m[3] + 
                 q_m[4] + q_m[5] + q_m[6] + q_m[7];
        q_m_n0 <= 8 - (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

// 条件判断优化
assign condition_2 = (cnt == 5'd0) || (q_m_n1 == q_m_n0);
assign condition_3 = (!cnt[4] && (q_m_n1 > q_m_n0)) || 
                     (cnt[4] && (q_m_n0 > q_m_n1));

// 控制信号同步打拍
always @(posedge sys_clk or negedge sys_rst_n)
    if (!sys_rst_n) begin
        {de_reg2, de_reg1} <= 2'b0;
        {c0_reg2, c0_reg1} <= 2'b0;
        {c1_reg2, c1_reg1} <= 2'b0;
        q_m_reg <= 9'b0;
    end else begin
        de_reg1 <= de;
        de_reg2 <= de_reg1;
        c0_reg1 <= c0;
        c0_reg2 <= c0_reg1;
        c1_reg1 <= c1;
        c1_reg2 <= c1_reg1;
        q_m_reg <= q_m;
    end

// 数据编码输出逻辑
always @(posedge sys_clk or negedge sys_rst_n)
    if (!sys_rst_n) begin
        data_out <= 10'b0;
        cnt <= 5'b0;
    end else if (de_reg2) begin
        if (condition_2) begin
            // 模式1:直接反转
            data_out[9]   <= ~q_m_reg[8];
            data_out[8]   <= q_m_reg[8];
            data_out[7:0] <= q_m_reg[8] ? q_m_reg[7:0] : ~q_m_reg[7:0];
            cnt <= cnt + (q_m_reg[8] ? (q_m_n1 - q_m_n0) : (q_m_n0 - q_m_n1));
        end else if (condition_3) begin
            // 模式2:全反转+特殊符号
            data_out[9]   <= 1'b1;
            data_out[8]   <= q_m_reg[8];
            data_out[7:0] <= ~q_m_reg[7:0];
            cnt <= cnt + {q_m_reg[8], 1'b0} + (q_m_n0 - q_m_n1);
        end else begin
            // 模式3:保持原样
            data_out[9]   <= 1'b0;
            data_out[8]   <= q_m_reg[8];
            data_out[7:0] <= q_m_reg[7:0];
            cnt <= cnt - {~q_m_reg[8], 1'b0} + (q_m_n1 - q_m_n0);
        end
    end else begin
        // 控制信号输出模式
        case ({c1_reg2, c0_reg2})
            2'b00:   data_out <= DATA_OUT0;
            2'b01:   data_out <= DATA_OUT1;
            2'b10:   data_out <= DATA_OUT2;
            default: data_out <= DATA_OUT3;
        endcase
        cnt <= 5'b0;
    end

endmodule

encode_par模块代码:

module encode_par (
    input  wire         clk         ,
    input  wire         clk_x5      ,
    input  wire         rst         ,
    input  wire         hsync       ,
    input  wire         vsync       ,
    input  wire         de          ,
    input  wire [23:0]  rgb         ,

    output wire         clk_p       ,
    output wire         clk_n       ,
    output wire         r_p         ,
    output wire         r_n         ,    
    output wire         g_p         ,
    output wire         g_n         , 
    output wire         b_p         ,
    output wire         b_n              
);

wire    [9:0]   blue;
wire    [9:0]   green;
wire    [9:0]   red;

encode  encode_inst0
(
    .sys_clk    (clk     ),
    .sys_rst_n  (rst  ),
    .data_in    (rgb[7:0]   ),
    .c0         (hsync      ),
    .c1         (vsync      ),
    .de         (de         ),

    .data_out   (blue       )
);

//------------- encode_inst1 -------------
encode  encode_inst1
(
    .sys_clk    (clk     ),
    .sys_rst_n  (rst  ),
    .data_in    (rgb[15:8]  ),
    .c0         (hsync      ),
    .c1         (vsync      ),
    .de         (de         ),

    .data_out   (green      )
);

//------------- encode_inst2 -------------
encode  encode_inst2
(
    .sys_clk    (clk     ),
    .sys_rst_n  (rst  ),
    .data_in    (rgb[23:16] ),
    .c0         (hsync      ),
    .c1         (vsync      ),
    .de         (de         ),
    
    .data_out   (red        )
);

//------------- par_to_ser_inst0 -------------
par_to_ser  par_to_ser_inst0
(
    .clk_x5      (clk_x5    ),
    .par_data    (blue      ),

    .ser_data_p  (b_p  ),
    .ser_data_n  (b_n  )
);

//------------- par_to_ser_inst1 -------------
par_to_ser  par_to_ser_inst1
(
    .clk_x5      (clk_x5    ),
    .par_data    (green     ),

    .ser_data_p  (g_p  ),
    .ser_data_n  (g_n  )
);

//------------- par_to_ser_inst2 -------------
par_to_ser  par_to_ser_inst2
(
    .clk_x5      (clk_x5    ),
    .par_data    (red       ),

    .ser_data_p  (r_p  ),
    .ser_data_n  (r_n  )
);

//------------- par_to_ser_inst3 -------------
par_to_ser  par_to_ser_inst3
(
    .clk_x5      (clk_x5        ),
    .par_data    (10'b1111100000),

    .ser_data_p  (clk_p    ),
    .ser_data_n  (clk_n    )
);


endmodule //encode_par

hdmi模块代码:

module hdmi (
    input  wire         clk         ,
    input  wire         rst         , 
    
    output  wire        ddc_scl     ,
    output  wire        ddc_sda     , 

    output wire          clk_p       ,
    output wire          clk_n       ,
    output wire          r_p         ,
    output wire          r_n         ,    
    output wire          g_p         ,
    output wire          g_n         , 
    output wire          b_p         ,
    output wire          b_n    

    
);

assign  ddc_scl = 1'b1;
assign  ddc_sda = 1'b1;

wire         hsync       ;
wire         vsync       ;
wire         tft_de      ;
wire [23:0]  rgb         ;


wire locked;

wire clk_out1;
wire clk_out2;

assign  rst_n = (rst & locked);

encode_par encode_par_inst
(
    .clk        (clk_out1 ) ,
    .clk_x5     (clk_out2 ) ,
    .rst        (rst_n    ) ,
    .hsync      (hsync ) ,
    .vsync      (vsync ) ,
    .de         (tft_de    ) ,
    .rgb        (rgb   ) ,

    .clk_p      (clk_p ) ,
    .clk_n      (clk_n ) ,
    .r_p        (r_p   ) ,
    .r_n        (r_n   ) ,    
    .g_p        (g_p   ) ,
    .g_n        (g_n   ) , 
    .b_p        (b_p   ) ,
    .b_n        (b_n   )      
);


tft_colorbar tft_colorbar_inst
(
    .sys_clk    ( clk  ) ,   //输入工作时钟,频率50MHz
    .sys_rst_n  ( rst_n  ) ,   //输入复位信号,低电平有效

    .rgb_tft    ( rgb      ) ,   //输出像素信息
    .hsync      ( hsync    ) ,   //输出行同步信号
    .vsync      ( vsync    ) ,   //输出场同步信号
    .tft_de     ( tft_de   )     //输出TFT使能信号

);


  clk_wiz_1 clk_wiz_1inst
  (
  // Clock out ports  
  .clk_out1(clk_out1),//50mhz
  .clk_out2(clk_out2),//250mhz
  // Status and control signals               
  .reset(~rst), 
  .locked(locked),
 // Clock in ports
  .clk_in1(clk)
  );



endmodule //hdmi
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值