FPGA ボードを遠隔操作! SawareruSys を ACRi ルームで使う (2)

ACRi ルームでも利用できるようになった、ディジタル回路・FPGA の「さわれる」遠隔学習システム SawareruSys について解説するコースの後半の記事です。この記事では、ACRi のイベントなどでコントローラボードを入手された方、あるいはこれから入手する予定の方向けに、SawareruSys の基本的な利用手順を説明します。

この記事の内容は、2024年8月に開催された 組込み技術に関するサマーワークショップ SWEST26における、SWEST/ACRi 共同企画セッションの中で行った、SawareruSys の利用体験会の資料をもとにしています。貴重な機会をご提供いただきました SWEST 実行委員会の皆様に、改めて感謝申し上げます。

まずは準備から

本記事は、すでに ACRi ルームの登録を済ませており、FPGA ボードが接続されたサーバ (vs サーバ) の予約や、リモートデスクトップでの vs サーバ上の Vivado の起動を経験したことがある方に向けて書かれています。もしもまだ登録していない、または vs サーバで Vivado を起動したことがないようでしたら、上記リンクやその先にある利用説明ページを参考に、まずはアカウントを登録し、基本的なサーバの使い方をご体験ください。

また、ACRi のイベントで配布する SawareruSys のコントローラボード (SawareruBoard) は、USB Type-C で利用者の PC と接続します。USB Type-C の接続ケーブルは、各自でご準備ください。

SawareruSys の配布パッケージは、GitHub リポジトリのトップページからリンクされています。この記事の公開時点では Windows にのみ対応しています (他 OS への対応は準備中です)。ページ内の「配布パッケージのダウンロード」と書かれた場所にある zip ファイルへのリンクからダウンロードし、適当な日本語を含まないパス上に展開してください。また、以後の作業では作業用フォルダが1つ必要です。作業用フォルダも、フォルダ名そのものを含めて、日本語を含まないパス上に作成してください。

最後の準備として、この記事で論理合成して動作確認を行う回路の SystemVerilog 記述の中身を、すぐにコピーペーストできる状態にしておきます。記述は テキストファイル でもダウンロードできるようにしていますが、以下からコピーペーストしても構いません。

    localparam LED_DIV = 26'd50000000; // LED の点滅間隔: 500 ms
    localparam SEG_DIV =  21'd3000000; // セグメントの移動間隔: 30 ms(SPD = 0)
    localparam SEG_PTN =        4'd12; // セグメントのアニメーションパターン数

    logic [25:0] wait_led, n_wait_led;
    logic        n_led;
    logic [20:0] wait_seg, n_wait_seg;
    logic [ 3:0] cnt_seg,  n_cnt_seg;
    logic [ 3:0] pos_seg,  n_pos_seg;
    logic        pos_seg_we;

    // LED の点滅制御
    always_comb begin
        n_wait_led = wait_led + 1'b1;
        n_led      = LED;

        if (wait_led == LED_DIV - 1) begin // カウントし終わったら
            n_wait_led = 0;
            n_led      = ~ LED;           // LED を反転
        end
    end

    always_ff @ (posedge CLK) begin
        if (RST) begin
            wait_led <= 0;
            LED      <= 1'b0;
        end else begin
            wait_led <= n_wait_led;
            LED      <= n_led;
        end
    end

    // 7 セグの点灯制御
    always_comb begin // 時間管理
        n_wait_seg = wait_seg + 1'b1;
        n_cnt_seg  = cnt_seg;
        pos_seg_we = 1'b0;

        if (wait_seg == SEG_DIV - 1) begin
            n_wait_seg = 0;
            if (cnt_seg >= SPD) begin      // カウントし終わったら
                n_cnt_seg  = 4'd0;
                pos_seg_we = 1'b1;        // pos_seg の書き込みフラグを 1 に
            end else begin
                n_cnt_seg  = cnt_seg + 1'b1;
            end
        end
    end

    always_comb begin // 次(時間経過後)のカウンタの値 n_pos_seg
        if (REV) begin
            if (pos_seg == 4'd0) begin
                n_pos_seg = SEG_PTN - 1'b1;
            end else begin
                n_pos_seg = pos_seg - 1'b1;
            end
        end else begin
            if (pos_seg == SEG_PTN - 1'b1) begin
                n_pos_seg = 4'd0;
            end else begin
                n_pos_seg = pos_seg + 1'b1;
            end
        end
    end

    always_ff @ (posedge CLK) begin
        if (RST) begin
            wait_seg <= 0;
            cnt_seg  <= 4'd0;
            pos_seg  <= 4'd0;
        end else begin
            wait_seg <= n_wait_seg;
            cnt_seg  <= n_cnt_seg;
            if (pos_seg_we) begin
                pos_seg  <= n_pos_seg;
            end
        end
    end

    // 7セグの点灯パターン(負論理)
    always_comb begin
        case (pos_seg)                         // gfedcba
            4'd0   : begin AN = 4'b0111; SEG = 7'b1111110; end
            4'd1   : begin AN = 4'b1011; SEG = 7'b1111110; end
            4'd2   : begin AN = 4'b1101; SEG = 7'b1111110; end
            4'd3   : begin AN = 4'b1110; SEG = 7'b1111110; end
            4'd4   : begin AN = 4'b1110; SEG = 7'b1111101; end
            4'd5   : begin AN = 4'b1110; SEG = 7'b1111011; end
            4'd6   : begin AN = 4'b1110; SEG = 7'b1110111; end
            4'd7   : begin AN = 4'b1101; SEG = 7'b1110111; end
            4'd8   : begin AN = 4'b1011; SEG = 7'b1110111; end
            4'd9   : begin AN = 4'b0111; SEG = 7'b1110111; end
            4'd10  : begin AN = 4'b0111; SEG = 7'b1101111; end
            4'd11  : begin AN = 4'b0111; SEG = 7'b1011111; end
            default: begin AN = 4'b1111; SEG = 7'b1111111; end
        endcase
        if (~ wait_seg[16]) begin // 明るさ調整(50%)
            AN = 4'b1111;
        end
    end

主に各自の PC 上で行う作業

回路の用意

SawareruSys で行う作業は、各自の PC 上で行う作業と、ACRi ルームのサーバ上のリモートデスクトップで行う作業とに分かれています。そのうち前半の作業はほとんどが各自の PC 上での、後半の作業はほとんどがリモートデスクトップ上での作業です。

各自の PC 上で行う作業を始めるには、開発フロントエンドの DRFront を起動します。配布パッケージの DRFront\DRFront.exe にあります。下図に示す画面が表示されますので、まずは右下の Setting ボタンを押して、設定画面を開きます。

DRFront の起動画面

下図に示す設定画面では、対象とする FPGA ボードや HDL の種類を選択できます。PC に Vivado をインストールしている場合には、インストール先のフォルダや、使用するバージョンを指定することもできます。

DRFront の設定画面

対象とする FPGA ボード (Target Board) は、どの vs サーバを予約したかによって異なります。2024年11月時点では、vs001 ~ vs710 には Atry A7-35T が、vs801 ~ vs810 には CMod A7-35T が、vs901 ~ vs910 には Nexys A7-100T が、それぞれ接続されています。自分の予約した vs サーバに対応するボードを選んでください。使用する HDL の種類は、SystemVerilog に設定します。設定が終わったら、OK ボタンを押して設定画面を閉じます。

次に、入力と出力を DRFront の画面上で指定することで、この記事で動作確認する回路のひな型を作成します。先ほどの Setting ボタンの1つ下、HDL Template ボタンを押すと、ひな型作成のためのウィンドウが開きます。

この記事で動作確認する回路には、下表に示す7つの入出力があります。

信号名方向ビット幅
CLKin (入力)1
RSTin (入力)1
REVin (入力)1
SPDin (入力)4
LEDout (出力)1
ANout (出力)4
SEGout (出力)7

ひな型作成のためのウィンドウでは、まず Entity/Module Name 欄に適当な回路名 (ここでは seg_loop とします) を入力し、Add ボタンを6回押します。画面上の表の信号名 (Name)、方向 (Direction)、ビット幅 (Width) を、上に示した表と一致するように設定します。設定が済んだ時点での画面の様子を下図に示します。

HDL のひな型を生成する画面の入力例

入力が完了したら、Save HDL File ボタンを押し、作業用フォルダに適当な名前をつけて保存します。ただし、不測のトラブルを避けるため、名前には日本語や _ 以外の記号を含めないことをおすすめします。これ以降も同様です。ここではファイル名を seg_loop.sv とします。

保存したひな型のコード全文の例を以下に示します。入出力は定義されましたが、中身のない状態です。

// NOTE: Template was generated by DRFront automatically.

module seg_loop (
    input logic CLK,
    input logic RST,
    input logic REV,
    input logic [3:0] SPD,
    output logic LED,
    output logic [3:0] AN,
    output logic [6:0] SEG
);


endmodule

保存した SystemVerilog のファイルを適当なテキストエディタで開き、準備段階で用意した回路の中身の記述をコピーしたら、このファイルの ); から endmodule の間の空行のところにペーストします。その後、忘れずにそのファイルを保存します。

入出力の割当て

これで回路記述が用意できましたので、入出力の割当てを行い、Vivado での作業で必要なファイルの準備を行います。DRFront の最上段、Source Dir. と書かれたテキストボックスの横にある … ボタンをクリックすると、ソース一式のあるフォルダを選択するダイアログが現れます。先ほど SystemVerilog のファイルを保存した、作業フォルダを選択します。その後、2段目右の Create Project ボタンを押すと、Vivado プロジェクトのためのフォルダが作成されます。このときの DRFront の画面の様子を下図に示します。3段目の Top Module の欄で、先ほど用意した seg_loop がトップモジュールとして検出されているはずです。

ソースフォルダのパス指定とプロジェクトの作成が済んだ様子

入出力を割当てるには3つの方法があります。1つ目は、各信号の横の Assign to と書かれた列で、プルダウンで割当てる方法です。2つ目は、信号名をドラッグして、ボード画像内の割当てたい部品にドロップする方法です。3つ目は、自動割当てを使う方法です。2つ目の方法がおすすめです。

割当てを行いたい信号の行をクリックすると、濃い青色の選択状態になります。その状態で、マウスをドラッグしてボード画像上の割当てたい部品のところへと移動させます。枠が水色で表示されれば、割当て完了です。枠が赤色で表示された場合には、重複した割当てがありますので、確認してください。

この記事で動作確認する回路 seg_loop では、7セグメント LED のアノード (AN)、クロック (CLK)、LED 出力 (LED)、プッシュスイッチ (REV)、リセット (RST)、7セグメント LED のカソード (SEG)、スライドスイッチ (SPD) を、FPGA ボード上の入出力へ、下図に示すとおりに割当てます。本来7セグメント LED は Nexys A7-100T にしか搭載されていないのですが、SawareruSys では仮想的に利用できるようになっています。仮想的に利用できる部品は、(Nexys 以外の) ボード画像の右側にある、Virtual 7-seg と書かれた領域に置かれています。

入出力の割当ての一覧

入出力の割当てが終わったら、DRFront の最下段にある4つのボタンのうち1番左にある、「Create/Update Files」ボタンを押します。ここまでの作業が終わると、作業用フォルダには以下のファイルとフォルダが生成されています。

  • seg_loop.sv: ひな型に追記して作成した、回路記述本体
  • project_1: Vivado プロジェクト用のフォルダ
    • logs: Vivado のログの保存先 (DRFront から Vivado を起動した場合)
    • dr_top.sv: 入出力割当てをもとに作成したラッパ回路
    • dr_testbench.sv: テストベンチのひな型
    • OpenProject.tcl: Vivado でプロジェクトを作成/開くときに使うスクリプト
    • GenerateBitstream.tcl: Vivado でマッピング~ビットストリームの生成の一連の手順を行うときに使うスクリプト
    • OpenHW.tcl: Vivado で Hardware Manager を開くときに使うスクリプト

ここまでの作業が済んだら、作業用フォルダ全体を ACRi ルームのサーバにアップロードします。また、SawareruSys の配布パッケージにある、サーバ用のコネクタアプリのスクリプト Connector\server\connector_serv.py もアップロードしておきます。ここから先の手順は、(PC に Vivado がインストールされていない限り) ACRi ルームのサーバにリモートデスクトップでログインして行うことになります。

主にリモートデスクトップ上で行う作業

リモートデスクトップで ACRi ルームのサーバに接続する方法は、1点を除いて通常の場合と変わりません。異なるのは、ssh コマンドで接続するときに、通常のリモートデスクトップ接続に必要な設定 (-L 13389:<サーバ名>:3389) に加えて、コントローラボードの接続に必要な設定 (-L 13399:<サーバ名>:3399) が必要なことです。したがって、SSH 接続時に入力するコマンドは以下のようになります。

ssh -L 13389:<サーバ名>:3389 -L 13399:<サーバ名>:3399 <ユーザ名>@gw.acri.c.titech.ac.jp

ただし、<サーバ名> は予約したサーバ名 (vs + 3桁の数字)、<ユーザ名>は各自の ACRi ルームのユーザ名 (u_ で始まるもの) に置き換えてください。

Vivado による論理合成・配置配線

SSH 接続が確立したら、通常通りの手順でリモートデスクトップに接続し、 Vivado を起動します。Vivado が起動した後は、通常はプロジェクトを作成したり開いたりするところですが、ここではメニューの Tools → Run Tcl Script を選択します。

Run Tcl Script から各種操作を始めようとしている様子

どのスクリプトを実行するかを尋ねられますので、先ほどアップロードした作業用フォルダの下、project_1 フォルダの中にある OpenProject.tcl を選択します。すると、まだプロジェクトが作成されていない場合は新規作成され、作成されている場合は既存のプロジェクトが開かれます。正しくプロジェクトが作成できている場合、Sources タブで確認できる回路の階層構造は、ラッパ回路 DR_TOP → 記述した seg_loop という形になっているはずです。

回路の階層構造。記述した seg_loop は、ラッパ回路 DR_TOP の直下に存在する

Vivado の画面左側にある Flow Navigator より、SYNTHESIS → Run Synthesis を選び、論理合成を実行します。論理合成に成功したら、Open Synthesized Design を選択して OK を押し、その結果を開きます。

チェックポイントを保存しようとしているときの様子

画面右側が SYNTHESIZED DESIGN に切り替わったら、メニューの File → Checkpoint → Write で、論理合成結果をチェックポイントとして保存します。このとき、ファイル名を尋ねられますが、変更せずに OK を押してください。そうすることで、続くスクリプトで最新のチェックポイントが自動的に検出されます。

チェックポイントを保存しようとしているときの様子

次に、保存したチェックポイントを使って、ビットストリーム生成までの一連の手順を Vivado に行わせます。再びメニューの Tools → Run Tcl Script を選択し、今度は GenerateBitStream.tcl を実行します。約2分程度で、一連の処理が自動的に行われ、Vivado の初期画面に戻ります。

最後に、作成されたビットストリームを FPGA に書き込むために、Hardware Manager を開きます。三たびメニューの Tools → Run Tcl Script を選択し、今度は OpenHW.tcl を実行します。Hardware Manager が開いたら、Open target のリンクをクリックし、Auto Connect でボードと接続しておきます。

なお、もし自分の PC に Vivado をインストールしている場合は、ビットストリーム生成までの手順は、自分の PC 上で行うこともできます (インストールしていない場合、この段落は読み飛ばしてください)。もしそうしたい場合は、Vivado を起動して Run Tcl Script を行うかわりに、DRFront の Open Project ボタン (OpenProject.tcl) や Generate Bitstream ボタン (GenerateBitStream.tcl) を押せば、DRFront から直接 Vivado を起動し、スクリプトを実行させることも可能です。ビットストリームが生成できたら、project_1 フォルダ内の seg_loop_project_1.bit を ACRi ルームのサーバにアップロードしてください。

遠隔操作の準備と FPGA への書き込み

ここからはリモートデスクトップ上で行う手順と、各自の PC とで行う手順とが前後します。混乱を避けるため、段落の冒頭に【リモートデスクトップ】、《各自の PC》のいずれかを書くことで、どちらで作業をするのかを明記します。

【リモートデスクトップ】 まずは、サーバ側での接続中継の準備です。リモートデスクトップのターミナル上で、作業用フォルダとともにアップロードした connector_serv.py のあるフォルダに移動します。そして、以下のコマンドでコネクタアプリを起動します。

python3 connector_serv.py /dev/ttyUSB1 3399

【リモートデスクトップ】 ログに Serial port opened. という1行が表示されていれば、コネクタアプリは正常に起動しています。このコマンドは、コネクタアプリのスクリプトを起動し、FPGA ボードのシリアルポート (/dev/ttyUSB1) と TCP の 3399 番ポートの間で通信の中継を行いなさい、という意味になります。サーバの 3399 番ポートは SSH 接続時に PC の 13399 番ポートに転送されるよう設定したので、ここまでで FPGA ボードから各自の PC までの接続中継が準備できたことになります。

《各自の PC》 次は、各自の PC での接続中継の準備です。コントローラボードを USB ケーブルで各自の PC と接続します。そして、SawareruSys の配布パッケージの Connector\client\Connector.exe を実行します。Controller Board の None と書かれた場所をクリックすると、利用可能なシリアルポートの一覧が表示されます。

PC 側のコネクタアプリの設定中の様子

《各自の PC》 コントローラボードは通常「USB シリアル デバイス」という名前で認識されるので、これを選択します。そして、2つの Connect ボタンを両方クリックします。両方の接続が正しく行われ、中央のグレーのバーが青に変われば、コントローラボード (COM●) と TCP の 13399 番ポートの間で接続中継の準備は完了です。サーバ上での準備と併せて、これでコントローラボードと FPGA ボードとの間がすべて繋がりました。

【リモートデスクトップ】 それでは FPGA に回路を書き込みます。Hardware タブの xc7a35t_0 (Nexys の場合は xc7a100t_0) を右クリックして、Program Device を選択します。どのファイルを書き込むかを尋ねられるので、project_1 フォルダの中にある seg_loop_project_1.bit を選択します。Run Tcl Script で Hardware Manager を開いているなら、右上の左から3つ目のボタン (モニタの右下に緑の丸が書かれたアイコン) をクリックすると、目的のフォルダに移動できるはずです。

ビットストリームを選択する様子

【リモートデスクトップ】 FPGA への回路の書き込みが完了すると、コントローラボード上の 7 セグメント LED が一定のパターンで移り変わる様子が確認できるはずです。コントローラボード上のスイッチやボタンで、切替えの速度や、方向を変更できるので、併せて確認してみてください。

後始末

一通りの実験が終わったら、後始末を行いましょう。PC 側で行う必要のある後始末は、以下の通りです。

  • PC 側のコネクタアプリの終了
  • コントローラボードの USB ケーブルを抜く

また、リモートデスクトップ側で行う必要のある後始末は、以下の通りです。

  • Vivado の終了
  • サーバ側のコネクタアプリの終了 (アプリを実行中のターミナルで Ctrl+C を押すと終了します)
  • デスクトップ右上の電源マークからログアウト

すべての後始末が完了し、リモートデスクトップが接続設定の画面に戻ったら、SSH 接続を切断します。

まとめ

以上が SawareruSys の基本的な使い方になります。SawareruSys は、今後も少しずつ改良していきたいと考えています (まずは必要な手順をもう少し簡略化したいところです……)。

また、初期のおひろめの機会では、コントローラボード単体での活用法とか、実は FPGA の実機がなくても成り立つ方法なのではないかとか、様々なアイディアの種をいただきました。こうしたアイディアについても、少しずつ実現できていければ、またその成果を ACRi ルームでも利用できるようにしていければと考えています。

愛知工業大学 藤枝直輝

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