Linux PCでのUSRP-X410内部FPGAイメージファイルの生成

更新しました Nov 17, 2022

環境

ハードウェア

  • USRP X410

ソフトウェア

  • FPGA Xilinx Compilation Tools

オペレーティング・システム

  • Linux

その他

  • Linux (ubuntu)
  • UHD
  • GNU Radio
  • RFNoC
  • Xilinx VIVADO

LinuxでのUSRP-X410開発環境の構築 」の手順によりLinux PC上にUSRP-X410の開発環境を構築し、「Multi-FosphorサンプルデモによるLinux PCでのUSRP-X410動作検証 」の手順によりLinux PCでUSRP-X410の動作を確認した後、本稿でUSRP-X410内部FPGAイメージファイル(.bit)をカスタマイズ・生成することができます。
本稿では、Linux PCでUSRP-X410内部のFPGAイメージファイルを生成するためのXilinx VIVADOコンパイラの設定と使用方法について説明します。

 
  1. ubuntu 20.04.3 LTSの関連モジュールおよびVivadoパッチのインストール

    1. 本書の手順を実行する前に、「LinuxでのUSRP-X410開発環境の構築 」により、Linux PCのセットアップが完了していること(同一PCにVivado 2019.1.1アップデートもインストール済み)を必ずご確認ください。また、本書の手順内では、UHD 4.2以上が必要となりますので、事前にインストールをお願いします。また、本書の手順によりXilinx Vivadoでコンパイル/ビルドするには、Linux-PCのメインメモリ(DRAM)のサイズとして最低16GB、推奨24GB以上が必要ですので、あらかじめご確認ください。必要に応じて、Ettus社の「USRP Hardware Driver and USRP Manual」を参照してください。
 
  1. 次のコマンドにより、ubuntu 20.04.3 LTSの関連モジュールをインストールします(ただし初回のみ)。このとき、VPN接続をしているとエラーとなることがありますので、その場合は、VPNを切断してから実行してください。また、これ以降、本書に記載のコマンドを「右クリック >> コピー」した後、端末ウィンドウ内で「右クリック >> 貼り付け」して、実行可能です。

sudo apt-get install python bash build-essential doxygen

1-1-a.png

  1. Xilinx社のダウンロードリンク より、Xilinx Vivado 2019.1用のAR73068パッチファイルをLinux PC(ubuntu)の「$HOME/ダウンロード」フォルダにダウンロードします。

 

  1. 次のコマンドにより、上記でダウンロードしたzipファイルを「$XILINX_VIVADO/patches」ディレクトリにコピーしてから解凍します。例えば、インストール・パスがデフォルトの場合は、「/tools/Xilinx/Vivado/2019.1/patches」です。


sudo mkdir $XILINX_VIVADO/patches
cd $XILINX_VIVADO/patches
sudo cp $HOME/ダウンロード/AR73068_Vivado_2019_1_preliminary_rev1.zip .
sudo unzip AR73068_Vivado_2019_1_preliminary_rev1.zip

 

ここで「vivado」ディレクトリが生成されます。
1-3-a.png

  1. 次のコマンドにより、Linux環境設定ファイルに環境変数を追加します。

cd $HOME
echo 'export XILINX_PATH=$XILINX_PATH:/tools/Xilinx/Vivado/2019.1/patches/vivado' >> $HOME/.bashrc

1-4-a.png
正しく追加されたか確認するために、次のコマンドにより、viエディタで表示してみます。
 

vi $HOME/.bashrc
 

<G>キー(<Shift-g>)を押して、ファイルの最終行に移動して確認します。
1-4-b.png
万が一、正しく追加されていなかった場合には、<i>キーで編集モードに移行することによって、ファイルを編集できます。編集した場合は <ESC>キー >> <:wq> と入力することによって、上書き保存後にviエディタを終了します。編集しなかった場合は <:q> と入力して、viエディタを終了します。
 

  1. さらに以下のコマンドにより、その環境設定ファイルをsourceします。もしくは、いったんTerminalウィンドウを閉じてから、再度Terminalを開きます。

source $HOME/.bashrc

1-5-a.png

 

  1. FPGAイメージの生成(ビルド)

 

  1. 本章以降のXilinx VivadoによるFPGAソースファイルのコンパイル/ビルド中は、ホストPC上で他の作業をすることは、なるべく避けてください。

  

  1. LinuxでのUSRP-X410開発環境の構築」を実行した際に、GitHubのリポジトリを下記のディレクトリにクローンしているはずです。下記の「git」は、セットアップ時にユーザが設定したディレクトリ名です。

$HOME/git
 

もし当該リポジトリの最新版をクローンしたい場合は、次のコマンドにより、再度、クローンを実行します。このとき、下記の「$HOME/git」の代わりに「$HOME/git2」などの別ディレクトリ名でも結構です。

mkdir $HOME/git
cd $HOME/git
git clone https://github.com/EttusResearch/uhd

 

  1. X410のFPGA用の標準(デフォルト)ソースファイル・ディレクトリは、以下の場所にありますので、次のコマンドにより、当該ディレクトリに移動します。

cd $HOME/git/uhd/fpga/usrp3/top/x400
 

本来は、必要に応じて、このディレクトリ内にあるソースファイル(.v)を編集してFPGAをカスタマイズしますが、まずはビルド確認のため、編集せずにそのまま次のステップに移ります。
 

  1. 次のいずれかのコマンドにより、Xilinx Vivadoのインストール・パスを認識させます。必要に応じてEttus社のマニュアルサイト「USRP Hardware Driver and USRP Manual」を参照してください。
  • Vivadoをデフォルト・パス(/tools/Xilinx/Vivado)にインストールした場合

source setupenv.sh

  • Vivadoをデフォルト・パス以外にインストールした場合

source setupenv.sh --vivado-path=<Vivadoのインストール・パス>

2-3-a.png

  1. 社内Xilinxライセンスサーバーに接続するためにVPN接続が必要な場合は、ここで接続します。
  2. 次のコマンドにより、ビルド(.bitファイル生成)します。例えば、CPU:Core-i5、DRAM:24GBのPCで約3時間を要します。

make X410_X4_200

2-5-a.png
ちなみに、以下のようなオプションスイッチ(上記コマンドの最後尾に追加)もあります。

GUI=1 (上記のBatchモードの代わりにGUIモードでビルドする場合)
CHECK=1 (HDL構文チェックのためのエラボレーションのみを実行する場合)
SYNTH=1 (論理合成のみを実行する場合)
TOP=<module> (構文チェックのための代替トップレベルモジュールを指定する場合)


また、USRP-X310や他の第3世代USRPデバイスとは異なり、FPGAイメージは、QSFP28コネクタの構成方法だけでなく、どのマスタークロックレートが利用可能かもエンコードされています。これは、データ・コンバータの構成がFPGAイメージの一部であるためです(X410のADC/DACは、FPGAと同じダイ上にあります)。例えば、FPGAターゲットタイプX4_200は、200MHzのアナログ帯域幅に設定され、245.76MHzまたは250MHzのマスタークロックレートをサポートすることができます。以下の他のターゲットタイプもMakefileを書き換えることにより利用可能です。

・X1_100        (QSFP28-Port0:1x10GbE/Lane0, QSFP28-Port1:NC)
・X4_100, X4_200    (QSFP28-Port0:4x10GbE/All Lanes, QSFP28-Port1:NC)
・XG_100, XG_200    (QSFP28-Port0:1x10GbE/Lane0, QSFP28-Port1:1x10GbE/Lane0)

 

  1. ビルド後の生成ファイルは、以下の場所に生成されます。

$HOME/git/uhd/fpga/usrp3/top/x400/build

2-6-a.png
上記ディレクトリに、以下の3つのファイルが生成されたことを確認します。

usrp_x410_fpga_X4_200.bit  (Configuration bitstream with header)
usrp_x410_fpga_X4_200.dts  (Device tree overlay)
usrp_x410_fpga_X4_200.rpt  (System, utilization and timing summary report)

ちなみに、ビルドログ(エラー発生時にはエラー内容も含む)は以下の場所に生成されます。

$HOME/git/uhd/fpga/usrp3/top/x400/build-X410_X4_200/

2-6-b.png
 

  1. FPGAイメージの書き換え確認

    1. X410に電源を入れるため、ホストPC(Linux)を一旦、シャットダウンし、X410に電源を入れてからホストPCを起動します。
    2. まず次のコマンドにより、X410のIPアドレスを確認しておきます。

uhd_find_devices

3-2-a.png
上図例では2つ目の「mgmt_addr: 192.168.11.10」のほう(最下位の数字が最大のもの)がX410のIPアドレスです。1つ目のアドレスは10GbE/QSFP28のものです。10GbE/QSFP28が2系統接続されている場合は、このほかにもう1つアドレスが表示されますのでご注意ください。

  1. Read/Writeバッファメモリのサイズを指定するために、次の2つのコマンドを実行します。

sudo sysctl -w net.core.rmem_max=2500000
sudo sysctl -w net.core.wmem_max=2500000

3-3-a.png

  1. 次のコマンドにより、X410内部FPGAの標準(デフォルト)イメージ(.bitファイル)が、正常に書き換えられるか確認します。

uhd_image_loader --args="type=x4xx,addr=<X410のIPアドレス>,fpga=X4_200" --fpga-path=<.bitファイルのパス>
 

ただし、上記の <.bitファイルのパス> は、デフォルトでは「$HOME/git/uhd/fpga/usrp3/top/x400/build/usrp_x410_fpga_X4_200.bit」となります。別の場所にあるイメージを書き込む場合には、適宜、変更してください。
3-4-a.png

  1. 上記が正常に完了したら次のコマンドを実行し、X410を検出した結果が、「LinuxでのUSRP-X410開発環境の構築 」10.11章の図(=下図)と同様になるかを確認します。

uhd_usrp_probe --args="addr=<X410のIPアドレス>" 

3-5-a.png
3-5-b.png3-5-c.png

  1. FPGAイメージのカスタマイズ

  1. X410内部のFPGAイメージを独自のものに書き換える場合は、前章のビルド確認手順を実行した後に、本章の手順に従って試してみてください。 また、X410デフォルトのFPGA内には余剰回路スペースがあまり残っていないと思われますので、大きな回路/論理などを追加した場合、ビルドに失敗することがありますのでご注意ください。

 

  1. 次のコマンドにより、X410のFPGA用の標準(デフォルト)ソースファイル・ディレクトリに移動します。

cd $HOME/git/uhd/fpga/usrp3/top/x400
 

このディレクトリ内にあるソースファイル群(.v)を編集してFPGAをカスタマイズします。ちなみに、GPIOが関連しているソースファイルは以下の6ファイルですが、その中で編集が必要なファイルを選別してすべて適切に編集してください。
  「x4xx.v」「x4xx_core.v」「x4xx_core_common.v
  「x4xx_dio.v」「x4xx_gpio_atr.v」「x4xx_gpio_spi.v

特に、実際にGPIOで入出力させたい信号の制御は、「x4xx_core.v」ファイル内の338~341行目付近の記述を参考にして、適宜、追加/編集(下例)することによって行います。必要に応じて、Ettus社のリポジトリサイト を参照してください。

例:次章にて、DIO#0 (12pin) をすべて出力に、DIO#1 (12pin) をすべて入力に設定した場合

wire [11:0] gpio1_input;    // arbitrary variable name
//-------------------------------------
.gpio_in_fabric_a    (),
.gpio_in_fabric_b    (gpio1_input),    // All 12 bits of input data to be transferred to "gpio1_input"
.gpio_out_fabric_a  (12'h03F),        // Output ‘0’ to half upper, and ‘1’ to half lower bits of DIO#0
.gpio_out_fabric_b  (12'h000),        // Don’t care, because DIO#1 is set to 'Input'
//-------------------------------------

 

 

  1. 上述の2章に従って、編集したファイルを含むソース・ディレクトリ内でビルドします。
  2. 上述の3章に従って、上記で生成したX410内部FPGAイメージ(.bitファイル)をFPGAにロードします。
  3. FPGAイメージ(.bitファイル)のロードが正常に完了したら、次章の「UHD API経由のGPIO制御機能の無効化」を実行してください。

 

  1. UHD API経由のGPIO制御機能(標準機能)の無効化

  1. X410内部FPGAのGPIOは、C++/PythonからUHD APIを経由してGPIO制御する機能がデフォルトで有効になっています。本来は、この機能を使用することが標準となっていますが、FPGA内部ロジックにより直接GPIOを制御する場合は、この機能を無効化する必要があります。詳しくは、Ettus社ウェブサイト「Getting Started with UHD and C++ - Ettus Knowledge Base」を参照してください。
  1. まず、「LinuxでのUSRP-X410開発環境の構築 」の4章を参照し、cmakeのバージョンを再度確認し、そのバージョンが3.5.1よりも古い場合は以降の手順においてエラーが発生しますので、cmakeの3.5.1以上のバージョン(3.8~最新バージョンを推奨)をインストールします。
  2. Ettus社Webサイト「https://kb.ettus.com/Getting_Started_with_UHD_and_C++ 」内の説明に従って「$HOME/git/uhd/host/examples/init_usrp/」ディレクトリ内の「init_usrp.cpp」ファイルの内容を編集します。このとき、init_usrp.cpp」ファイルの内容を当該Webサイト内の「Full Example」に書き換えることをお薦めします。ただし、「Full Example」冒頭の「#include <uhd/utils/thread_priority.hpp>」文は、「#include <uhd/utils/thread.hpp>」に修正してください。またその際に、以下の例に示すように、「usrp->set_gpio_src」および「usrp->set_gpio_attr」の部分を「init_usrp.cpp」ファイルに追加します。下の例はあくまでも一例ですので、必要に応じてピン設定/パラメータ設定を変更してください。


init_usrp.cpp への追加例
ファイル内に以下の「usrp->set_gpio_src」および「usrp->set_gpio_attr」記述部分を追加します。詳しくは、Ettus社のマニュアルサイト を参照してください。


――――――――――「usrp->set_gpio_src」部の例 ――――――――――
// Set every pin on DIO#0 to be USER_APP
usrp->set_gpio_src("GPIO0",
            {"USER_APP", "USER_APP", "USER_APP", "USER_APP", "USER_APP", "USER_APP",
             "USER_APP", "USER_APP", "USER_APP", "USER_APP", "USER_APP", "USER_APP"});
// Set every pin on DIO#1 to be USER_APP
usrp->set_gpio_src("GPIO1",
            {"USER_APP", "USER_APP", "USER_APP", "USER_APP", "USER_APP", "USER_APP",
             "USER_APP", "USER_APP", "USER_APP", "USER_APP", "USER_APP", "USER_APP"});

―――――――――――――――――――――――――――――――――――――――――――――――――

――――――――――「usrp->set_gpio_attr」部の例 ―――――――――
// Set “pin_mask” for configuring Non-ATR mode (all bits to be configured)
uint32_t pin_mask = 0xFFFFFF; 
// Set “pin_mask_ddr” for configuring all pins of DIO#0 to be 'Output' and all pins of DIO#1 to be 'In-put'
uint32_t pin_mask_ddr = 0x000FFF;
// Set DDR for DIO#0 to be all outputs, DIO#1 to be all inputs
usrp->set_gpio_attr("GPIO", "DDR", pin_mask_ddr, pin_mask);
// Set Non-ATR mode to all pins of DIO#0 & DIO#1 (total 24bits)
usrp->set_gpio_attr("GPIO", "CTRL", 0, pin_mask);
―――――――――――――――――――――――――――――――――――――――――――――――――


また、好みに応じて下記部分の数値を書き換えます。
――――――――――――――― パラメータ設定部 ――――――――――――――――
std::string subdev("A:0");   // <motherboard slot name>:<daughterboard frontend name>
std::string ant("TX/RX");    // Rx Antenna Port
・ ・ ・ ・ ・
double rate(1e6);            // Rx Sample Rate
double freq(915e6);          // Rx RF Frequency
double gain(10);             // Rx Gain
double bw(1e6);              // Rx RF Bandwidth
―――――――――――――――――――――――――――――――――――――――――――――――――

――――「init_usrp.cpp」パラメータ設定部の編集例 ――――
int UHD_SAFE_MAIN(int argc, char *argv[]) {
    uhd::set_thread_priority_safe();

    std::string device_args("addr=192.168.10.2");
    std::string subdev("B:1");    // "A:0" or "A:1" or "B:0" or "B:1"
    std::string ant("RX1");       // "TX/RX0" or "RX1"
    std::string ref("internal");

    double rate(40e6);
    double freq(3000e6);
    double gain(5);
    double bw(400e6);
―――――――――――――――――――――――――――――――――――――――――――――――――

以上の編集が完了したら、上書き保存(元ファイルのバックアップを推奨)または別ファイル名(例えば「init_usrp_XXX.cpp」など)で保存します。

  1. $HOME/git/uhd/host/examples/init_usrp/」ディレクトリ内の「CMakeLists.txt」ファイルの内容を、当該Webサイト内の「CMake」項を参考にして、必要に応じて編集します。ただし、上記5.2章で保存したファイル名が「init_usrp.cpp」のままであれば、編集は不要です。複数種類のパラメータ設定ごとに「init_usrp.cpp」の内容を変更して、それぞれ別のファイル名(例えば「init_usrp_XXX.cpp」など)で保存した場合は、下図で示すように「CMakeLists.txt」内の該当部分を変更して保存します。ただし「CMakeLists.txt」のファイル名は変えないでください。


―――――――――――「CMakeLists.txt」の編集例 ―――――――――――
### Make the executable #######################################################
add_executable(init_usrp_XXX init_usrp_XXX.cpp)

set(CMAKE_BUILD_TYPE "Release")
message(STATUS "******************************************************************************")
message(STATUS "* NOTE: When building your own app, you probably need all kinds of different  ")
message(STATUS "* compiler flags. This is just an example, so it's unlikely these settings    ")
message(STATUS "* exactly match what you require. Make sure to double-check compiler and     ")
message(STATUS "* linker flags to make sure your specific requirements are included.          ")
message(STATUS "******************************************************************************")

# Shared library case: All we need to do is link against the library, and
# anything else we need (in this case, some Boost libraries):
if(NOT UHD_USE_STATIC_LIBS)
    message(STATUS "Linking against shared UHD library.")
    target_link_libraries(init_usrp_XXX ${UHD_LIBRARIES} ${Boost_LIBRARIES})
# Shared library case: All we need to do is link against the library, and
# anything else we need (in this case, some Boost libraries):
else(NOT UHD_USE_STATIC_LIBS)
    message(STATUS "Linking against static UHD library.")
    target_link_libraries(init_usrp_XXX
        # We could use ${UHD_LIBRARIES}, but linking requires some extra flags,
        # so we use this convenience variable provided to us
        ${UHD_STATIC_LIB_LINK_FLAG}
        # Also, when linking statically, we need to pull in all the deps for
        # UHD as well, because the dependencies don't get resolved automatically
        ${UHD_STATIC_LIB_DEPS}
    )
endif(NOT UHD_USE_STATIC_LIBS)
―――――――――――――――――――――――――――――――――――――――――――――――――


CMakeLists.txt」を編集した場合は上書き保存(元ファイルのバックアップを推奨)します。
 

  1. 上記で作成/編集した「init_usrp_XXX.cpp」(または「init_usrp.cpp」)と「CMakeLists.txt」を、任意の場所に新規作成した空のディレクトリにコピーします。

5-4-a.png

上図は、新規作成ディレクトリが「$HOME/usrp_init/」の場合です。

 

  1. 当該Webサイト内の「Compile and Install」項に従って、コンパイル/ビルドします。前項で作成した新規ディレクトリ上で、次のコマンドを実行します。

mkdir build
cd build
cmake ../
make

5-5-a.png

  1. X410が起動されていることを確認後(起動していない場合は、一旦、ホストPCをシャットダウンしてから、X410→ホストPCの順に起動)、送受信バッファメモリのサイズを指定するために、次の2つのコマンドを実行します。

sudo sysctl -w net.core.rmem_max=25000000
sudo sysctl -w net.core.wmem_max=25000000

5-6-a.png

  1. 当該Webサイト内の「Running the Application」項に従って、上記5-5.で生成された実行ファイル(「init_usrp」または「init_usrp_XXX」)をホストPC上で実行します。

./init_usrp

5-7-a.png
上図内の警告文「[WARNING] [UHD] Unable to set the thread priority. Performance may be negatively affected.」は、特に影響が無いので無視してください。この警告文を表示しないようにしたい場合など、詳しくは、Ettus社の解説サイト をご参照ください。
 

  1. 以上が完了したら、X410のFPGAが期待動作をするか確認します。