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

news2024/9/27 14:21:41

(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.coloradmin.cn/o/2170214.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSS 背景属性概览:颜色、图像、位置、组合及透明

目录 非 VIP 用户可前往公众号回复“css”进行免费阅读 background - color background - image background - repeat background - position background - attachment background组合 背景透明 非 VIP 用户可前往公众号回复“css”进行免费阅读 background - color …

Stable Diffusion绘画 | SDXL模型的优缺点及模型推荐

现在 SD 已经开始全面进入 SDXL 的高分辨率时代。 SDXL 模型的优点 学习参数最多的模型&#xff1a;参数总量超过100亿&#xff0c;可对标 Midjourney 分辨率提升4倍&#xff1a;底模分辨率直接为 1024 x 1024 多出 Refiner 采样重构器&#xff1a;能增加更多的细节 更强的提示…

2024上海工博会,正运动展位新品与应用方案(二)

上海&#xff0c;9月26日&#xff0c;上海工博会已成功开展三天。正运动展位&#xff08;6.1H-E261&#xff09;依然人气高涨&#xff0c;吸引了众多专业观众和行业同仁的关注。精彩仍在继续&#xff5e; 展会现场 01 多元工业应用场景方案展示 DEMO应用演示在本次展会上&…

云打包p12苹果证书和profile文件在线制作流程

使用hbuilderx的uniapp框架&#xff0c;除了开发小程序外&#xff0c;还可以打包出原生的安卓或苹果应用。 假如是打包安卓应用个&#xff0c;则需要安卓证书。 而假如打包ios应用&#xff0c;则需要p12格式的苹果证书和苹果证书的profile文件。其中苹果证书可以理解为基于非…

c++----继承(初阶)

大家好呀&#xff0c;今天我们也是多久没有更新博客了&#xff0c;今天来讲讲我们c加加中的一个比较重要的知识点继承。首先关于继承呢&#xff0c;大家从字面意思看&#xff0c;是不是像我们平常日常生活中很容易出现的&#xff0c;比如说电视剧里面什么富豪啊&#xff0c;去了…

CDF 累积分布函数图 怎么看

以上图为例&#xff0c;图中有五个数据集&#xff0c;每条曲线代表每个数据集中流的数量&#xff0c;然后我以蓝色的线条为例去解释怎么看这个图。 红色的方框的点说明&#xff0c;dataset-1中流数量少于500的app占全部app的20%&#xff1b;紫色的方框的点说明&#xff0c;da…

win10下NAT 端口转发及ssh VMware ubuntu24虚拟机

问题&#xff1a;win10无法访问VMware ubuntu24虚拟机。ping不通&#xff0c;ssh不通。 现象&#xff1a; 无法设置网桥模式。原因不明。win10 网络连接 中没有vmnet0 网桥模式。win10 网络连接 中&#xff0c;有vmnet8的NAT模式&#xff0c;有vmnet1的仅主机模式。VMware ub…

【Redis】Linux下安装配置及通过C++访问Redis

文章目录 一、Linux Centos 7.0版本下的安装及配置二、通过C访问Redis 一、Linux Centos 7.0版本下的安装及配置 通过源来安装&#xff0c;此次安装的版本为 redis 5.0 的&#xff0c;要通过其他源进行安装&#xff0c;首先安装 scl 源 yum install centos-release-scl-rh再安…

【LeetCode】每日一题 2024_9_26 数组元素和与数字和的绝对差(模拟)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 题目&#xff1a;数组元素和与数字和的绝对差 代码与解题思路 func differenceOfSum(nums []int) int {sum1, sum2 : 0, 0for _, v : range nums {sum1 vfor v > 0 {sum2 v%10v / 10}}return sum1-s…

教师工作量在线管理服务

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

dockerfile部署springboot项目(构建镜像:ebuy-docker:v1.0)

文章目录 1、docker部署Mysql2、dockerfile构建镜像1.1、在idea中导入课件中的项目资料\day01\ebuy-docker1.2、修改项目application.yml数据库连接参数1.3、启动项目访问测试&#xff1a;http://localhost:8081/1.4、执行mvn package命令进行项目打包1.5、虚拟机中新建目录/op…

高性能计算秘密武器:NVIDIA B100与B200如何让你的HPC性能飙升?

嘿&#xff0c;各位科技界的狂热粉丝、AI领域的探索先锋&#xff0c;你们是否正站在高性能计算&#xff08;HPC&#xff09;的十字路口&#xff0c;寻找那把能开启全新纪元的钥匙&#xff1f;今天&#xff0c;就让我带你深入剖析NVIDIA的最新力作——B100与B200&#xff0c;一同…

C++结尾

面试题 1.什么是虚函数&#xff1f;什么是纯虚函数 在定义函数时前面加virtual。虚函数是为了&#xff0c;父子类中只有一个该函数。如果在子类重写虚函数&#xff0c;那么用的就是子类重写的虚函数&#xff1b;如果子类没有重写虚函数&#xff0c;那么调用的是父类继承的虚函…

【JAVA开源】基于Vue和SpringBoot的网上租赁系统

本文项目编号 T 050 &#xff0c;文末自助获取源码 \color{red}{T050&#xff0c;文末自助获取源码} T050&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析5.4 用例设计5.4.1 用…

生信软件37 - 基于测序reads的变异进行单倍型分型工具WhatsHap

1. WhatsHap简介 WhatsHap是一种使用DNA测序reads的基因组变异进行定相&#xff08;分型&#xff09;的软件&#xff0c;即基于reads的定相或单倍型组装&#xff0c;特别适用于长reads &#xff08;三代测序数据&#xff09;&#xff0c;但也兼容短reads的定相。 Whatshap特点…

Ubuntu22.04安装cudnn详细步骤

下载指定版本的cudnn https://developer.nvidia.com/rdp/cudnn-archive#a-collapse804-111 安装 sudo dpkg -i cudnn-local-repo-ubuntu2204-8.9.7.29_1.0-1_amd64.deb 根据上步提示&#xff1a; sudo cp /var/cudnn-local-repo-ubuntu2204-8.9.7.29/cudnn-local-08A7D361-…

【C++】STL标准模板库容器set

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C ⚙️操作环境:Visual Studio 2022 目录 &#x1f4cc;关联式容器set(集合)简介 &#x1f4cc;set(集合)的使用 &#x1f38f;set(集合)的模板参数列表 &#x1f38f;set(集合)的构造函数 &#x1f38f;set(集合)的迭代…

【算法题】72. 编辑距离-力扣(LeetCode)

【算法题】72. 编辑距离-力扣(LeetCode) 1.题目 下方是力扣官方题目的地址 72. 编辑距离 给你两个单词 word1 和 word2&#xff0c; 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作&#xff1a; 插入一个字符删除一个字符替换一个…

哈希算法以及容器实现

哈希 一&#xff0c;哈希算法1.什么是哈希2.哈希产生的原因3.常见哈希算法4.闭散列&#xff08; 哈希表&#xff09;1.线性探测2.二次探测 5.开散列&#xff08;哈希桶&#xff09;1.开散列插入2.开散列扩容 二&#xff0c;代码实现1.哈希表2.哈希桶1.迭代器的实现2.底层容器的…

C++ --- 模板为什么不能分离编译?

模板为甚么不能分离编译&#xff0c;但普通函数却可以&#xff1f; 一、前置知识二、普通函数能分离编译的原因三、模板不能分离编译的原因 一、前置知识 编译阶段: 源代码到目标代码&#xff1a; 编译器首先将源代码&#xff08;如C/C文件&#xff09;翻译成汇编语言&#x…