FPGAからカラーバーとテキスト表示してみる
背景
FPGAボードで何かデモを実行したくなった。LEDをピカピカ程度ではつまらない。HDMI出力を試してみる。
構成
FPGA→FPGA内部SerDes→ボードのHDMI出力→ボードのHDMI端子→HDMIケーブル→液晶パネル
コード
`timescale 1ns / 1ns
module video_timing_ctrl #(
// 水平タイミングパラメータ
parameter video_hlength = 2200, // 水平ラインの総ピクセル数
parameter video_h_visible = 1920, // 水平表示領域のピクセル数
parameter video_hsync_pol = 1, // 水平同期信号の極性 (1: 正極性, 0: 負極性)
parameter video_hsync_len = 44, // 水平同期信号の長さ(ピクセル数)
parameter video_hbp_len = 148, // 水平バックポーチの長さ(ピクセル数)
// 垂直タイミングパラメータ
parameter video_vlength = 1125, // 垂直ラインの総行数
parameter video_v_visible = 1080, // 垂直表示領域の行数
parameter video_vsync_pol = 1, // 垂直同期信号の極性 (1: 正極性, 0: 負極性)
parameter video_vsync_len = 5, // 垂直同期信号の長さ(行数)
parameter video_vbp_len = 36, // 垂直バックポーチの長さ(行数)
// 外部同期位置パラメータ(オプション)
parameter sync_h_pos = 1079, // 外部同期時の水平位置
parameter sync_v_pos = 132 // 外部同期時の垂直位置
)(
input pixel_clock, // ピクセルクロック
input reset, // 同期リセット
input ext_sync, // 外部同期信号(オプション)
output [13:0] timing_h_pos, // 水平カウンターの現在位置
output [13:0] timing_v_pos, // 垂直カウンターの現在位置
output [13:0] pixel_x, // 有効ピクセルのX位置
output [13:0] pixel_y, // 有効ピクセルのY位置
output video_vsync, // 垂直同期信号
output video_hsync, // 水平同期信号
output video_den, // データ有効信号
output video_line_start// 行開始信号
);
// 水平タイミング計算
localparam T_HSYNC_END = video_hsync_len - 1;
localparam T_HVIS_BEGIN = video_hsync_len + video_hbp_len;
localparam T_HVIS_END = T_HVIS_BEGIN + video_h_visible - 1;
// 垂直タイミング計算
localparam T_VSYNC_END = video_vsync_len - 1;
localparam T_VVIS_BEGIN = video_vsync_len + video_vbp_len;
localparam T_VVIS_END = T_VVIS_BEGIN + video_v_visible - 1;
// 水平・垂直カウンタ
reg [13:0] h_counter = 14'd0;
reg [13:0] v_counter = 14'd0;
// 有効領域の判定
wire h_visible = (h_counter >= T_HVIS_BEGIN) && (h_counter <= T_HVIS_END);
wire v_visible = (v_counter >= T_VVIS_BEGIN) && (v_counter <= T_VVIS_END);
// 有効ピクセル位置の計算
assign pixel_x = h_visible ? (h_counter - T_HVIS_BEGIN) : 14'd0;
assign pixel_y = v_visible ? (v_counter - T_VVIS_BEGIN) : 14'd0;
// データ有効信号の生成
assign video_den = h_visible && v_visible;
// 行開始信号の生成
assign video_line_start = v_visible && (h_counter == 14'd0);
// 同期信号の生成
wire vsync_active = (v_counter <= T_VSYNC_END);
wire hsync_active = (h_counter <= T_HSYNC_END);
assign video_vsync = video_vsync_pol ? vsync_active : ~vsync_active;
assign video_hsync = video_hsync_pol ? hsync_active : ~hsync_active;
// 現在のタイミング位置の出力
assign timing_h_pos = h_counter;
assign timing_v_pos = v_counter;
// 外部同期信号の遅延レジスタ
reg ext_sync_last = 1'b0;
reg ext_sync_curr = 1'b0;
always @(posedge pixel_clock or posedge reset) begin
if (reset) begin
h_counter <= 14'd0;
v_counter <= 14'd0;
ext_sync_last <= 1'b0;
ext_sync_curr <= 1'b0;
end else begin
// 外部同期信号の遷移検出
if (ext_sync_curr && ~ext_sync_last) begin
h_counter <= sync_h_pos;
v_counter <= sync_v_pos;
end else begin
// 水平カウンタの更新
if (h_counter < video_hlength - 1) begin
h_counter <= h_counter + 1'b1;
end else begin
h_counter <= 14'd0;
// 垂直カウンタの更新
if (v_counter < video_vlength - 1) begin
v_counter <= v_counter + 1'b1;
end else begin
v_counter <= 14'd0;
end
end
end
// 外部同期信号の更新
ext_sync_last <= ext_sync_curr;
ext_sync_curr <= ext_sync;
end
end
endmodule
結果
実験用モニターで
所感
ChatGPT-o1miniでしたら、PythonやCだけでなく、Verilogだってエラーのないコードをガンガン書いてくれます。
もう人間の設計者は不要なのでしょうね。