当前位置: 首页 > article >正文

63.HDMI显示器驱动设计与验证-彩条实验

(1)常见的视频传输接口有三种: VGA 接口、 DVI 接口和 HDMI 接口,目前的显示设备都配有这三种视频传输接口。三类视频接口的发展历程为 VGA→DVI→HDMI。其中 VGA 接口出现最早,只能传输模拟图像信号; 随后出现的 DVI 接口又分为三类: DVI-A、 DVI-D、 DVI-I,分别可传输纯模拟图像信号、纯数字图像信号和兼容模拟、数字图像信号;最后的HDMI 在传输数字图像信号的基础上又可以传输音频信号。

(2)HDMI 全称“High Definition Multimedia Interface 高清多媒体接口”,HDMI 标准的制定,并没有抛弃 DVI 标准中相对成熟且较易实现的部分技术标准,整个传输原理依然是基于 TMDS 编码技术。针对 DVI 的诸多问题,HDMI 做了大幅改进。HDMI 接口体积更小,各种设备都能轻松安装可用于机顶盒、DVD 播放机、个人计算机、电视、游戏主机、综合扩大机、数字音响与电视机等设备;抗干扰能力更强,能实现最长20 米的无增益传输;针对大尺寸数字平板电视分辨率进行优化,兼容性好;拥有强大的版权保护机制(HDCP),有效防止盗版现象;支持 24bit 色深处理,(RGB、YCbCr4-4-4、YCbCr4-2-2);一根线缆实现数字音频、视频信号同步传输,有效降低使用成本和繁杂程度。

(3)HDMI type-a 引脚

TMDS:最小化传输差分信号

升腾A7板块采用了SII9134芯片,能实现VGA转HDMI的编码,因此不需要自己编写HDMI的编码

(4)如果要编写HDMI编码,对应Visio视图:

(5)TMDS编码(8bit转10bit)具体代码:

module encode
(
    input   wire                hdmi_clk        ,       
    input   wire                reset_n         ,       //复位信号,低电平有效
    input   wire                hsync           ,       //行同步信号
    input   wire                vsync           ,       //列同步信号
    input   wire                de              ,       
    input   wire        [7:0]   data_in         ,       
    
    output  reg         [9:0]   data_out           
);

//变量定义
wire            condition_1     ;
wire            condition_2     ;
wire            condition_3     ;
wire    [8:0]   q_m             ;

reg     [3:0]   q_m_n1          ;
reg     [3:0]   q_m_n0          ;
reg     [3:0]   data_in_n1      ;     //最多8个1 ,即1000 四位
reg     [7:0]   data_in_reg     ;
reg     [4:0]   cnt             ;
reg     [8:0]   q_m_reg         ;
reg             de_reg0         ;
reg             de_reg1         ;
reg             hsync_reg0      ;
reg             hsync_reg1      ;
reg             vsync_reg0      ;
reg             vsync_reg1      ;

//条件定义
always@(posedge hdmi_clk or negedge reset_n)
    if(!reset_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];
                        
assign condition_1 = (data_in_n1 > 4'd4) || ((data_in_n1 == 4'd4) && (data_in_reg[0] == 1'd0));

always@(posedge hdmi_clk or negedge reset_n)
    if(!reset_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   =   4'd8 - (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] == 1'd0) && (q_m_n1 > q_m_n0)) 
                        || ((cnt[4] == 1'd1) && (q_m_n1 < q_m_n0)); 


//打拍变量定义
always@(posedge hdmi_clk or negedge reset_n)
    if(!reset_n)begin
        data_in_reg <= 8'd0;
        q_m_reg     <= 9'd0;
        de_reg0     <= 1'd0;
        de_reg1     <= 1'd0;
        hsync_reg0  <= 1'd0;
        hsync_reg1  <= 1'd0;
        vsync_reg0  <= 1'd0;
        vsync_reg1  <= 1'd0;       
    end
    else begin 
        data_in_reg <= data_in;
        q_m_reg     <= q_m  ;
        de_reg0     <= de;
        de_reg1     <= de_reg0;
        hsync_reg0  <= hsync;
        hsync_reg1  <= hsync_reg0;
        vsync_reg0  <= vsync;
        vsync_reg1  <= vsync_reg0;     
    end

//q_m信号变量
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'd0 : 1'd1;

always@(posedge hdmi_clk or negedge reset_n)
    if(!reset_n)begin
        data_out <= 10'd0;
        cnt      <= 5'd0;
    end
    else begin
        if(de_reg1)begin
            if(condition_2)begin
                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]);
                if(q_m_reg[8] == 1'd0)
                    cnt <= cnt + q_m_n0 - q_m_n1;
                else 
                    cnt <= cnt + q_m_n1 - q_m_n0;
            end
            else begin
                if(condition_3)begin
                    data_out[9] <= 1'd1;
                    data_out[8] <= q_m_reg[8];
                    data_out[7:0] <= ~q_m_reg[7:0];
                    cnt <= cnt + {q_m_reg[8],1'd0} + q_m_n0 - q_m_n1;
                end
                else begin
                    data_out[9] <= 1'd0;
                    data_out[8] <= q_m_reg[8];
                    data_out[7:0] <= q_m_reg[7:0];
                    cnt <= cnt - {~q_m_reg[8],1'd0} + q_m_n1 - q_m_n0;  
                end
            end
        end
        else begin
            cnt <= 5'd0;
            case({vsync_reg1,hsync_reg0})
                2'b00: data_out <= 10'b11_0101_0100;
                2'b01: data_out <= 10'b00_1010_1011;
                2'b10: data_out <= 10'b01_0101_0100;
                2'b11: data_out <= 10'b10_1010_1011;
                default:;
            endcase
        end
    
    end


endmodule

(6)原语:英文全称“Primitive”,是Xilinx针对其器件特征开发的一系列常用模块的名字,用户可以将其视为Xilinx公司为用户提供的库函数。原语按照功能可以分为10类,包括:计算组件、IO端口组件、寄存器和锁存器、时钟组件、处理器组件、移位寄存器组件、配置和检测组件、RAM/ROM组件、Slice/CLB组件以及G比特收发器组件。

(7)ODDR是Xilinx提供的双数据速率原语,双数据速率原语ODDR可以用于在逻辑资源中实现DDR寄存器,可以把单沿传输的数据转换为双沿传输的数据。

OBUFDA是Xilinx提供的将单端信号转换为差分信号的原语。

(8)升腾Pro对应Viso视图(驱动SII934芯片):

(9)对应代码:

  • IIC控制器
module IIC_ctrl(

    input   wire            clk         ,
    input   wire            reset_n     ,
    input   wire            IIC_start   ,
    input   wire            wr_en       ,
    input   wire            rd_en       ,
    input   wire    [7:0]   device_addr ,
    input   wire    [15:0]  byte_addr   ,
    input   wire    [7:0]   wr_data     ,
    input   wire            addr_num    ,
    
    output  reg             IIC_SCL     ,
    inout   wire            IIC_SDA     ,
    output  reg             IIC_clk     ,
    output  reg             IIC_end     ,
    output  reg     [7:0]   rd_data     
    
);

    reg     [4:0]       cnt_1M          ;      //计数最大值是25  一个五位宽的寄存器足以胜任计数任务
    reg     [15:0]      state           ;
    reg     [1:0]       IIC_clk_cnt     ;
    reg                 EN_IIC_clk_cnt  ;
    reg     [2:0]       bit_cnt         ;
    reg                 ack             ;
    reg                 sda_out         ;
    reg     [7:0]       rd_data_reg     ;
        
    wire                sda_in          ;
    wire                EN_IIC_SDA      ;
    wire    [6:0]       device_add_i    ;   
    
    assign device_add_i = device_addr[7:1];
    
    parameter IDLE        =  16'b0000_0000_0000_0001    ;       //空闲状态
    parameter START       =  16'b0000_0000_0000_0010    ;       //发送开始信号
    parameter SEND_D_A    =  16'b0000_0000_0000_0100    ;       //发送控制命令(器件地址+写操作)   {7'b1010_011,1'b0}
    parameter ACK_1       =  16'b0000_0000_0000_1000    ;       //等待响应 
    parameter SEND_B_H    =  16'b0000_0000_0001_0000    ;       //发送存储地址高8位  
    parameter ACK_2       =  16'b0000_0000_0010_0000    ;       //等待响应
    parameter SEND_B_L    =  16'b0000_0000_0100_0000    ;       //发送存储地址低8位
    parameter ACK_3       =  16'b0000_0000_1000_0000    ;       //等待响应
    parameter WR_DATA     =  16'b0000_0001_0000_0000    ;       //写入单比特数据   
    parameter ACK_4       =  16'b0000_0010_0000_0000    ;       //等待响应
    parameter START_2     =  16'b0000_0100_0000_0000    ;       //发送开始信号
    parameter SEND_RD_A   =  16'b0000_1000_0000_0000    ;       //发送控制命令(器件地址+读操作)   {7'b0101_011,1'b1} 
    parameter ACK_5       =  16'b0001_0000_0000_0000    ;       //等待响应
    parameter RD_DATA     =  16'b0010_0000_0000_0000    ;       //读出单比特数据
    parameter NO_ACK      =  16'b0100_0000_0000_0000    ;       //等待无响应信号
    parameter END         =  16'b1000_0000_0000_0000    ;       //结束单比特传输
    
//    parameter DEVICE_ADD  =  7'b1010_011 ;                      //EEPROM器件地址设定
    

/*-----------IIC_clk生成模块--------------------*/
//IIC_clk 频率要求1MHz,而系统时钟clk频率为50MHz,半个周期需要计数25次(5位寄存器)

always@(posedge clk or negedge reset_n)
    if(!reset_n)
        cnt_1M <= 5'd0;
    else if(cnt_1M == 5'd24)
        cnt_1M <= 5'd0;
    else 
        cnt_1M <= cnt_1M + 5'd1;
     
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        IIC_clk <= 1'd0;
    else if(cnt_1M == 5'd24)
        IIC_clk <= ~IIC_clk;
    else 
        IIC_clk <= IIC_clk;
  
/*----------------状态机设计-----------------------*/  

always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        state <= IDLE;
    else begin
        case(state)
            IDLE      :
                        if(IIC_start)
                            state <= START;
                        else 
                            state <= state;
            START     : 
                        if(IIC_clk_cnt == 2'd3)
                            state <= SEND_D_A;
                        else 
                            state <= state;           
            SEND_D_A  : 
                        if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                            state <= ACK_1;
                        else 
                            state <= state;
            ACK_1     : 
                        if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) &&  (addr_num == 1'd1))
                            state <= SEND_B_H;
                        else if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (addr_num == 1'd0))
                            state <= SEND_B_L;
                        else 
                            state <= state;  
            SEND_B_H  : 
                        if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                            state <= ACK_2;
                        else 
                            state <= state;
            ACK_2     : 
                        if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))
                            state <= SEND_B_L;
                        else 
                            state <= state;  
            SEND_B_L  : 
                        if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                            state <= ACK_3;
                        else 
                            state <= state;
            ACK_3     : 
                        if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (wr_en == 1'd1))
                            state <= WR_DATA;
                        else if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (rd_en == 1'd1))
                            state <= START_2;
                        else 
                            state <= state;
            WR_DATA   : 
                        if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                            state <= ACK_4;
                        else 
                            state <= state;
            ACK_4     : 
                        if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))
                            state <= END;
                        else 
                            state <= state; 
            START_2   : 
                        if(IIC_clk_cnt == 2'd3)
                            state <= SEND_RD_A;
                        else 
                            state <= state; 
            SEND_RD_A : 
                        if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                            state <= ACK_5;
                        else 
                            state <= state;
            ACK_5     : 
                        if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))
                            state <= RD_DATA;
                        else 
                            state <= state; 
            RD_DATA   : 
                        if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                            state <= NO_ACK;
                        else 
                            state <= state;
            NO_ACK    : 
                        if(IIC_clk_cnt == 2'd3)
                            state <= END;
                        else 
                            state <= state; 
            END       : 
                        if((bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
                            state <= IDLE;
                        else 
                            state <= state;
            default   : state <= IDLE;
        endcase       
    end
        
/*----------------IIC_clk_cnt 、 EN_IIC_clk_cnt设计-----------------------*/
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        IIC_clk_cnt <= 2'd0;
    else if(!EN_IIC_clk_cnt) 
        IIC_clk_cnt <= 2'd0;
    else 
        IIC_clk_cnt <= IIC_clk_cnt + 2'd1;

always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        EN_IIC_clk_cnt <= 1'd0;
    else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
        EN_IIC_clk_cnt <= 1'd0;
    else if(IIC_start)
        EN_IIC_clk_cnt <= 1'd1;
    else 
        EN_IIC_clk_cnt <= EN_IIC_clk_cnt;

/*--------------------bit_cnt设计-----------------------*/
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        bit_cnt <= 3'd0;
    else if((state == IDLE)||(state == START)||(state == ACK_1)
                ||(state == ACK_2)||(state == ACK_3)||(state == ACK_4) 
                ||(state == START_2)||(state == ACK_5)||(state == NO_ACK))
        bit_cnt <= 3'd0;
    else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
        bit_cnt <= 3'd0;
    else if(IIC_clk_cnt == 2'd3)
        bit_cnt <= bit_cnt + 3'd1;
    else 
        bit_cnt <= bit_cnt;

/*--------------------ack 、 sda_in信号设计---------------------------*/
always@(*)
    begin
        case(state)
            ACK_1,ACK_2,ACK_3,ACK_4,ACK_5   : if(IIC_clk_cnt == 2'd0)
                                                    ack <= sda_in   ;
                                              else 
                                                    ack <= ack      ;
            default                         : ack = 1'd1;
        endcase
    end

assign sda_in = IIC_SDA ;

/*--------------------IIC_SCL设计-----------------------*/
always@(*)
    begin
        case(state)
            IDLE:
                    IIC_SCL <= 1'd1;
            START:
                    if(IIC_clk_cnt == 2'd3)
                        IIC_SCL <= 1'd0;
                    else 
                        IIC_SCL <= 1'd1;
            SEND_D_A,ACK_1,SEND_B_H,ACK_2,SEND_B_L,ACK_3,WR_DATA,
                ACK_4,START_2,SEND_RD_A,ACK_5,RD_DATA,NO_ACK:
                    if((IIC_clk_cnt == 2'd1) || (IIC_clk_cnt == 2'd2))
                        IIC_SCL <= 1'd1;
                    else 
                        IIC_SCL <= 1'd0;
            END:
                    if((bit_cnt == 3'd0) && (IIC_clk_cnt == 2'd0))
                        IIC_SCL <= 1'd0;
                    else 
                        IIC_SCL <= 1'd1;
            default:
                    IIC_SCL <= 1'd1;
        endcase
    end
    
/*--------------------sda_out 、 rd_data_reg设计-----------------------*/
always@(*)
    begin
        case(state)
            IDLE        :begin
                            sda_out <= 1'd1; 
                            rd_data_reg <= 8'd0;
                         end
            START       :
                if(IIC_clk_cnt >= 2'd1)
                    sda_out <= 1'd0; 
                else 
                    sda_out <= 1'd1;
            SEND_D_A    :
                if(bit_cnt <= 3'd6)
                    sda_out <= device_add_i[6 - bit_cnt];
                else 
                    sda_out <= 1'd0;
            ACK_1,ACK_2,ACK_3,ACK_4,ACK_5   :
                sda_out <= 1'd1;
            SEND_B_H    :  
                sda_out <= byte_addr[15-bit_cnt]; 
            SEND_B_L    :  
                sda_out <= byte_addr[7-bit_cnt];     
            WR_DATA     :
                sda_out <= wr_data[7-bit_cnt];        
            START_2     :
                if(IIC_clk_cnt >= 2'd2)
                    sda_out <= 1'd0; 
                else 
                    sda_out <= 1'd1;   
            SEND_RD_A   :
                if(bit_cnt <= 3'd6)
                    sda_out <= device_add_i[6 - bit_cnt];
                else 
                    sda_out <= 1'd1;                 
            RD_DATA     :begin
                            sda_out <= 1'd1;
                            if(IIC_clk_cnt == 2'd2)
                                rd_data_reg[7 - bit_cnt] <=  sda_in;
                            else    
                                rd_data_reg <= rd_data_reg;
                         end
            NO_ACK      :
                sda_out <= 1'd1;
            END         :
                if((bit_cnt == 3'd0) && (IIC_clk_cnt <= 2'd2))
                    sda_out <= 1'd0;
                else 
                    sda_out <= 1'd1;
            default     :begin
                    sda_out <= 1'd1;
                    rd_data_reg <= rd_data_reg;
            end
        endcase
    end
 
/*--------------------rd_data设计-----------------------*/ 
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        rd_data <= 8'd0;
    else if((state == RD_DATA) && (bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
        rd_data <= rd_data_reg;
    else    
        rd_data <= rd_data;
        
/*--------------------EN_IIC_SDA设计-----------------------*/ 
//EN_IIC_SDA信号为1,表示IIC_SDA输出;反之,EN_IIC_SDA信号为0,表示IIC_SDA作为输入.

assign EN_IIC_SDA = ((state == IDLE) || (state == START) || (state == SEND_D_A) 
                        || (state == SEND_B_H) || (state == SEND_B_L) || (state == WR_DATA)
                        || (state == START_2) || (state == SEND_RD_A) || (state == NO_ACK)
                        || (state == END));
                        
/*--------------------IIC_SDA设计-----------------------*/ 
assign IIC_SDA = EN_IIC_SDA ? sda_out : 1'dz;

/*--------------------IIC_end设计-----------------------*/ 
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        IIC_end <= 1'd0;
    else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
        IIC_end <= 1'd1;
    else 
        IIC_end <= 1'd0;

endmodule
  • 给SII9134寄存器配置的模块
    module hdmi_cfg
    (
        input   wire            cfg_clk     ,
        input   wire            reset_n     ,
        input   wire            cfg_end     ,
        
        output  reg             cfg_start   ,
        output  wire   [31:0]   cfg_data    ,
        output  reg             cfg_done
        
    );
    
    parameter NUM_REG   = 10'd4 ;
    parameter CNT_WAIT_MAX  = 10'd1023  ;
    
    reg     [9:0]   cnt_wait    ;
    reg     [9:0]   cnt_num     ;
                     
    wire    [31:0]  cfg_data_reg[NUM_REG - 1'd1 : 0];
    
    assign cfg_data_reg[0] = {8'h72,16'h08,8'h35};
    assign cfg_data_reg[1] = {8'h72,16'h49,8'h00};
    assign cfg_data_reg[2] = {8'h72,16'h4a,8'h00};
    assign cfg_data_reg[3] = {8'h72,16'h2f,8'h00};
    
    always@(posedge cfg_clk or negedge reset_n)
        if(!reset_n)
            cnt_wait <= 10'd0;
        else if(cnt_wait == CNT_WAIT_MAX)
            cnt_wait <= cnt_wait;
        else 
            cnt_wait <= cnt_wait + 10'd1;
    
    always@(posedge cfg_clk or negedge reset_n)
        if(!reset_n)
            cnt_num <= 10'd0;
        else if(cfg_end)
            cnt_num <= cnt_num + 10'd1;
        else 
            cnt_num <= cnt_num  ;
          
    always@(posedge cfg_clk or negedge reset_n)
        if(!reset_n)
            cfg_start <= 1'd0;
        else if(cnt_wait == CNT_WAIT_MAX - 1'd1)
            cfg_start <= 1'd1;
        else if(cfg_end == 1'd1 && cnt_num < NUM_REG)
            cfg_start <= 1'd1;
        else 
            cfg_start <= 1'd0;
            
    assign cfg_data = cfg_done ?  32'd0 : cfg_data_reg[cnt_num];
    
    always@(posedge cfg_clk or negedge reset_n)
        if(!reset_n)
            cfg_done <= 1'd0;
        else if(cfg_end == 1'd1 && cnt_num == NUM_REG)
            cfg_done <= 1'd1;
        else 
            cfg_done <= cfg_done; 
    
    endmodule
    
  • IIC顶层模块
    module hdmi_iic
    (
        input       wire                hdmi_clk        ,
        input       wire                reset_n         ,
        
        output      wire                hdmi_scl        ,
        inout       wire                hdmi_sda        
    );
    
    wire                IIC_start;
    wire                IIC_end;
    wire    [31:0]      cfg_data; 
    wire                cfg_clk;
    
    IIC_ctrl    IIC_ctrl_inst
    (
    
        .clk         (hdmi_clk          ),
        .reset_n     (reset_n           ),
        .IIC_start   (IIC_start         ),
        .wr_en       (1'd1              ),
        .rd_en       (),
        .device_addr (cfg_data[31:24]   ),
        .byte_addr   (cfg_data[23:8]    ),
        .wr_data     (cfg_data[7:0]     ),
        .addr_num    (1'd0              ),
    
        .IIC_SCL     (hdmi_scl          ),
        .IIC_SDA     (hdmi_sda          ),
        .IIC_clk     (cfg_clk           ),
        .IIC_end     (IIC_end           ),
        .rd_data     ()
    );
    
    hdmi_cfg    hdmi_cfg_inst
    (
        .cfg_clk     (cfg_clk           ),
        .reset_n     (reset_n           ),
        .cfg_end     (IIC_end           ),
    
        .cfg_start   (IIC_start         ),
        .cfg_data    (cfg_data          ),
        .cfg_done    ()
        
    );
    
    endmodule
    
  • 彩条数据生成模块
module data_gen(
    input   [9:0]   hang        ,
    input   [9:0]   lie         ,
    input           hdmi_clk     ,
    input           reset_n     ,
    
    output  reg     [23:0]  data    
);
//定义最大行、列
    parameter HANG_MAX  = 640   ;
    parameter LIE_MAX   = 480   ;
    
//定义颜色
    parameter RED       =   24'hff0000;
    parameter ORANGE    =   24'hffcc66;
    parameter YELLOW    =   24'hffff00;
    parameter GREEN     =   24'h33cc33;
    parameter CYAN      =   24'h00ffcc;
    parameter BLUE      =   24'h3333ff;
    parameter PUPPLE    =   24'hcc00cc;
    parameter BLACK     =   24'h000000;
    parameter WHITE     =   24'hffffff;
    parameter GRAY      =   24'hb2b2b2;

//数据生成设计
    always@(posedge hdmi_clk or negedge reset_n)
        if(!reset_n)
            data <= BLACK   ;
        else if((hang >= 1) && (hang <= HANG_MAX/10))
            data <= RED     ;
        else if((hang > HANG_MAX/10) && (hang <= (HANG_MAX/10) * 2))
            data <= ORANGE  ;
        else if((hang > (HANG_MAX/10) * 2) && (hang <= (HANG_MAX/10) * 3))
            data <= YELLOW  ;
        else if((hang > (HANG_MAX/10) * 3) && (hang <= (HANG_MAX/10) * 4))
            data <= GREEN  ;
        else if((hang > (HANG_MAX/10) * 4) && (hang <= (HANG_MAX/10) * 5))
            data <= CYAN  ;
        else if((hang > (HANG_MAX/10) * 5) && (hang <= (HANG_MAX/10) * 6))
            data <= BLUE  ;
        else if((hang > (HANG_MAX/10) * 6) && (hang <= (HANG_MAX/10) * 7))
            data <= PUPPLE  ;
        else if((hang > (HANG_MAX/10) * 7) && (hang <= (HANG_MAX/10) * 8))
            data <= BLACK  ;
        else if((hang > (HANG_MAX/10) * 8) && (hang <= (HANG_MAX/10) * 9))
            data <= WHITE  ;
        else if((hang > (HANG_MAX/10) * 9) && (hang <= HANG_MAX))
            data <= GRAY   ;
        else
            data <= BLACK  ;
            
endmodule
  • 顶层模块:
    module hdmi_colorbar
    (
        input   wire                clk             ,
        input   wire                reset_n         ,
        
        output  wire                hdmi_clk        ,
        output  wire                hdmi_reset_n    ,
        output  wire                hdmi_scl        ,
        inout   wire                hdmi_sda        ,
        output  wire    [23:0]      rgb_tft         ,
        output  wire                hsync           ,
        output  wire                vsync           ,
        output  wire                tft_DE  
        
    );
    
    wire            clk_25M ;
    wire            rst_n   ;
    wire            locked  ;
    wire    [9:0]   hang    ;
    wire    [9:0]   lie     ;
    wire    [23:0]  data    ;
    
    assign  rst_n = reset_n & locked    ;
    assign  hdmi_reset_n = rst_n        ;
    
    clk_gen clk_gen_inst
    (
        .clk_25M    (clk_25M    ),     // output clk_25M
        .clk_125M   (),    
        .reset      (~reset_n   ), 
        .locked     (locked     ),       
        .clk_in1    (clk        )
    );    
    
    assign hdmi_clk = clk_25M;  
    
    data_gen   data_gen_inst
    (
        .hang        (hang      ),
        .lie         (lie       ),
        .hdmi_clk    (clk_25M   ),
        .reset_n     (rst_n     ),
        
        .data        (data      )    
    );
    
    tft_ctrl    tft_ctrl_inst
    (
        .hdmi_clk        (clk_25M       ),
        .reset_n         (rst_n         ),
        .data_in         (data          ),
    
        .hang            (hang          ),
        .lie             (lie           ),
        .hsync           (hsync         ),
        .vsync           (vsync         ),
        .rgb_tft         (rgb_tft       ),
        .tft_DE          (tft_DE        )
    );
    
    hdmi_iic    hdmi_iic_inst
    (
        .hdmi_clk        (clk_25M       ),
        .reset_n         (rst_n         ),
                         
        .hdmi_scl        (hdmi_scl      ),
        .hdmi_sda        (hdmi_sda      )
        
    );
    
    endmodule
    

(10)实验现象:


http://www.kler.cn/news/321545.html

相关文章:

  • LeetCode142. 环形链表 II(2024秋季每日一题 28)
  • 付费和免费代理IP工具的区别大吗?
  • 深度学习中的正则化和归一化
  • JWT令牌技术介绍及使用
  • Spring事务和AOP
  • 文件上传、重定向、Gin路由
  • 融云音视频RTC介绍
  • 六、设计模式-6.1、单例模式
  • 显示技术概念极简理解(分辨率、英寸、PPI、DPI)
  • IDEA Dependency Analyzer 分析 maven 项目包的依赖
  • Python 使用selenium 4.25 进行爬虫(1)
  • 一文读懂电路中VCC、VDD、VEE、VSS的区别
  • YOLOv8改进 - 注意力篇 - 引入SK网络注意力机制
  • 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-26
  • 了解网络的相关信息
  • 从0开始linux(5)——vim
  • 微信小程序-canvas
  • go语言网络编程
  • 【Linux 从基础到进阶】Kafka消息队列配置与管理
  • C/C++中的内存管理
  • c语言200例 063 信息查询
  • 数据结构 ——— 移除元素(快慢指针)
  • io流(学习笔记03)字符集
  • 大数据时代的PDF解析:技术与挑战
  • Python:百度贴吧实现自动化签到
  • Spring是什么
  • 有源蜂鸣器(5V STM32)
  • 无人机之虚拟云台技术篇
  • LeetCode 137. 只出现一次的数字 II
  • Linux安装vim超详细教程