シリアル通信で Hello, FPGA (4)

実用的な回路の設計・実装と動作確認を通じて,ハードウェア記述言語 (HDL) を使った FPGA 上のディジタル回路の設計について学ぶコースの第4回です。

前回までに、シリアル通信 (UART) による文字送信回路を設計し、論理シミュレーションを使って動作検証を行いました。今回はこの回路を FPGA に書き込んで、シリアル通信で PC に文字を送信します。

トップモジュールの作成

トップモジュールの設計

第2回で設計した文字送信回路は、他の回路から1文字のデータを受け取ってシリアル通信で送信する回路でした。そのため、文字送信回路にデータを渡す回路が別途必要です。今回はその回路を、回路同士の階層関係で一番上 (トップ) になる回路、すなわちトップモジュールとして設計していきましょう。

今回もまずは回路の外見、入出力から考えていきます。文字送信回路は順序回路でした。トップモジュールもステートマシンが必要なので、順序回路です。そのため、まずはクロック入力 (CLK) とリセット入力 (RST) が必要です。出力は文字送信回路から出力されるデータ出力 (すなわちシリアル通信の TXD) となります。今回必要な入出力は以上の3本だけです。

トップモジュールの回路構成。

回路の中身を考えましょう。今回は、前回のテストベンチと同様に、1文字の ‘A’ を出力させることにします。回路の構成をブロック図で表すと上図の通りとなります。文字送信回路のデータ入力は、今回も 0x41 で固定します。書き込み有効入力を ‘1’ とするかどうかは、ステートマシンによって判断します。

トップモジュールにおけるステートマシンの状態遷移図。

トップモジュールのステートマシンは、上の状態遷移図のように設計できます。必要な状態は、送信開始 (SEND)、送信終了待ち (WAIT)、送信終了済み (FIN) の3つです。SEND 状態からは必ず WAIT 状態に遷移します。WAIT 状態では、文字送信回路が送信を終了した (BUSY を ‘0’ にした) ことを確認してから、FIN 状態に遷移します。

補足: 本当は、1文字だけ送る分には、送信終了を待つ必要はありません。つまり、SEND 状態から FIN 状態にいきなり遷移してしまっても構いません。次回はこの回路を複数文字の送信ができるように拡張しますが、その時に説明がしやすいように、このような設計としています。

トップモジュールの SystemVerilog 記述

以上を踏まえて記述したトップモジュールの SystemVerilog 記述は以下のとおりです。

module serial_fpga (
    input  logic CLK, RST,
    output logic TXD);

    typedef enum {
        STATE_SEND,
        STATE_WAIT,
        STATE_FIN
    } state_type;
    state_type  state, n_state;
    logic       we;
    logic       busy;
    logic [7:0] data_in;

    serial_send # (
            .WAIT_DIV(868))
        ser (
            .CLK(CLK),
            .RST(RST),
            .DATA_IN(data_in),
            .WE(we),
            .DATA_OUT(TXD),
            .BUSY(busy));

    assign data_in = 8'h41;

    always_comb begin
        n_state = state;
        we      = 1'b0;
        if (state == STATE_SEND) begin
            n_state = STATE_WAIT;
            we      = 1'b1;
        end else if (state == STATE_WAIT) begin
            if (~ busy) begin
                n_state = STATE_FIN;
            end
        end
    end

    always_ff @ (posedge CLK) begin
        if (RST) begin
            state <= STATE_SEND;
        end else begin
            state <= n_state;
        end
    end
endmodule

文字送信回路を貼り付けているのが15~23行、ステートマシンが27~46行にあたります。新しい文法があるわけではないので解説は省略します。もし読んでいてピンと来ない部分があれば、前回までのコードの解説を参照してください。

制約ファイル (XDC) の作成

制約ファイルとは

これで、クロック入力 (CLK) とリセット入力 (RST) 、シリアル出力 (TXD) をもち、’A’ という文字を送信する回路が完成しました。しかし、FPGA でこの回路を動作させるにはもう1つ必要な作業があります。それは、HDL の中で定義した入出力と、実際の FPGA の入出力端子とを結びつける作業です。この関係を指定するのに使うファイルが、制約ファイルです。

Vivado では、制約ファイルは XDC (Xilinx Design Constraints) というフォーマットで記述されていて (中身は Tcl 言語のスクリプトです)、拡張子は .xdc です。制約ファイルは、特定の信号間のタイミングチェックを無効化したり、特定の論理素子を指定した場所に配置したりなどと、様々な機能をもちます。ただ、FPGA で回路を動作させるのであれば、最低限、入出力の結びつけとクロック入力の周波数の指定だけしておけば十分です。

制約ファイルの書き方と例

制約ファイルを書く場合、テンプレートが公開されていればそれを利用するのが簡単です。ACRi の FPGA 検証環境で利用できる Arty や PYNQ を製造している Digilent 社は、制約ファイルのテンプレートを公開しています。 Arty (Arty A7-35) 向けのテンプレートは GitHub で、PYNQ (PYNQ-Z1) 向けのテンプレートは Digilent 社の Web サイトで公開されています。これを参考に制約ファイルを書いていきます。今回は、Arty を使って検証します。そのため、Arty A7-35-Master.xdc (Arty-Master.xdc でも可) を使っていきます。

クロック入力とシリアル出力は、それぞれ発振器と USB-シリアル変換 LSI に接続されているピンを指定します。クロック入力は、Clock Signal とコメントのある次の行から2行分をコピーペーストし、コメントを外し (先頭の # を削除し)、get_ports の後の信号名を適切に修正します (今回は CLK)。この2行で、クロック入力に対応する FPGA の端子が E3 ピンであることと、その周波数が 100 MHz (周期が 10 ns) であることを指定しています。

シリアル出力については、USB-UART Interface の周辺を見ます。信号名の uart_rxd_out, uart_txd_in は PC 側から見た「受信」「送信」で名前付けしている点に注意してください (この辺りは第2回でも説明しました) 。つまり、uart_rxd_out が FPGA から見たときの「送信」です。この行をコピーペーストし、クロック入力と同様に修正します。

リセット入力は、今回は便宜的にボード上の押しボタン0番を使おうと思います。Buttons の下、btn[0] と名前のついている行をコピーペーストして修正します。

出来上がった制約ファイルは以下のとおりです。このファイルに .xdc という拡張子をつけて保存し、プロジェクトに Constraint(s) として追加します。

set_property -dict { PACKAGE_PIN E3    IOSTANDARD LVCMOS33 } [get_ports { CLK }];
create_clock -add -name sys_clk_pin -period 10.00 [get_ports { CLK }];
set_property -dict { PACKAGE_PIN D9    IOSTANDARD LVCMOS33 } [get_ports { RST }];
set_property -dict { PACKAGE_PIN D10    IOSTANDARD LVCMOS33 } [get_ports { TXD }];

PC での出力の確認

論理合成と FPGA への書き込み

これで準備が整いました。論理合成と FPGA への書き込み,動作確認を行っていきます。詳しい方法についてはコース 20Q1.09A の記事を参照してください。

トップモジュールと文字送信回路を Design Source(s) として、制約ファイルを Constraint(s) として、それぞれソースとして追加したプロジェクトを用意し、論理合成 (Run Synthesis) からプログラミングファイルの作成 (Generate Bitstream) までの一連の処理を行います。Hardware Manager を開き、ボードと接続し、Program Device で作成したプログラミングファイルを FPGA に書き込みます。

Tera Term を用いた出力の確認 (Windows 向け)

Windows でシリアル通信を行う場合は、Tera Term がよく利用されます。ここでは、Windows 向けに Tera Term を用いた出力の確認方法を説明します。Linux を使っている場合は次の項に進んでください。

Tera term の新規接続画面。

Tera Term をまだインストールしていない場合は、Tera Term のススメ を参考にダウンロード・インストールします。メニューの「ファイル → 新しい接続」を選択し、シリアルを選択し、「USB Serial Port (COM●)」と書かれたポートを指定します。●の部分は環境に依存します。また、1枚のボードから2種類のポートが検出されるかもしれませんが、多くの場合、番号の大きい方のポートを選ぶとうまく行きます (番号の小さい方は FPGA への書き込みに使っているようです)。

Tera Term のシリアルポート設定画面。

次に、シリアル通信の通信速度などの設定を行います。スピードは 115200 に設定し、データとストップビットをそれぞれ 8 bit と 1 bit に設定します (第2回の取り決め通り)。パリティ・フロー制御は使わないので、none に設定します。設定を確認し、「現在の接続を再設定」ボタンを押すと、設定が更新されます。

Tera Term を使い、FPGAから ‘A’ を受信した様子。

この状態で FPGA に改めて回路を書き込む (手元にボードがある場合はリセットボタン……BTN0 を押しても構いません) と、Tera Term の画面に A と表示されます。

もし表示されない場合は、ポートの設定などが正しいか、FPGA に回路を正しく書き込めているかを改めて確認してください。手元にボードがある場合は、Tera Term 上で適当にキーボードから文字を入力し、シリアル受信の LED (Arty なら LD10) が光るかどうかを確かめてください。

GTKTerm を用いた出力の確認 (Linux 向け)

次に、Linux 向けに GTKTerm を用いた出力の確認方法を説明します。GTKTerm をまだインストールしていない場合には、パッケージから探す、ソースコードからビルドするなどの方法でインストールします。Ubuntu の場合は、(sudo を使う権限があれば) $ sudo apt install gtkterm で済みます。

あらかじめ、FPGA のシリアル通信のポートを確認しておきます。$ dmesg | grep ttyUSB とコマンドを打ち込むと、「FTDI USB Serial Device converter now attached to ttyUSB●」と書かれた行が見つかるはずです。●の部分は環境に依存します。 また、1枚のボードから2種類のポートが検出されるかもしれませんが、多くの場合、番号の大きい方のポートを選ぶとうまく行きます (番号の小さい方は FPGA への書き込みに使っているようです)。このポート番号を覚えておきます。

GTKTerm のシリアルポート設定画面。

$ gtkterm & とコマンドを打ち込み、GTKTerm を起動します。メニューの「Configuration → Port」から、シリアル通信のポートや通信速度などの設定を行います。Port は先ほど調べたポート番号、Baud Rate は 115200 に設定し、データ (Bits) とストップビット (Stopbits) をそれぞれ 8 と 1 に設定します (第2回の取り決め通り)。Parity と Flow control は使わないので、none に設定します。

※ 権限がないと言われた場合は、/dev/ttyUSB● への書き込み権限を加えるか、あるいは GTKTerm を sudo で実行する必要があります。

GTKTerm を使い、FPGA から ‘A’ を受信した様子。

この状態で FPGA に改めて回路を書き込む (手元にボードがある場合はリセットボタン……BTN0 を押しても構いません) と、GTKTerm の画面に A と表示されます。

もし表示されない場合は、ポートの設定などが正しいか、FPGA に回路を正しく書き込めているかを改めて確認してください。手元にボードがある場合は、GTKTerm 上で適当にキーボードから文字を入力し、シリアル受信の LED (Arty なら LD10) が光るかどうかを確かめてください。

まとめ

今回は、FPGA の実機で PC とのシリアル通信を行うために、文字送信回路を組み入れたトップモジュールの設計、制約ファイルの作成、論理合成と FPGA への書き込み、PC の端末エミュレータによる出力の確認を、順に行っていきました。

最終回ではこの連載の最終目標である「シリアル通信で Hello, FPGA」を FPGA からPC に送信し、その結果を確認していくことにしましょう。

愛知工業大学 藤枝直輝

タイトルとURLをコピーしました