特別版No.3のmax10生基板を活用する.

●プロンプト

 システムクロックの指示を忘れたので,後から追加で指示した.

FPGAデザインを設計して,Quartus Primer Lite用のプロジェクトを作る
# アプリケーション
2色マトリクスLEDのダイナミック点灯制御
## マトリクスLEDの信号
8ビットシフトレジスタ経由のColumn Green
8ビットシフトレジスタ経由のRow
8ビットシフトレジスタ経由のColumn Red
3つの信号のクロックは1つ(信号名:CLOCK)
## 表示内容
1秒ごとに異なる文字を表示する
表示するのは数字の0~9まで
# HDL
SystemVerilog
# 合成系
Quartus Prime lite
# デバイス
## FPGAチップ
max10
## LEDマトリクス
LTP-12188M-08 (https://akizukidenshi.com/goodsaffix/ltp12188m.pdf)
## シフトレジスタ
74HC595(https://toshiba.semicon-storage.com/info/TC74HC595AP_datasheet_ja_20140301.pdf?did=16501&prodName=TC74HC595AP)
## ベースボード
https://github.com/Lathe-Mariel/PCB_CQmax10
# 物理制約
信号は全て,3.3-V LVCMOS
信号名 | FPGA ピン | 内容
---|---|---
ROW | 98 | Row(Anode)
COL_GREEN | 101 | Column Green(Cathode Green)
COL_RED | 99 Column Red(Cathode Red)
CLR1 | 100 | Clear1(column green shift regster clear, active low)
CLR3 | 96 | Clear3(row shift regster clear, active low)
CLR2 | 105 | Clear2(column red shift regster clear, active low)
RCLOCK | 97 | R Clock(shift regster rck)
CLOCK | 106 | Clock(shift regster clock)
clk | 88 | System clock
rst_n | 17 | system reset_n
広げる

●生成されたRTLコード

 マトリクスLEDのLTP-12188M-08(Lite-On Technology Corporation)はRow側がアノードで,Column(赤・緑)側がカソードである.プロンプトで指示してあったが,Claudeはいつも通り,定数で入れ替えできるようなRTLコードを生成した.

●トップモジュール

 実機で動かしたところ数字が鏡像だったので,手動でコード修正し,行の表示順を入れ替えた.

`default_nettype none
// コメント省略

module top_matrix_led #(
    parameter int CLK_FREQ_HZ       = 50_000_000,              // system clk = 50 MHz
    parameter int SHIFT_HALF_PERIOD = 10,                      // sys-clk cycles per CLOCK/RCLOCK half-period
    parameter int ROW_HOLD_TICKS    = CLK_FREQ_HZ / 1000,      // ~1 kHz row switch -> ~125 Hz frame refresh
    parameter int DIGIT_HOLD_TICKS  = CLK_FREQ_HZ,             // 1 second per digit
    parameter int CLR_PULSE_TICKS   = 16,                      // width of the power-up /MR pulse
    parameter bit ROW_ACTIVE_HIGH   = 1'b1,                    // see assumption (2) above
    parameter bit COL_ACTIVE_LOW    = 1'b1                     // see assumption (2) above
	 )(
    input  logic clk,          // pin 88  : system clock
    input  logic rst_n,        // pin 17  : asynchronous reset, active low

    output logic ROW,          // pin 98  : row shift register serial data in
    output logic COL_GREEN,    // pin 101 : column-green shift register serial data in
    output logic COL_RED,      // pin 99  : column-red shift register serial data in

    output logic CLR1,         // pin 100 : column-green shift reg clear, active low
    output logic CLR3,         // pin 96  : row shift reg clear, active low
    output logic CLR2,         // pin 105 : column-red shift reg clear, active low

    output logic RCLOCK,       // pin 97  : storage register clock (latch, shared)
    output logic CLOCK         // pin 106 : shift register clock (shared)
);

    // ---------------------------------------------------
    // Reset synchronizer (async assert, sync de-assert)
    // ---------------------------------------------------
    logic [1:0] rst_sync;
    logic       rst_int_n;

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) rst_sync <= 2'b00;
        else        rst_sync <= {rst_sync[0], 1'b1};
    end
    assign rst_int_n = rst_sync[1];

    // --------------------------------------------------
    // 1-second digit counter: cycles 0 -> 9 -> 0 ...
    // --------------------------------------------------
    logic [25:0] sec_cnt;
    logic [3:0]  digit_idx;

    always_ff @(posedge clk or negedge rst_int_n) begin
        if (!rst_int_n) begin
            sec_cnt   <= 26'd0;
            digit_idx <= 4'd0;
        end else if (sec_cnt == DIGIT_HOLD_TICKS-1) begin
            sec_cnt   <= 26'd0;
            digit_idx <= (digit_idx == 4'd9) ? 4'd0 : digit_idx + 4'd1;
		      led <= !led;
        end else begin
            sec_cnt <= sec_cnt + 26'd1;
        end
    end

    // -------------------------------------------------
    // Font lookup for the row currently being scanned
    // -------------------------------------------------
    logic [2:0] row_idx;     // 0-7, which glyph row is being scanned right now
    logic [7:0] col_pattern; // 1 = pixel lit, bit7 = leftmost column

    font_rom u_font (
        .digit   (digit_idx),
        .row     (row_idx),
        .pattern (col_pattern)
    );

    // Even digit -> green, odd digit -> red (exercises both color channels)
    logic [7:0] row_sel_raw, colg_raw, colr_raw;
    always_comb begin
        row_sel_raw = 8'h80 >> row_idx;   // Row順反転のため手動で編集                    // one-hot: selects active row
        colg_raw    = digit_idx[0] ? 8'h00      : col_pattern;
        colr_raw    = digit_idx[0] ? col_pattern : 8'h00;
    end

    // Apply hardware polarity (see assumption 2)
    logic [7:0] row_pat, colg_pat, colr_pat;
    assign row_pat  = ROW_ACTIVE_HIGH ? row_sel_raw : ~row_sel_raw;
    assign colg_pat = COL_ACTIVE_LOW  ? ~colg_raw   :  colg_raw;
    assign colr_pat = COL_ACTIVE_LOW  ? ~colr_raw   :  colr_raw;

    // -----------------------------------------------
    // Scan / shift-out sequencer
    // -----------------------------------------------
    typedef enum logic [3:0] {
        ST_CLR,          // hold CLR1/CLR2/CLR3 low once after reset
        ST_LOAD,         // load row/col pattern for current row into shift regs
        ST_BIT_SETUP,    // drive data bit on ROW/COL_GREEN/COL_RED, CLOCK low
        ST_BIT_CLKHI,    // CLOCK high (rising edge shifts the bit into all 3 595's)
        ST_LATCH_SETUP,  // RCLOCK low, settle
        ST_LATCH_HI,     // RCLOCK high (rising edge latches all 3 storage regs)
        ST_LATCH_LO,     // RCLOCK back low
        ST_HOLD          // display current row for ROW_HOLD_TICKS, then next row
    } state_e;

    state_e      state;
    logic [7:0]  row_shift, colg_shift, colr_shift; // MSB-first shift-out registers
    logic [2:0]  bit_idx;                            // counts which of the 8 bits is being sent
    logic [25:0] timer;

    always_ff @(posedge clk or negedge rst_int_n) begin
        if (!rst_int_n) begin
            state      <= ST_CLR;
            row_idx    <= 3'd0;
            bit_idx    <= 3'd0;
            timer      <= 26'd0;
            row_shift  <= 8'h00;
            colg_shift <= 8'h00;
            colr_shift <= 8'h00;
            ROW        <= 1'b0;
            COL_GREEN  <= 1'b0;
            COL_RED    <= 1'b0;
            CLOCK      <= 1'b0;
            RCLOCK     <= 1'b0;
            CLR1       <= 1'b0;   // asserted (active-low) immediately at reset
            CLR2       <= 1'b0;
            CLR3       <= 1'b0;
        end else begin
            unique case (state)

                // ---- power-up clear pulse ----
                ST_CLR: begin
                    CLR1   <= 1'b1;
                    CLR2   <= 1'b1;
                    CLR3   <= 1'b1;
                    CLOCK  <= 1'b0;
                    RCLOCK <= 1'b0;
                    if (timer == CLR_PULSE_TICKS-1) begin
                        timer <= 26'd0;
                        CLR1  <= 1'b1;   // release clear (idle = high)
                        CLR2  <= 1'b1;
                        CLR3  <= 1'b1;
                        state <= ST_LOAD;
                    end else begin
                        timer <= timer + 26'd1;
                    end
                end

                // -- load next row's pattern into the shift-out regs --
                ST_LOAD: begin
					     if(timer == SHIFT_HALF_PERIOD-1)begin
                        row_shift  <= row_pat;
                        colg_shift <= colg_pat;
                        colr_shift <= colr_pat;
                        bit_idx    <= 3'd0;
                        timer      <= 26'd0;
                        CLOCK      <= 1'b0;
                        state      <= ST_BIT_SETUP;
			           end else begin
						      timer <= timer + 26'd1;
						  end
                end

                // -- present MSB of each shift-out reg, CLOCK low --
                ST_BIT_SETUP: begin
                    ROW       <= row_shift[7];
                    COL_GREEN <= colg_shift[7];
                    COL_RED   <= colr_shift[7];
                    CLOCK     <= 1'b0;
                    if (timer == SHIFT_HALF_PERIOD-1) begin
                        timer <= 26'd0;
                        state <= ST_BIT_CLKHI;
                    end else begin
                        timer <= timer + 26'd1;
                    end
                end

                // -- CLOCK high: rising edge shifts the bit in --
                ST_BIT_CLKHI: begin
                    CLOCK <= 1'b1;
                    if (timer == SHIFT_HALF_PERIOD-1) begin
                        timer      <= 26'd0;
                        row_shift  <= {row_shift[6:0],  1'b0};
                        colg_shift <= {colg_shift[6:0], 1'b0};
                        colr_shift <= {colr_shift[6:0], 1'b0};
                        if (bit_idx == 3'd7) begin
                            bit_idx <= 3'd0;
                            state   <= ST_LATCH_SETUP;
                        end else begin
                            bit_idx <= bit_idx + 3'd1;
                            state   <= ST_BIT_SETUP;
                        end
                    end else begin
                        timer <= timer + 26'd1;
                    end
                end

                // ---- RCLOCK low, settle ----
                ST_LATCH_SETUP: begin
                    CLOCK  <= 1'b0;
                    RCLOCK <= 1'b0;
                    if (timer == SHIFT_HALF_PERIOD-1) begin
                        timer <= 26'd0;
                        state <= ST_LATCH_HI;
                    end else begin
                        timer <= timer + 26'd1;
                    end
                end

                // ---- RCLOCK high: rising edge latches storage regs ----
                ST_LATCH_HI: begin
                    RCLOCK <= 1'b1;
                    if (timer == SHIFT_HALF_PERIOD-1) begin
                        timer <= 26'd0;
                        state <= ST_LATCH_LO;
                    end else begin
                        timer <= timer + 26'd1;
                    end
                end

                // ---- RCLOCK back low ----
                ST_LATCH_LO: begin

                    RCLOCK <= 1'b0;
                    if (timer == SHIFT_HALF_PERIOD-1) begin
                        timer <= 26'd0;
                        state <= ST_HOLD;
                    end else begin
                        timer <= timer + 26'd1;
                    end
                end

                // -- hold this row visible, then advance to next row --
                ST_HOLD: begin
                    if (timer == ROW_HOLD_TICKS-1) begin
                        timer   <= 26'd0;
                        row_idx <= row_idx + 3'd1;
                        state   <= ST_LOAD;
                    end else begin
                        timer <= timer + 26'd1;
                    end
                end

                default: state <= ST_CLR;
            endcase
        end
    end

endmodule
`default_nettype wire
広げる

●フォントROM

`default_nettype none

// コメント省略

module font_rom (
    input  logic [3:0] digit,    // 0-9 (values 10-15 are unused -> blank)
    input  logic [2:0] row,      // 0-7, top to bottom
    output logic [7:0] pattern
);

    always_comb begin
        unique case (digit)
            4'd0: begin
                unique case (row)
                    3'd0: pattern = 8'h3C;//00111100
                    3'd1: pattern = 8'h66;//01100110
                    3'd2: pattern = 8'h66;//01100110
                    3'd3: pattern = 8'h66;//01100110
                    3'd4: pattern = 8'h66;//01100110
                    3'd5: pattern = 8'h66;//01100110
                    3'd6: pattern = 8'h66;//01100110
                    3'd7: pattern = 8'h3C;//00111100
                    default: pattern = 8'h00;
                endcase
            end
            4'd1: begin
                unique case (row)
                    3'd0: pattern = 8'h18;//00011000
                    3'd1: pattern = 8'h38;//00111000
                    3'd2: pattern = 8'h18;//00011000
                    3'd3: pattern = 8'h18;//00011000
                    3'd4: pattern = 8'h18;//00011000
                    3'd5: pattern = 8'h18;//00011000
                    3'd6: pattern = 8'h18;//00011000
                    3'd7: pattern = 8'h3C;//00110100
                    default: pattern = 8'h00;
                endcase
            end
            4'd2: begin
                unique case (row)
                    3'd0: pattern = 8'h3C;
                    3'd1: pattern = 8'h66;
                    3'd2: pattern = 8'h06;
                    3'd3: pattern = 8'h0C;
                    3'd4: pattern = 8'h18;
                    3'd5: pattern = 8'h30;
                    3'd6: pattern = 8'h60;
                    3'd7: pattern = 8'h7E;
                    default: pattern = 8'h00;
                endcase
            end
            4'd3: begin
                unique case (row)
                    3'd0: pattern = 8'h3C;
                    3'd1: pattern = 8'h66;
                    3'd2: pattern = 8'h06;
                    3'd3: pattern = 8'h1C;
                    3'd4: pattern = 8'h06;
                    3'd5: pattern = 8'h06;
                    3'd6: pattern = 8'h66;
                    3'd7: pattern = 8'h3C;
                    default: pattern = 8'h00;
                endcase
            end
            4'd4: begin
                unique case (row)
                    3'd0: pattern = 8'h0C;
                    3'd1: pattern = 8'h1C;
                    3'd2: pattern = 8'h3C;
                    3'd3: pattern = 8'h6C;
                    3'd4: pattern = 8'h7E;
                    3'd5: pattern = 8'h0C;
                    3'd6: pattern = 8'h0C;
                    3'd7: pattern = 8'h0C;
                    default: pattern = 8'h00;
                endcase
            end
            4'd5: begin
                unique case (row)
                    3'd0: pattern = 8'h7E;
                    3'd1: pattern = 8'h60;
                    3'd2: pattern = 8'h60;
                    3'd3: pattern = 8'h7C;
                    3'd4: pattern = 8'h06;
                    3'd5: pattern = 8'h06;
                    3'd6: pattern = 8'h66;
                    3'd7: pattern = 8'h3C;
                    default: pattern = 8'h00;
                endcase
            end
            4'd6: begin
                unique case (row)
                    3'd0: pattern = 8'h1C;
                    3'd1: pattern = 8'h30;
                    3'd2: pattern = 8'h60;
                    3'd3: pattern = 8'h7C;
                    3'd4: pattern = 8'h66;
                    3'd5: pattern = 8'h66;
                    3'd6: pattern = 8'h66;
                    3'd7: pattern = 8'h3C;
                    default: pattern = 8'h00;
                endcase
            end
            4'd7: begin
                unique case (row)
                    3'd0: pattern = 8'h7E;
                    3'd1: pattern = 8'h06;
                    3'd2: pattern = 8'h0C;
                    3'd3: pattern = 8'h18;
                    3'd4: pattern = 8'h30;
                    3'd5: pattern = 8'h30;
                    3'd6: pattern = 8'h30;
                    3'd7: pattern = 8'h30;
                    default: pattern = 8'h00;
                endcase
            end
            4'd8: begin
                unique case (row)
                    3'd0: pattern = 8'h3C;
                    3'd1: pattern = 8'h66;
                    3'd2: pattern = 8'h66;
                    3'd3: pattern = 8'h3C;
                    3'd4: pattern = 8'h66;
                    3'd5: pattern = 8'h66;
                    3'd6: pattern = 8'h66;
                    3'd7: pattern = 8'h3C;
                    default: pattern = 8'h00;
                endcase
            end
            4'd9: begin
                unique case (row)
                    3'd0: pattern = 8'h3C;
                    3'd1: pattern = 8'h66;
                    3'd2: pattern = 8'h66;
                    3'd3: pattern = 8'h66;
                    3'd4: pattern = 8'h3E;
                    3'd5: pattern = 8'h06;
                    3'd6: pattern = 8'h0C;
                    3'd7: pattern = 8'h38;
                    default: pattern = 8'h00;
                endcase
            end
            default: pattern = 8'h00; // digits 10-15: blank (unused)
        endcase
    end

endmodule
`default_nettype wire
広げる

●動作確認

コメントを残す