UART通信におけるRS232送信モジュールの実装

UART送信モジュールの設計概要

UART通信の送信モジュールをVerilog HDLで実装する際の主要な構成要素:

/*
標準的なボーレート設定:
4800, 9600, 14400, 115200 bps
50MHzシステムクロック時のカウント値:
(1/4800)  * 10^9 /20 -1 = 10416
(1/9600)  * 10^9 /20 -1 = 5207
(1/14400) * 10^9 /20 -1 = 3471
(1/115200)* 10^9 /20 -1 = 433
*/

module uart_transmitter
(
    input   [16:0]  baud_rate       ,
    input           clock           ,
    input           reset           ,
    input   [7:0]   data_in         ,
    input           transmit_enable ,
    
    output  reg     serial_out      ,
    output  reg     transfer_complete    
);

主要機能ブロックの実装

ボーレートカウンタ設定

    reg [15:0]      max_baud_count;
    
    always @(posedge clock) begin
        case(baud_rate)
            17'd4800   : max_baud_count <= 16'd10416;
            17'd9600   : max_baud_count <= 16'd5207;
            17'd14400  : max_baud_count <= 16'd3471;
            17'd115200 : max_baud_count <= 16'd433;
            default    : max_baud_count <= 16'd5207; // デフォルト9600bps
        endcase
    end

データ転送制御

    reg [3:0] bit_position;
    reg [15:0] baud_counter;
    reg counter_enable;
    
    // ボーレートカウンタ制御
    always @(posedge clock or negedge reset) begin
        if(!reset) begin
            baud_counter <= 16'd0;
            counter_enable <= 1'b0;
        end
        else if(!counter_enable)
            baud_counter <= 16'd0;
        else if(baud_counter == max_baud_count)
            baud_counter <= 16'd0;
        else
            baud_counter <= baud_counter + 1'b1;
    end

シリアルデータ出力

    always @(posedge clock or negedge reset) begin
        if(!reset)
            serial_out <= 1'b1;
        else if(!counter_enable)
            serial_out <= 1'b1;
        else if(baud_counter == 16'd1) begin
            case(bit_position)
                4'd0: serial_out <= 1'b0;  // スタートビット
                4'd1: serial_out <= data_buffer[0];
                // ... データビット2-8
                4'd9: serial_out <= 1'b1;  // ストップビット
                default: serial_out <= 1'b1;
            endcase
        end
    end

テストベンチ例

module uart_tx_test;

    reg [16:0] baud_set = 17'd9600;
    reg clk = 1'b1;
    reg rst_n = 1'b0;
    reg [7:0] test_data;
    reg start_signal;
    
    initial begin
        forever #10 clk = ~clk;
        
        #21 rst_n = 1'b1;
        #40;
        
        // テストデータ送信
        for(integer i=0; i<8; i=i+1) begin
            @(posedge clk);
            test_data = i;
            start_signal = 1'b1;
            #20 start_signal = 1'b0;
            #(5208 * 20 * 10); // 1フレーム分待機
        end
        $stop;
    end
    
    uart_transmitter DUT (
        .baud_rate(baud_set),
        .clock(clk),
        .reset(rst_n),
        .data_in(test_data),
        .transmit_enable(start_signal),
        .serial_out(tx),
        .transfer_complete(done)
    );

endmodule

シミュレーション波形では、シリアル出力線が初期状態でHIGHになり、スタートビットでLOWに変化することを確認できます。

タグ: UART RS232 Verilog FPGA シリアル通信

7月30日 22:39 投稿