根据PRX100T-D原理图和项目设计要求,我们设计了hdmi 图像显示项目的框图:
其中:
虚线中的是fpga内部逻辑,IN_CLK_50M 为板子上的时钟输入给FPGA;PB[7:1] 代表7个按键;HDMI_CLK 为fpga 输出的pixel 时钟(adv7511 视频输入时钟); IIC_SDA,IIC_SCL 为fpga 输出用来配置adv7511 寄存器; HDMI_HS,HDMI_VS,HDMI_D[23:0], HDMI_EN 有fpga 输出, 提供给adv7511 作为VESA视频格式信号。
FPGA主要分为几个主要的模块:
- pll:输入的时钟源50M 时钟, 产生50M 系统时钟; 产生VESA 标准所需要的148.5M 时钟(1920 x 1080 @60Hz)。
- key_filter: 使用148.5M 时钟, 将输入按键滤波,同时产生和148.5M时钟同步的单沿脉冲。
- rom: 存储莲花图像数据,之后会根据VESA 标准 ,将数据输出到adv7511 上。
- vga_driver: 产生VESA标准的1920 x 1080 @ 60Hz 所需要的h,v,de 信号。
- vga_show: 根据h,v,de等信号,平时输出莲花图像在屏幕中心,当有按键信号时, 根据按键信号的含义,将图像上下左右移动, 按OK 键 ,回到初始位置。
- iic_cfg: 用于配置adv7511 芯片, 包括adv7511 输入视频格式, 输出视频格式等。
设计需求:
- 要求使用100T开发板上的ADV7511进行图片显示;
- 显示区域分辨率为1920*1080,要显示的图片分辨率480 * 270pix;
- 要求图片显示在屏幕中央,可以通过按键进行上下移动, 按下中心按键可以返回中心;
项目顶层代码:
`timescale 1ns / 1ps
module hdmi_pic_show
(
input IN_CLK_50M,
input [7:1] PB,
output HDMI_CLK,
output HDMI_HS,
output HDMI_VS,
output HDMI_EN,
output [23:0] HDMI_D,
inout IIC_SDA,
inout IIC_SCL
);
//====================================
//pll
wire sys_clk_50m,vga_clk;
wire locked,sys_rst_n;
pll pll_inst
(
.clk_out1 (sys_clk_50m), // output clk_out1
.clk_out2 (vga_clk), // 148.5MHz
.reset (1'b0), // input reset
.locked (locked), // output locked
.clk_in1 (IN_CLK_50M)
); // input clk_in1
assign sys_rst_n = locked;
//=====================================
//key
wire center_flag;
wire up_flag;
wire down_flag;
wire left_flag;
wire right_flag;
key_filter #(
.DVI_CNT(148)
)
key_filter_inst(
.clk (vga_clk),
.rst_n (sys_rst_n),
.pb (PB),
.center_flag(center_flag),
.up_flag (up_flag),
.down_flag (down_flag),
.left_flag (left_flag),
.right_flag (right_flag)
);
//=================================
//vga_driver
wire h_sync;
wire v_sync;
wire hv_de;
vga_driver #(
.h_sync_pola (1),
.v_sync_pola (1)
)
vga_driver_inst(
.vga_clk (vga_clk),
.rst_n (sys_rst_n),
.h_sync (h_sync),
.v_sync (v_sync),
.hv_de (hv_de)
);
//=================================
//rom
wire [16:0] rd_rom_addr;
wire [23:0] rd_rom_data;
pic_rom pic_rom_inst (
.clka (vga_clk), // input wire clka
.addra (rd_rom_addr), // input wire [16 : 0] addra
.douta (rd_rom_data) // output wire [23 : 0] douta
);
//=================================
// i2c
iic_cfg iic_cfg_inst(
.clk (sys_clk_50m), //50m
.rst_n (sys_rst_n),
.iic_sda (IIC_SDA),
.iic_scl (IIC_SCL)
);
//================================
vga_show #(
.h_pix (1920),
.v_pix (1080)
)
vga_show_inst(
.vga_clk (vga_clk),
.rst_n (sys_rst_n),
.h_sync (h_sync),
.v_sync (v_sync),
.hv_de (hv_de),
.center_flag(center_flag),
.up_flag (up_flag),
.down_flag (down_flag),
.left_flag (left_flag),
.right_flag (right_flag),
.rd_rom_data(rd_rom_data),
.rd_rom_addr(rd_rom_addr),
.hdmi_hs (HDMI_HS),
.hdmi_vs (HDMI_VS),
.hdmi_en (HDMI_EN),
.hdmi_d (HDMI_D)
);
//assign HDMI_CLK = vga_clk;
ODDR #
(
.DDR_CLK_EDGE ("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE"
.INIT (1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE ("ASYNC") // Set/Reset type: "SYNC" or "ASYNC"
)
pclk_clk_out
(
.Q (HDMI_CLK), // 1-bit DDR output
.C (vga_clk),
.CE (1'b1), // 1-bit clock enable input
.D1 (1'b1), // 1-bit data input (positive edge)
.D2 (1'b0), // 1-bit data input (negative edge)
.R (1'b0), // 1-bit reset
.S (1'b0) // 1-bit set
);
endmodule
pll 产生的时钟vga_clk (148.5M)没有直接使用assign 输出到pin 上, 而是使用了xilinx 的原语ODDR,这样可以保证时钟比较稳定,不受片外负载的影响。相当于将ODDR 的D1, D2 的数据 输出到HDMI_CLK 上了。

