🥬Verilog视频信号图形显示 FPGA(iCE40)
iCE40 | FPGA | Verilog | VGA | Verilator | 视频信号 | FPGA游戏台 | FPGA驱动矩阵灯 | 光束追踪 | 媒体播放器
您需要一块带视频输出的 FPGA 板。 我们将在 640x480 下工作,几乎任何视频输出都可以在此像素工作。 它有助于轻松地对 FPGA 板进行编程并相当熟悉 Verilog。 如果您没有开发板,请不要担心,您可以使用 Verilator 模拟器。
材料
Lattice iCE40
即用型开发平台(Xilinx Artix-7)
视频板(Xilinx Artix-7)
使用 SDL(简单直接媒体层) 进行 Verilator 模拟
屏幕是一个微型宇宙,有自己的空间和时间。从远处看,屏幕显示出平滑的二维图像。 近距离观察,它会分解成许多单独的色块:红色、绿色和蓝色。 我们将这种复杂性隐藏在像素的抽象概念后面:我们可以控制的屏幕的最小部分。 典型的高清屏幕为 1920 x 1080:总共 200 万像素。 即使 640x480 的显示屏也有超过 300,000 个像素。屏幕每秒刷新多次,从而产生运动的错觉。 在 60 Hz 频率下,1920x1080 屏幕每秒绘制 1.24 亿像素! 快速处理大量数据的需求是在硬件级别处理图形的一大挑战。
显示连接器和布线各不相同,但 VGA、HDMI 和 DisplayPort 具有相似的数据设计。 颜色有三个通道,通常是红色、绿色和蓝色,以及水平和垂直同步信号。 可能还有音频和配置数据,但现在这并不重要。红、绿、蓝通道依次承载每个像素的颜色。当屏幕接收到水平同步和垂直同步上的新帧时,屏幕开始新的一行。同步信号是消隐间隔的一部分。
消隐间隔允许阴极射线管 (CRT) 中的电子枪移动到下一行(水平回扫)或屏幕顶部(垂直回扫)。 现代数字显示器保留了消隐间隔,并将其重新用于传输音频和其他数据。
驱动显示器
选择显示时序后,我们就可以创建视频信号了。有四个阶段:
像素时钟
显示信号
绘制图形
视频输出(VGA、HDMI、DisplayPort)
像素时钟
我们知道我们需要 25.2 MHz 的频率,但是如何达到它呢?
FPGA 包括锁相环 (PLL),用于生成自定义时钟频率。遗憾的是,并没有配置 PLL 的标准方法。我们需要特定于供应商的设计。
我已经为我们的板子提供了实施方案:
iCE40板子:
module clock_480p (
input wire logic clk_12m, // input clock (12 MHz)
input wire logic rst, // reset
output logic clk_pix, // pixel clock
output logic clk_pix_locked // pixel clock locked?
);
localparam FEEDBACK_PATH="SIMPLE";
localparam DIVR=4'b0000;
localparam DIVF=7'b1000010;
localparam DIVQ=3'b101;
localparam FILTER_RANGE=3'b001;
logic locked;
SB_PLL40_PAD #(
.FEEDBACK_PATH(FEEDBACK_PATH),
.DIVR(DIVR),
.DIVF(DIVF),
.DIVQ(DIVQ),
.FILTER_RANGE(FILTER_RANGE)
) SB_PLL40_PAD_inst (
.PACKAGEPIN(clk_12m),
.PLLOUTGLOBAL(clk_pix), // use global clock network
.RESETB(rst),
.BYPASS(1'b0),
.LOCK(locked)
);
endmodule
开发平台:
module clock_480p (
input wire logic clk_12m, // input clock (12 MHz)
input wire logic rst, // reset
output logic clk_pix, // pixel clock
output logic clk_pix_locked // pixel clock locked?
);
localparam FEEDBACK_PATH="SIMPLE";
localparam DIVR=4'b0000;
localparam DIVF=7'b1000010;
localparam DIVQ=3'b101;
localparam FILTER_RANGE=3'b001;
logic locked;
SB_PLL40_PAD #(
.FEEDBACK_PATH(FEEDBACK_PATH),
.DIVR(DIVR),
.DIVF(DIVF),
.DIVQ(DIVQ),
.FILTER_RANGE(FILTER_RANGE)
) SB_PLL40_PAD_inst (
.PACKAGEPIN(clk_12m),
.PLLOUTGLOBAL(clk_pix), // use global clock network
.RESETB(rst),
.BYPASS(1'b0),
.LOCK(locked)
);
endmodule
显示信号
我们可以从像素时钟和显示时序生成同步信号。我们还想报告当前的屏幕位置以了解何时绘制内容。
我们用一个简单的显示模块来完成这两件事:
module sim_480p (
input wire logic clk_pix,
input wire logic rst_pix,
output logic [9:0] sx,
output logic [9:0] sy,
output logic hsync,
output logic vsync,
output logic de
);
parameter HA_END = 639;
parameter HS_STA = HA_END + 16;
parameter HS_END = HS_STA + 96;
parameter LINE = 799;
parameter VA_END = 479;
parameter VS_STA = VA_END + 10;
parameter VS_END = VS_STA + 2;
parameter SCREEN = 524;
always_comb begin
hsync = ~(sx >= HS_STA && sx < HS_END);
vsync = ~(sy >= VS_STA && sy < VS_END);
de = (sx <= HA_END && sy <= VA_END);
end
always_ff @(posedge clk_pix) begin
if (sx == LINE) begin // last pixel on line?
sx <= 0;
sy <= (sy == SCREEN) ? 0 : sy + 1; // last line on screen?
end else begin
sx <= sx + 1;
end
if (rst_pix) begin
sx <= 0;
sy <= 0;
end
end
endmodule
测试台
绘制图形
视频输出
Verilator仿真
关联项目
驱动 32×32 RGB LED 矩阵
FPGA游戏台
VGA时钟
光束射线追踪器赛车
FPGA 媒体播放器
Last updated