見出し画像

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だってエラーのないコードをガンガン書いてくれます。
もう人間の設計者は不要なのでしょうね。

いいなと思ったら応援しよう!