(本記事は「FPGA Advent Calendar 2018」24日目の記事です。)
勢いでAvnet Ultra96ボードを購入してみた。
せっかくなのでチュートリアルを一通り試して、どんなもんかね?というのをまとめてアドベントカレンダーのネタにしてみたもの。
- Avnet Ultra96 ボードを試してみた
- チュートリアルを試してみる
- まとめ
Avnet Ultra96 ボードを試してみた
ボードについて
購入はAvnetのオンラインショップにて。本体の価格は29,800円。載ってるFPGAの割には安い!!と思って、とりあえずポチってみた。因みに順調に売れたようで12/24現在、在庫が0になっていた。
主要機能
主な機能をユーザーズガイドから抜粋。
- Zynq UltraScale+ MPSoC ZU3EG SBVA484
- Memory
- Wi-Fi / Bluetooth
- DisplayPort
- 1x USB 3.0 Type Micro-B upstream port
- 2x USB 3.0 Type A downstream ports
- 40-pin Low-speed expansion header
- 60-pin High speed expansion header
- Mounted on thermal bracket with fan
ご覧の通り載ってるFPGAがzynqのUltraScale+ MPSoC(ZU3EG)で、しかもロジックがそこそこ大きい!
注意点としては、電源とUART&JTAGの口が別売りな点。
電源はAvnetで販売はされているようだけど、国内のサイトでは見当たらなかったのでamazonで適当に購入。。
その後もう少し見てたらAvnetのUltra96のサイトの簡単導入ガイドで以下が紹介されていることに気づいた・・・。
Ultra96ボードには電源が同梱されていません。弊社で評価済の電源をご紹介しますので、別途ご用意ください。
- 12V/2A ACアダプタ:UNIFIVE Model: UU324-1220 https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-4B8J
- EIAJ3 電源変換アダプタ:2.1φ→EIAJ3変換 WK-J3 変換ケーブル https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=2AD6-DEK3
因みに筆者が購入したのはこれ↓で、この後の動作確認も普通に出来てたので問題ない模様。安かったから良しとしよう。
UART&JTAGはzynqのMIO経由で接続されておりボード上にpinヘッダが出てるので、何か繋げるものの当てがあれば不要なはず。筆者はそのへんですぐ使えそうなものがなかったのでサクッとAvnetが出してるUltra96用のUSB-to-JTAG/UART Podを購入した(5000円)。
動作確認
この辺は先程の簡単導入ガイドの"3.動作確認"をトレースしているだけ。同梱のmicro SDカードにはボードの評価用のデータが含まれている。
そのため、以下の手順に従うだけで簡単な評価は可能になっていた。以下は"3.動作確認"から引用したもの
Ultra96ボードと電源を入手したら、評価を開始できます。Wi-Fi接続のできるPCを用意し、以下の手順に沿って動作を確認しましょう。
同梱のmicroSDカードをボードに挿入してください
用意した電源アダプタを接続し、12V Jack より12V/2Aを供給して下さい
ボード上のJumper SW2 を”SD”セッティングにして下さい
Powerボタンを押して電源を入れて下さい
PCのブラウザから http://192.168.2.1 に接続して下さい
この後、Webサーバ経由で各種デモをご利用いただけます
- 用意されているExample Projectsの詳細は、Ultra96 Getting Started Guideをご覧ください
デモアプリ:LEDの点灯制御
同梱SDに入ってるイメージを使ってUltra96を立ち上げるとボード側でWi-Fiの初期化やらWebサーバの起動が行われて、Webブラウザ経由で何個かのデモアプリを動かすことが出来る。
その中にLEDの点灯制御が入っている。いわゆるLチカってやつ。
Webブラウザで192.168.2.1にアクセスした時の画面が以下。
この画面の中から「Ultra96 GPIO LEDs」をクリックすると以下の画面に移ってLEDの制御を行うことが出来る。
全LEDをOFF | 全LEDをON |
---|---|
![]() |
![]() |
チュートリアルを試してみる
ここでUltra96用のチュートリアルが公開されている(要ログイン)。公開されているのは以下の4パート。
- Tutorial 01 Build a ZU+ MPSoC Hardware Platform
- Tutorial 02 First ZU+ Application - Hello World
- Tutorial 03 Generate and Run Bare Metal ZU+ Test Applications
- Tutorial 04 FSBL and Boot from microSD Card
上記の他に各チュートリアルの生成物がzipファイル化されたものがSolutionとして提供されている。
なおXilinxのツールの推奨バージョンは2018.2になるようだ。
Tutorial 01 Build a ZU+ MPSoC Hardware Platform
bdfのインストール
githubにAvnetのボードのデータが公開されているので、それをダウンロードしてVivadoのインストール先の所定のディレクトリにコピーする。
$ wget https://github.com/Avnet/bdf/archive/master.zip $ unzip master.zip $ cp -rp bdf-master/* <Vivadoのインストールパス>/data/boards/board_files/.
Tutorial 02 First ZU+ Application - Hello World
お次はお馴染みの「Hello Wolrdを実行してみる」というチュートリアル。
1. プロジェクトの作成
とりあえずVivado2018.2を起動
$ source <Vivadoのインストールパス>/settings64.sh $ vivado &
適当にプロジェクトを作ってFPGAの選択画面に行くと選択できるボードにUltra96が追加されているのでそれを選択。
2. ZYNQ UltraScale + MPSoC の設定
作成したプロジェクトで「Create Block Design」を選択して起動したGUIエディタ上でIPのリストから「ZYNQ UltraScale + MPSoC」を追加。
追加すると「Designer Assistance available」というメッセージが追加されてUltra96用のボードプリセットの設定を行えるのでそれを実行する。
3. 適当にメモリを追加
チュートリアルでは2.でZYNQのIP置いてプリセット読み込んだだけで次に行くのだが、IP置いただけだとPL領域を一切触らないので適当にメモリを追加してZYNQと接続してみた。
この状態で「IP INTEGRATOR→Generate Block Design」を選択してブロックデザインを合成した後、「PROGRAM AND DEBUG → Generate Bitstream」を選択して、FPGAのビットストリームデータを生成する。(最初からGenrate Bitstremだけでも問題にはならんはず)
4. ハードウェアのエクスポートとSDKの起動
ここではXilinxのSDKというeclipseベースの統合開発環境を使って「Hello World」プロジェクトを作って、そのプロジェクト上で生成したバイナリをJTAG経由で実行することになる。
そのため、Vivadoで作ったハードウェアの設定とPL領域の情報が含まれたビットストリームデータをSDK用にエクスポートする必要がある。
手順はとってもシンプルでVivado上から
- 「File → Export → Export Hardware」を選択
- 現れた画面上で「Include bitstream」のチェックボックスをチェックして「OK」を選択
でOK。
その後同じくVivadoのメニューから「File → Launch SDK」を選択し、表示されたウィンドウのデフォルト設定のまま、「OK」を押すとSDKが立ち上がる。
この方法でSDKを立ち上げると、起動時に既にエクスポートしたデータを取り込んだ「<プロジェクト名>_wrapper_hw_platform_0」というプロジェクトが存在しているはずで、これをこのまま使っていく。
5. BSPの作成
メニューから「File → New → Board Support Package」を選択するとBSPの作成画面が起動する。基本的にはデフォルトの設定でOKなのだが、一応以下の2点だけ確認して「Finish」を選択
- Hardware Platformが「<プロジェクト名>_wrapper_hw_platform_0」になってること
- Board Support Package OSが「standalone」であること
BSP作成後にBSPの設定を一部変更する必要があるので、それを行っていく。 「system.mss」というファイルを開くと「Modify this BSP's Settings」というボタンがあるのでそれを押す。
変更する部分は、UARTの設定部分だ。開いた画面の「standalone」を押して開いた画面から「stdin/stdout」を探す。 作成時にはuart_0になっているので、これをuart_1に変更する
6. Hello Worldプロジェクトの作成
メニューから「File → New → Application Project」を選択すると通常のアプリケーションプロジェクトの作成画面が起動する。
適当にプロジェクト名に入力して、「Board Support Package」の部分を「Use exsiting」にして先ほど5.で作ったBSPを選択したら「Next」を選択
「Next」を選択するとアプリケーションのテンプレートの選択画面が開くのでそこから「Hello World」を選択して「Finish」でプロジェクトの作成は完了だ。
7. Hello Worldプロジェクトの実行
さていよいよプロジェクトを実行してみよう。
手順としては
- ボードのDIPスイッチの設定を「JTAGモード」に変更(2bitのDIPスイッチを両方ON)
- ターミナルを接続
- ビットストリームファイルをJTAG経由でFPGAに転送
- SDK上からHello Worldを実行
の3ステップだ。
1. DIPの設定を変更
以下の画像の様にDIPを両方ONにしてブートモードをJTAGにする
2. ターミナルを接続
screen
でもminicom
でもSDK上のSDK terminalでもなんでも良いので、ターミナルエミュレータ使ってボードとUARTで接続する。今回はminicom
を使用。
$ minicom -D /dev/ttyUSB1 -b 115200
設定は以下の通り。
因みに、これまでUART等を一回も使ったことのないユーザーだと権限がなくてシリアルポートへの接続が拒否されることがあるので注意が必要。
Ubuntuの場合なら以下のような感じでdialoutグループにユーザーを追加しよう。
$ sudo gpasswd -a ユーザ名 dialout
3. ビットストリームファイルをJTAG経由でFPGAに転送
VivadoもしくはSDK上からビットストリームファイルの転送を行う。ここではSDKを使用した手順を紹介。
の簡単2ステップ。
ただし、これはXilinxのドライバがきちんと入っていれば、、、、の話。筆者はクリーンインストール後に設定をすっかり忘れていて、ビットストリームファイルの転送に失敗した。。
失敗する場合は、USBのルールファイル等の設定が出来ていない可能性が濃厚なのでとりあえず以下の手順を実施してみるのをオススメする。
$ cd <Vivadoのインストールパス>/data/xicom/cable_drivers/lin64/install_script/install_drivers # 64bit #$ cd <Vivadoのインストールパス>/data/xicom/cable_drivers/lin32/install_script/install_drivers # 32bit $ sudo ./install_drivers $ sudo reboot
4. SDK上からHello Worldを実行
SDK上の「Hello World」プロジェクトにポインタを合わせて右クリックすると開くメニューから「Run As → 1. Launch on Hardware(System Debugger)」を選択
プログラムの転送と実行が行われて正常に実行できれば、2.で接続したターミナルに「Hello World」が表示される。
Tutorial 03 Generate and Run Bare Metal ZU+ Test Applications
ここからはサクッと。
チュートリアル3ではテストアプリケーションを実行して、ボード上の機能を一通りテストすることが可能になっている。
チュートリアル2の要領でプロジェクト作成画面を開き、テンプレートの選択画面から以下の3つのプロジェクトを選択してボードで実行してみる流れとなっていた。
- Memory Tests
- Peripheral Tests
- Zynq MP DRAM Tests
注意点は「各アプリケーションの実行の間にPower ON Resetを挟む必要がある」ということだ。PORなのでビットストリームも再展開が必要になる。
Memory Tests
--Starting Memory Test Application-- NOTE: This application runs with D-Cache disabled.As a result, cacheline requests will not be generated Testing memory region: axi_bram_ctrl_Mem0 Memory Controller: axi_bram_ctrl Base Address: 0xA0000000 Size: 0x10000 bytes 32-bit test: PASSED! 16-bit test: PASSED! 8-bit test: PASSED! Testing memory region: psu_ddr_0_MEM_0 Memory Controller: psu_ddr_0 Base Address: 0x50 Size: 0x7FEFFFB0 bytes 32-bit test: PASSED! 16-bit test: PASSED! 8-bit test: PASSED! --Memory Test Application Complete-- ---Entering main---
ご覧になってお気づきかもしれないが、Vivadoのブロックデザイン作成時に適当に追加したaxi_bram_ctrlとその先に繋がるRAMへのテストが勝手に実行されていた。
どうもBSPからそのへんの情報を読み取って作ってくれているみたい。ZYNQからaxi_bram_ctrlへのパスは敢えて64ビットバスに変更しているが、エラーも無いのでそのへんの設定もきちんと反映されていることが確認できた。
Peripheral Tests
こちらはペリフェラルへのアクセステスト。こいつについては少し修正が必要。 というのものテスト対象にターミナルと接続しているUART1が含まれており、これが含まれているとテストが途中で停止してしまうから。 そのため"testperiph.c"というソースコードファイルのUART1に関するテスト部分(L.852〜L.881)をコメントアウトする。
// { // int Status; // // print("\r\nRunning UartPsPolledExample() for psu_uart_0...\r\n"); // Status = UartPsPolledExample(XPAR_PSU_UART_0_DEVICE_ID); // if (Status == 0) { // print("UartPsPolledExample PASSED\r\n"); // } // else { // print("UartPsPolledExample FAILED\r\n"); // } // } // { // int Status; // // print("\r\n Running Interrupt Test for psu_uart_0...\r\n"); // // Status = UartPsIntrExample(&intc, &psu_uart_0, \ // XPAR_PSU_UART_0_DEVICE_ID, \ // XPAR_PSU_UART_0_INTR); // // if (Status == 0) { // print("UartPsIntrExample PASSED\r\n"); // } // else { // print("UartPsIntrExample FAILED\r\n"); // } // // }
---Entering main--- Running ScuGicSelfTestExample() for psu_acpu_gic... ScuGicSelfTestExample PASSED ScuGic Interrupt Setup PASSED Running XZDma_SelfTestExample() for psu_adma_1... XZDma_SelfTestExample PASSED Running Interrupt Test for psu_adma_1... ZDMA Simple Example PASSED Running XZDma_SelfTestExample() for psu_adma_2... XZDma_SelfTestExample PASSED Running Interrupt Test for psu_adma_2... ZDMA Simple Example PASSED Running XZDma_SelfTestExample() for psu_adma_3... XZDma_SelfTestExample PASSED Running Interrupt Test for psu_adma_3... ZDMA Simple Example PASSED Running XZDma_SelfTestExample() for psu_adma_4... XZDma_SelfTestExample PASSED Running Interrupt Test for psu_adma_4... ZDMA Simple Example PASSED Running XZDma_SelfTestExample() for psu_adma_5... XZDma_SelfTestExample PASSED Running Interrupt Test for psu_adma_5... ZDMA Simple Example PASSED Running XZDma_SelfTestExample() for psu_adma_6... XZDma_SelfTestExample PASSED Running Interrupt Test for psu_adma_6... ZDMA Simple Example PASSED 〜長いので中略〜 Running Interrupt Test for psu_gdma_7... ZDMA Simple Example PASSED Running IicPsSelfTestExample() for psu_i2c_1... IicPsSelfTestExample PASSED Running XZDma_SelfTestExample() for psu_adma_0... XZDma_SelfTestExample PASSED Running Interrupt Test for psu_adma_0... ZDMA Simple Example PASSED Running SpiPsSelfTestExample() for psu_spi_0... SpiPsSelfTestExample PASSED Running SpiPsSelfTestExample() for psu_spi_1... SpiPsSelfTestExample PASSED Running Interrupt Test for psu_ttc_0... TtcIntrExample PASSED Running Interrupt Test for psu_ttc_1... TtcIntrExample PASSED Running Interrupt Test for psu_ttc_2... TtcIntrExample PASSED Running Interrupt Test for psu_ttc_3... TtcIntrExample PASSED Running WdtPsSelfTestExample() for psu_wdt_0... WdtPsSelfTestExample PASSED Running WdtPsSelfTestExample() for psu_wdt_1... WdtPsSelfTestExample PASSED ---Exiting main---
Zynq MP DRAM Tests
これは実行してみた結果だけペタリ。まあとりあえずなんか動いた、、ということで。
******************************************************************************** Zynq MPSoC DRAM Diagnostics Test (A53) ******************************************************************************** Select one of the options below: +--------------------------------------------------------------------+ | Memory Tests | +-----+--------------------------------------------------------------+ | '0' | Test first 2MB region of DDR | | '1' | Test first 32MB region of DDR | | '2' | Test first 64MB region of DDR | | '3' | Test first 128MB region of DDR | | '4' | Test first 256MB region of DDR | | '5' | Test first 512MB region of DDR | | '6' | Test first 1GB region of DDR | | '7' | Test first 2GB region of DDR | | '8' | Test first 4GB region of DDR | | '9' | Test first 8GB region of DDR | +-----+--------------------------------------------------------------+ | Eye Tests | +-----+--------------------------------------------------------------+ | 'r' | Perform a read eye analysis test | | 'w' | Perform a write eye analysis test | | 'a' | Print test start address | | 't' | Specify test start address (default=0x0) | | 's' | Select the DRAM rank (default=1) | +-----+--------------------------------------------------------------+ | Miscellaneous options | +-----+--------------------------------------------------------------+ | 'i' | Print DDR information | | 'v' | Verbose Mode ON/OFF | | 'o' | Toggle cache enable/disable | | 'b' | Toggle between 32/64-bit bus widths | | 'h' | Print this help menu | +-----+--------------------------------------------------------------+ Bus Width = 32, D-cache is enable, Verbose Mode is OFF DDR ECC is DISABLED Enter 'h' to print help menu Enter Test Option: 2 Starting Memory Test '2' - Testing 64MB length from address 0x0... ---------+--------+------------------------------------------------+----------- TEST | ERROR | PER-BYTE-LANE ERROR COUNT | TIME | COUNT | LANES [ #0, #1, #2, #3, #4, #5, #6, #7] | (sec) ---------+--------+------------------------------------------------+----------- MT0(1: 0)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 1.34021 ---------+--------+------------------------------------------------+----------- MTS(1: 1)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 0.675676 ---------+--------+------------------------------------------------+----------- MTS(1: 2)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 0.676332 ---------+--------+------------------------------------------------+----------- MTS(1: 3)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 0.676332 ---------+--------+------------------------------------------------+----------- MTS(1: 4)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 0.676332 ---------+--------+------------------------------------------------+----------- MTS(1: 5)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 0.676332 ---------+--------+------------------------------------------------+----------- MTS(1: 6)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 0.676332 ---------+--------+------------------------------------------------+----------- MTS(1: 7)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 0.676332 ---------+--------+------------------------------------------------+----------- MTS(1: 8)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 0.676332 ---------+--------+------------------------------------------------+----------- MTP(1: 9)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 1.08134 ---------+--------+------------------------------------------------+----------- MTP(1:10)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 1.08069 ---------+--------+------------------------------------------------+----------- MTL(1:11)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 1.16523 ---------+--------+------------------------------------------------+----------- MTL(1:12)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 1.16523 ---------+--------+------------------------------------------------+----------- MTL(1:13)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 1.16523 ---------+--------+------------------------------------------------+----------- MTL(1:14)| 0 | 0, 0, 0, 0, 0, 0, 0, 0 | 1.16523 ---------+--------+------------------------------------------------+----------- Bus Width = 32, D-cache is enable, Verbose Mode is OFF
Tutorial 04 FSBL and Boot from microSD Card
ブログ投稿直後は載っけてなかったんだけど、意外とサクッと終わったので追加。
FSBLの作成
チュートリアル2・3と同様に「File → New → Application Project」を選択 先ほど既にBSPは作っているが、そのBSPにはSDカードからブートする際には必要なデータが含まれていないため、新たに作成する必要がある。
そのため下の画像のように「Create New」を選択して「Next」を押す。
次の画面では「Zynq MP FSBL」を選択して「Finish」を押す。
次は先程BSPを修正したのと同様に新規に作成したBSPの設定を変更する。(uart_0をuart_1に変更)
BOOT.binの作成
今回はSD起動後に実行するテストをチュートリアル3で実行した「Peripheral Tests」にする。
SDK上の左の”Project Explorer”から「Periph_Test」を開く。開いた状態でメニューから「Xilinx → Create Boot Image」を選択。
すると、以下の画面が開く。
今回は特に設定を変更する必要は無いので、そのまま「Create Image」を押して画面を閉じよう。 画面を閉じると「Periph_Test」の中に「bootimage」というディレクトリが生成されて、その中に
- BOOT.bin
- Periph_Test.bif
という2つのファイルができるので、これをマイクロSDの先頭のパーティションに入れる。(同梱のマイクロSDカードを使うなら”boot”と書いたボリューム) このマイクロSDをUltra96に挿して、ブートモード設定をSD(DIPスイッチをOFFーON)に変更してボードの電源を入れると、"BOOT.bin"が各種設定を行った後に"Periph_Test.bif"が実行される
画像の先頭に「Xilinx Zynq MP First Stage Boot Loader」という文字があるのがわかるかと思う。
まとめ
値段の割には載っているFPGAも大きめでいろんなことが出来るボードだと思う。それに付属しているチュートリアルもとても丁寧な作りになっているので、そちらをきちんと追っていけば導入時点で躓くことはあんまりないと思った。
ボード自体もコンパクトで家で机の上に置いて実験するには良いサイズ。というかこれで周辺まで充実させたらこの価格にはならないと思うので、自分にとってはとってもありがたいFPGAボードになりそう。96Boards用の拡張ヘッダも付いてるのでそのうちそっち用のアクセサリも購入して試してみたい。
今年になってRISC-Vや実装に使われているChiselを勉強していてるので、今後はまず手始めに既存のRISC-V実装(たぶんSCR1というコアになるかな)を入れてみて、その後に自分で書いたRISC-Vとかもこのボードに入れて試せたらなぁ、、、という風に進めていきたい。
明日の「FPGA Advent Calendar 2018」最終日は @shimoshida さんの「まだディープラーニング圧縮で疲弊してるの?男は黙ってBinarization」です。