【盘古100Pro+开发板实验例程】FPGA学习 | HDMI 回环实验

本原创文章由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注明出处(www.meyesemi.com)

1. 实验简介

实验目的:

完成 HDMI 回环实验

实验环境:

Window11

PDS2022.2-SP6.4

硬件环境:

MES2L676-100HP

2. 实验原理

HDMI 输入接口采用宏晶微 MS7200 HMDI 接收芯片,HDMI 输出接口采用宏晶微 MS7210 HMDI 发送芯片。 芯片兼容 HDMI1.4b 及以下标准视频的 3D 传输格式,最高分辨率高达 4K@30Hz,最高采样率达到 300MHz, 支持 YUV 和 RGB 之间的色彩空间转换,数字接口支持 YUV 及 RGB 格式。

MS7200 和 MS7210 的 IIC 配置接口与 FPGA 的 IO 相连,通过 FPGA 的编程来对芯片进行初始化和配置操作。

MES2L100HP 开发板上将 MS7200 的 SA 管脚下拉到地,故 IIC 的 ID 地址为 0x56,将 MS7210 的 SA 管脚 上拉到电源电压,故 IIC 的 ID 地址为 0xB2。

2.1. 显示原理

下图表示一个 8*8 像素的画面,图中每个格子表示一个像素点,显示图像时像素点快速点亮的过程按表格中 编号的顺序逐个点亮,从左到右,从上到下,按图中箭头方向的"Z"字形顺序。

以上图为例,每行 8 个像素点,每完成一行信号的传输,会转到下一行信号传输,直到完成第 8 行数据的传输, 就完成了一个画面的数据传输了,一个画面也称为一场或一帧,显示每秒中刷新的帧数称为帧率。比如 1920*1080P 像素,就是 1 行有效像素点 1920,一场有效行为 1080 行。

每个像素点的像素值数据,对应每个像素点的颜色。常见的像素值表示格式比如:RGB888,RGB 分别代表: 红 R,绿 G,蓝 B,888 是指 R、G、B 分别有 8bit,也就是 R、G、B 每一色光有 28=256 级阶调,通过 RGB 三色光的 不同组合,一个像素上最多可显示 24 位的 256*256*256 =16,777,216 色。

HDMI 显示的数据源采用 verilog 编写的显示时序产生模块 sync_vg 实现上图的时序,彩条生成模块 pattern_vg 根据像素点所在位置,即列数和行数确定像素值,实现彩条图案。

2.2. HDMI_PHY 配置

MS7200 为 HMDI 接收芯片,MS7210 为 HMDI 发送芯片,芯片的 IIC 配置接口已与 FPGA 的 IO 相连,芯片 正常使用需要通过 FPGA 的对芯片进行初始化和配置操作。寄存器配置切忌修改。具体配置可以参考 demo。

3. 接口列表

顶层模块接口如下所示:

4. 工程说明

系统时钟 sys_clk 通过 pll 锁相环 IP 分出 cfg_clk 给到 ms72xx_ctl 模块,该模块通过 IIC 配置 MS7200 与 MS7210 芯片。HDMI 输入的数据经过 MS7200 芯片解码后转成标准 RGB 格式的数据输入到 FPGA 中。再将该数 据输出到 MS7210 芯片。MS7210 将 RGB 格式的数据编码成 TMDS 信号对外输出。

5. 代码模块说明

Ms72xx_ctl.v 模块

复制代码
module ms72xx_ctl(
    input clk,
    input rst_n,
    output init_over,
    output iic_tx_scl,
    inout iic_tx_sda,
    output iic_scl,
    inout iic_sda
);

    reg rstn_temp1, rstn_temp2;
    reg rstn;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            rstn_temp1 <= 1'b0;
        else
            rstn_temp1 <= rst_n;
    end

    always @(posedge clk) begin
        rstn_temp2 <= rstn_temp1;
        rstn <= rstn_temp2;
    end

    wire init_over_rx;
    wire [7:0] device_id_rx;
    wire iic_trig_rx;
    wire w_r_rx;
    wire [15:0] addr_rx /*synthesis PAP_MARK_DEBUG="true"*/;
    wire [7:0] data_in_rx;
    wire busy_rx;
    wire [7:0] data_out_rx;
    wire byte_over_rx;

    wire [7:0] device_id_tx;
    wire iic_trig_tx;
    wire w_r_tx;
    wire [15:0] addr_tx /*synthesis PAP_MARK_DEBUG="true"*/;
    wire [7:0] data_in_tx;
    wire busy_tx;
    wire [7:0] data_out_tx;
    wire byte_over_tx;

    ms7200_ctl ms7200_ctl(
        .clk      (clk),           // input
        .rstn     (rstn),          // input
        .init_over(init_over_rx),  // output reg
        .device_id(device_id_rx),  // output [7:0]
        .iic_trig (iic_trig_rx),   // output reg
        .w_r      (w_r_rx),       // output reg
        .addr     (addr_rx),       // output reg [15:0]
        .data_in  (data_in_rx),    // output reg [7:0]
        .busy     (busy_rx),       // input
        .data_out (data_out_rx),   // input [7:0]
        .byte_over(byte_over_rx)   // input
    );

    ms7210_ctl ms7210_ctl(
        .clk      (clk),           // input
        .rstn     (init_over_rx),  // input
        .init_over(init_over),     // output reg
        .device_id(device_id_tx), // output [7:0]
        .iic_trig (iic_trig_tx),  // output reg
        .w_r      (w_r_tx),       // output reg
        .addr     (addr_tx),      // output reg [15:0]
        .data_in  (data_in_tx),   // output reg [7:0]
        .busy     (busy_tx),      // input
        .data_out (data_out_tx),  // input [7:0]
        .byte_over(byte_over_tx)  // input
    );

    wire sda_in     /*synthesis PAP_MARK_DEBUG="true"*/;
    wire sda_out    /*synthesis PAP_MARK_DEBUG="true"*/;
    wire sda_out_en /*synthesis PAP_MARK_DEBUG="true"*/;

    iic_dri #(
        .CLK_FRE    (27'd10_000_000),  // system clock frequency
        .IIC_FREQ   (20'd400_000),     // I2c clock frequency
        .T_WR       (10'd1),           // I2c transmit delay ms
        .ADDR_BYTE  (2'd2),            // I2C addr byte number
        .LEN_WIDTH  (8'd3),            // I2C transmit byte width
        .DATA_BYTE  (2'd1)             // I2C data byte number
    ) iic_dri_rx (
        .clk        (clk),
        .rstn       (rstn),
        .device_id  (device_id_rx),
        .pluse      (iic_trig_rx),     // I2C transmit trigger
        .w_r        (w_r_rx),         // I2C transmit direction 1:send 0:receive
        .byte_len   (4'd1),            // I2C transmit data byte length
        .addr       (addr_rx),         // I2C transmit addr
        .data_in    (data_in_rx),      // I2C send data
        .busy       (busy_rx),         // I2C bus status
        .byte_over  (byte_over_rx),    // I2C byte transmit over flag
        .data_out   (data_out_rx),     // I2C receive data
        .scl        (iic_scl),
        .sda_in     (sda_in),
        .sda_out    (sda_out),
        .sda_out_en (sda_out_en)
    );

    assign iic_sda = sda_out_en ? sda_out : 1'bz;
    assign sda_in = iic_sda;

    wire sda_tx_in     /*synthesis PAP_MARK_DEBUG="true"*/;
    wire sda_tx_out    /*synthesis PAP_MARK_DEBUG="true"*/;
    wire sda_tx_out_en /*synthesis PAP_MARK_DEBUG="true"*/;

    iic_dri #(
        .CLK_FRE    (27'd10_000_000),  // system clock frequency
        .IIC_FREQ   (20'd400_000),     // I2c clock frequency
        .T_WR       (10'd1),           // I2c transmit delay ms
        .ADDR_BYTE  (2'd2),            // I2C addr byte number
        .LEN_WIDTH  (8'd3),            // I2C transmit byte width
        .DATA_BYTE  (2'd1)             // I2C data byte number
    ) iic_dri_tx (
        .clk        (clk),
        .rstn       (rstn),
        .device_id  (device_id_tx),
        .pluse      (iic_trig_tx),     // I2C transmit trigger
        .w_r        (w_r_tx),          // I2C transmit direction 1:send 0:receive
        .byte_len   (4'd1),            // I2C transmit data byte length
        .addr       (addr_tx),         // I2C transmit addr
        .data_in    (data_in_tx),      // I2C send data
        .busy       (busy_tx),         // I2C bus status
        .byte_over  (byte_over_tx),    // I2C byte transmit over flag
        .data_out   (data_out_tx),     // I2C receive data
        .scl        (iic_tx_scl),
        .sda_in     (sda_tx_in),
        .sda_out    (sda_tx_out),
        .sda_out_en (sda_tx_out_en)
    );

    assign iic_tx_sda = sda_tx_out_en ? sda_tx_out : 1'bz;
    assign sda_tx_in = iic_tx_sda;

endmodule

该模块主要完成对 ms7210 和 ms7200 芯片的 IIC 配置。具体代码不详细分析,按照 IIC 协议去完成即可, 然后就是配置 ms7210 和 ms7200 的寄存器即可。以下给出 IIC 协议的时序说明,如下图所示:

当 SDA 和 SCL 都处于高电平时,表示空闲状态,因此在硬件设计时其实也要通过上拉电阻将信号拉高,表示 空闲。当 SCL 保持高电平时,SDA 拉低时表示 IIC 总线启动,标志一次数据传输的开始,在开始前,IIC 总线必须处 于空闲状态。在数据传输过程中,SDA 上逐位串行传输每一位数据,在 SCL 高电平期间,SDA 必须保持稳定。当 SCL 为低电平时,SDA 才允许改变。

IIC 总线每次传输一个字节,也就是传输 8 个 bit,每 8bit 后要收到一个来自接收方反馈的 ACK(应答信号), 该应答信号为高电平时,表示接收方接收字节失败。为低电平时,表示有效。之后,在 SCL 高电平期间,SDA 重新 拉高,则表示传输结束,IIC 总线回到空闲状态。

6. 实验现象

连接好 MES2L100HP 开发板、视频源和显示器;

注意视频源必须为 1920*1080P@60,下图为设置分辨率步骤,下载程序,可以看到显示器显示与视频源一致的图像。

上图为 FPGA 的 HDMI_OUT 输出的图像。

注意事项:

需要插上 HDMI 接口,板子上电时才会对 HDMI 芯片进行配置,否则将配置失败。

我们对 HDMI 芯片配置时使用的是 RGB888 协议,如果视频源的颜色格式不是 RGB888,会出现一些问题。 如上图,视频源的颜色格式是 YCbCr444,回环实验中,在显示器上显示视频源的画面,显示器上的画面颜色会偏绿。

相关推荐
九河云1 小时前
电商直播流量爆发式增长,华为云分布式流量治理与算力调度服务的应用场景剖析
分布式·科技·华为云·电商·传统
NfN-sh2 小时前
计数组合学7.12( RSK算法的一些推论)
笔记·学习·算法
农夫山泉(代码版)2 小时前
Linux驱动学习(七)平台总线框架
linux·服务器·学习
驱动起爆大师x_x2 小时前
STM32_Hal库学习SPI
stm32·嵌入式硬件·学习
小眼睛FPGA2 小时前
【盘古100Pro+开发板实验例程】FPGA学习 | 基于 UDP 的以太网传输实验例程
科技·单片机·学习·ai·fpga开发·fpga
pusue_the_sun2 小时前
从零开始搞定类与对象(中)
开发语言·c++·学习
cjie2212 小时前
Verilog与SytemVerilog差别
fpga开发
屁股割了还要学2 小时前
【数据结构入门】链表
c语言·开发语言·数据结构·c++·学习·算法·链表
Wendy14414 小时前
【目标检测基础】——yolo学习
学习·yolo·目标检测