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)实验现象:

相关推荐
eachanm4 小时前
vivado中除法器ip核的使用
fpga开发
IM_DALLA4 小时前
【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL62
学习·fpga开发·verilog学习
诚实可靠小郎君952717 小时前
Testbench编写与Vivado Simulator的基本操作
fpga开发·fpga·simulator·testbench·vivado2018.3
KGback17 小时前
【论文解析】基于开源 Matrix 指令集扩展(矢量点积)的高性能 RISC-V 处理器“香山”(nanhu 版本)的 LLM 加速的研究
fpga开发·risc-v
思尔芯S2C1 天前
What is RISC-V?
fpga开发·soc·risc-v·eda·fpga原型验证·prototyping·verification
dadaobusi1 天前
为什么芯片开发不使用zynq的开发板做环境?(AI问答)
fpga开发
楠了个难1 天前
初识ZYNQ——FPGA学习笔记15
笔记·学习·fpga开发
伊丽莎白鹅1 天前
ZYNQ学习--AXI总线协议
学习·fpga开发
FPGA狂飙1 天前
FPGA IP 和 开源 HDL 一般去哪找?
fpga开发·verilog·fpga·vivado·xilinx