ボード:Tang Primer 25K

サウンドモジュール:PMOD-AUDIO V1.2(muse lab)

サウンドモジュールのスピーカを使ったモノラル出力としたので,FPGAからPMODモジュールへの信号は1本のみを利用

単純なPWMで音階を表現しただけのメロディプレーヤを作成する.

Claudeの生成したメロディは,よく分からないものだったので,手動で修正した.

●プロンプト

FPGAデザインを作る

# Application
インテル入っているCMの効果音を鳴らす

# Hardware
## FPGA Board
Tang Primer 25K

### System Clock
50MHz

## Speaker
PMOD-AUDIO-v1.2
(https://github.com/wuxx/icesugar/blob/master/schematic/pmod-audio-v1.2.pdf)
(https://github.com/wuxx/icesugar/blob/master/src/basic/verilog/music4/music.v)

# HDL
SystemVerilog

# Physical constraint file
Port1 | G11 | Input_L    // スピーカ側はG10だったので生成コードを手動で修正
Port2 | D11 | none
Port3 | B11 | none
Port4 | C11 | none
Port5 | G10 | none
Port6 | D10 | none
Port7 | B10 | none
Port8 | C10 | none
Expand

●生成コード

・トップモジュール

module top (
    input  logic clk,          // 50 MHz system clock (core-board oscillator, pin E2)
    output logic pmod_audio    // PMOD-AUDIO "IL" input (Port1 / G11)
);

    logic rst;

    // Power-on reset generator (synchronous, self-clearing)
    por_reset u_por (
        .clk (clk),
        .rst (rst)
    );

    // Note sequencer + square-wave tone generator
    jingle_player u_jingle (
        .clk   (clk),
        .rst   (rst),
        .audio (pmod_audio)
    );

endmodule
広げる

・音源・シーケンサモジュール

// 省略

module jingle_player #(
    parameter int CLK_HZ = 50_000_000
) (
    input  logic clk,
    input  logic rst,
    output logic audio
);

    // ------------
    // Step table (5 tones + trailing rest/gap before the loop repeats)
    //
    //  step | note            | freq (Hz) | half-period (cyc @50MHz) | dur (ms)
    //   0   | F#         |  739.989   | 33784               |  600
    //   1   | C#         |  554.365   | 45096               |  200
    //   2   | F#         |  739.989   | 33784               |  200
    //   3   | C#         |  554.365   | 45096               |  200
    //   4   | G#         |  830.609   | 30098               |  200
    //   5   | (rest / gap)  |    --   |      0              | 2000
    // ------------
    localparam int NUM_STEPS = 7;

    logic [2:0]  step;
    logic [17:0] half_period;
    logic [26:0] duration_cyc;

    always_comb begin
        unique case (step)
            3'd0: begin half_period = 18'd67568; duration_cyc = 27'd10_000_000; end // 600ms
            3'd1: begin half_period = 18'd0;     duration_cyc = 27'd20_000_000; end //
            3'd2: begin half_period = 18'd90193; duration_cyc = 27'd10_000_000; end // 200ms
            3'd3: begin half_period = 18'd67568; duration_cyc = 27'd10_000_000; end // 200ms
            3'd4: begin half_period = 18'd90193; duration_cyc = 27'd10_000_000; end // 200ms
            3'd5: begin half_period = 18'd60196; duration_cyc = 27'd15_000_000; end //
            default: begin half_period = 18'd0;  duration_cyc = 27'd200_000_000; end // 3000ms rest
        endcase
    end

    // -----------------------
    // Step/duration sequencer
    // -----------------------
    logic [26:0] dur_cnt;
    logic        step_done;

    assign step_done = (dur_cnt == duration_cyc - 27'd1);

    always_ff @(posedge clk) begin
        if (rst) begin
            dur_cnt <= '0;
            step    <= '0;
        end else if (step_done) begin
            dur_cnt <= '0;
            step    <= (step == NUM_STEPS - 1) ? 3'd0 : step + 3'd1;
        end else begin
            dur_cnt <= dur_cnt + 27'd1;
        end
    end

    // --------------------------
    // Square-wave tone generator
    // --------------------------
    logic [17:0] tone_cnt;
    logic        tone_bit;
    logic        note_active;

    assign note_active = (half_period != 18'd0);

    always_ff @(posedge clk) begin
        if (rst) begin
            tone_cnt <= '0;
            tone_bit <= 1'b0;
        end else if (!note_active) begin
            tone_cnt <= '0;
            tone_bit <= 1'b0;  // silence during the rest step
        end else if (tone_cnt == half_period - 18'd1) begin
            tone_cnt <= '0;
            tone_bit <= ~tone_bit;
        end else begin
            tone_cnt <= tone_cnt + 18'd1;
        end
    end

    assign audio = tone_bit;

endmodule
広げる

・リセット

module por_reset #(
    parameter int WIDTH = 6            // 64 clk cycles of reset after config
) (
    input  logic clk,
    output logic rst
);

    logic [WIDTH-1:0] cnt = '0;

    always_ff @(posedge clk) begin
        if (!(&cnt))
            cnt <= cnt + 1'b1;
    end

    assign rst = ~(&cnt);

endmodule
広げる

コメントを残す