- 1回目: 開発環境の準備
- 2回目: Hello Worldプロジェクト <--- 今回の内容
- 3回目: PSのGPIOでLチカ
- 4回目: PLのAXI GPIOでPSからLチカ
- 5回目: PLだけでLチカ
- 6回目: 自作IPでLチカ
- 7回目: ブートイメージを作る
- 8回目: Linux起動する
- 9回目: Linuxカーネルを少しカスタマイズする
- 10回目: LinuxのRootFSをカスタマイズする / PythonでHello World
- 11回目: LinuxユーザアプリケーションでLチカ
- 12回目: LinuxカーネルモジュールでLチカ
- 13回目: LAN(Ethernet 0)を使う
- 14回目: Linuxユーザアプリをデバッグする / RootFSに取り込む
- 15回目: Linux起動時にアプリケーションを自動実行させる
- 16回目: Linuxから自作IPをUIOで制御する
- 17回目: Linuxで自作IPのデバイスドライバを作る
- 18回目: IoT化してスマホからLチカ
この記事の内容を4分で見る( https://www.youtube.com/watch?v=VJCL2Z81DLQ )
環境
- 開発用PC: Windows 10 64-bit
- Vivado 2017.4 WebPACKライセンス
- Xilinx SDK 2017.4
- ターゲットボード: ZYBO (Z7-20)
Windows環境は1回目を参照。
Hello Worldプロジェクト
PS部のUARTとCPU上のソフトウェアでHello Worldを出力します。メインはPS部ですが、まずはVivadoでハードウェアを作ります。その後、SDKでHello Worldソフトを書きます。
プロジェクトの作成 (Vivado)
まず、Vivadoでハードウェアを作ります。Vivado 2017.4を起動します。そして、File -> New Project。プロジェクトの保存先とプロジェクト名を設定します。ここではプロジェクト名は"project_1"にします。プロジェクトタイプは "RTL Project"にします。"Add Sources"と"Add Constraints"では何もせずNext。"Default Part"の所で、まず"Boards"を選びます。そして、Vendorにdigilentinc.comを選びます。Display NameにZybo Z7-20を選びます。これらは、前回の環境設定の所でボードファイルを追加したため選択可能となっています。Nextをクリック、Finishをクリックしてプロジェクト作成完了です。使用しているボードが違う場合には、適宜置き換えてください。
無事プロジェクトが作成されると、以下のような画面になります。
PSだけのハードウェアを作る (Vivado)
PSだけのブロックデザインを作る
上のVivado画面を見ると、Top module nameがNot definedとなっています。つまり、今は空っぽの状態です。これに、PS部だけのモジュールを作り搭載します。PS部とはCPU(ARM Cortex-9 x 2) と、UART等のペリフェラルIFを持つユニットです。
左側のFlow Navigator -> IP INTEGRATOR -> Create Block Designで、新しいブロックデザインを作ります。名前はデフォルトのままdesign_1とします。
Diagramビューの"Press the + button to add IP"をクリックして、"ZYNQ7 Processing System"を選択します。すると、PS部が配置されます。そして、画面上の"Run Block Automation"をクリックします。設定Window画面が出ますが、「Apply Board Preset」にチェックがついていることを確認してOKしてください。これによって、プロジェクト作成時に指定したボード(ZYBO)に適したPSが作られて、配置されます。
PS部のプロパティ変更もできます。"Block Properties"の所から変更が出来ます。又は、DiagramビューでPSをダブルクリックすることでも、PSをカスタマイズできます。今回は、何も変更しません。このPSは既にZYBOボードに適した設定になっているためです。例えば、ターミナル出力に使うUART1用のIOは複数の候補から選択することが出来ますが、実際にボード上で接続されているのは、MIO48とMIO49です。今作ったPSもUART1はMIO48とMIO49を使うように設定されています。
設定は変更しませんが、どのようなことが出来るか見てみます。
PS部のオーバービューを見たり
各種コンフィギュレーションをしたり (例えば、UARTのボーレート変更)
ペリフェラル用のIOとして、どのピンを使うかの設定をしたり (MIO(Multiplexed IO)というピンから選ぶ。マイコンによくある、どの機能にするかを選ぶMUXみたいな感じ)
作成したブロックデザインをチェックする
PSを配置しただけですが、とにかくブロックデザインを作ってみました。これが問題ないかどうかをチェックします。Diagramビュー上で右クリック -> Validate Designを選ぶことで、チェックできます。すると、こんなシンプルなデザインなのに、なんとエラーが出ていました。M_AXI_GP0_ACLKにクロックが正しく供給されていないのが原因のようです。
ブロックデザインを修正する
AXIはIP間を接続するときに使うバスです。PSがマスターとなって、他のスレーブIP(例えば、AXI GPIO)と接続するときに使います。M_AXI_GP0_ACLKはその基になるクロックです。そのため、今回は使わないので、AXI_GP0のマスター機能そのものをOFFにすることでも修正可能です。しかし、どうせそのうち使うので、今回はちゃんとクロックを供給設定してあげることで修正します。ちょうど、PSからFCLK_CLK0というポートが出ています。この設定を見ると、50MHzの出力のようです。周波数などは変更可能ですが、今回はデフォルトのまま使います。
このFCLK_CLK0とM_AXI_GP0_ACLKを接続してあげます。Diagramビュー上でPSのピンの近くにマウスカーソルを持っていくと鉛筆アイコンになるので、そのままドラッグして接続するだけです。
この状態で再度Validate Designすると、エラーが消えています。
ハードウェアを完成させる
以上で、PS部だけを持つブロックデザインが完成。Hello Worldのためには、CPUとUARTだけあればいいので、今回はこれで十分です。このブロックデザインを、最上位デザインとして使います。まず、出力ファイルを生成してソースファイルを作成します。次に、HDLラッパーを作成して全体のデザインフローで使えるようにします。
具体的には、"BLOCK DESIGN" -> "Sources"タブ上で、今回のデザイン("design_1")で右クリック
- Generate Output Products -> Generate
- Create HDL Wrapper -> OK
1のGenerate Output Productsによって、verilogソースコードが生成されます。2のCreate HDL Wrapperによって最上位HDLファイルが生成されます。これに依って、最上位がdesign_1_wrapper.vとなり、その下にdesign_1.vが来ます。以下のように、Sourcesタブ内で上下関係やソースの中身を確認することが出来ます。
また、ProjectSummaryを見ると、自動的にTop module nameが、今生成したdesign_1_wrapperになっていることが分かります。
ハードウェアをエクスポートする
ハードウェアが完成したので、これをエクスポートします。ビットストリーム(*.bit)というファイルが出力結果になります。左側のFlow Navigator -> PROGRAM AND DEBUG -> Generate Bitstreamをクリックします。これによって、論理合成&配置配線が行われてビットストリームファイルが生成されます。生成には少し時間がかかります。完了後、ポップアップウィンドウが出ます。生成結果のレポート等を見たければ、ここで選んでください。特に不要ならCancel。成果物はproject_1\project_1.runs\impl_1\design_1_wrapper.bitに保存されます。
生成したビットストリームを、ソフトウェア(Xilinx SDK)で使いやすいようにエクスポートします。メニューバー -> File -> Export -> Export Hardware。Include bitstreamにチェックをつけて、OK
その結果、project_1\project_1.sdkというフォルダと、その下にdesign_1_wrapper.hdfファイルが生成されます。これがハードウェア側の成果物であり、次にやるソフトウェア実装へのインプットになります。project_1\project_1.sdkフォルダがそのままXilinx SDK (EclipseベースのIDE)のワークスペースになります。design_1_wrapper.hdfにはメモリマップ情報などとビットストリームファイルが含まれています。
ソフトウェアを実装する (Xilinx SDK)
Xilinx SDKの起動
Vivado上のメニューバー -> File -> Launch SDK -> OKで、今までVivadoで作成したハードウェア用のソフトウェア開発環境が立ち上がります。具体的には、自動的にXilinx SDKが立ち上がり、hw_platformフォルダが作られる。hw_platformフォルダにビットストリームファイルのコピー、PSに必要なクロック設定等を行うCソースコード生成が行われます。hw_platformフォルダが、対象となるハードウェア(先ほど作成したハードウェア)の情報をまとめたフォルダになります。
プロジェクト作成
SDK上のメニューバー -> New -> Application Project で、新しいソフトウェアプロジェクトを作ります。ここから先は、通常のマイコン用ソフト開発と同じです。以下の設定でプロジェクトを作ります。
- プロジェクト名: HelloWorld
- OS: なし
- ハードウェア: 先ほどVivadoで作ったハードウェア (design_1_wrapper_hw_platform_0)
- 動作CPU: CPU0
- 言語: C言語
HelloWorldというフォルダと、HelloWorld_bspというフォルダが作られます。HelloWorldがこれからメインで実装していくところになります。HelloWorld_bspが、今回使用するハードウェア(ボード)用のライブラリ群になります。UARTを使用したprint関数等が含まれています。
ソースコード
Hello WorldをUARTから出力するコードを書きます。が、実は、自動生成されたソースコード上で既に以下のように実装されています。なので、そのままでOKです。
int main()
{
init_platform();
print("Hello World\n\r");
cleanup_platform();
return 0;
}
実行する
ボードの準備
ZYBOのボード上でJP5のジャンパ接続を変えてJTAGの所をショートさせます(デフォルトはQSPI)。これによって、今回作成したハードウェアをJTAG(USB)経由で書き込めます。ボード上のマイクロUSB端子(J12)にUSBケーブルを刺して、PCと接続します。電源ONします。
PC側で、適当なターミナルソフト(例えばTera Term)を起動して、USB Serial Portに接続します。ボーレートは115200にします。
ハードウェア情報を書き込む
まず最初に、ハードウェア情報(ビットストリームファイル)を書き込みます。メニューバー -> Xilinx -> Program FPGAで、以下のウィンドウが表示されるので、Program。これによって、ZYBOは先ほどVivadoで作成したとおりのハードウェア構成になりました。これは、電源をOFFにするまで保たれます。電源をOFF/ONしたりリセットしたら、再度書き込みが必要になります。
プログラムを実行する
ここまで来たら、通常のマイコンと同じです。Project Explorer上でHelloWorldプロジェクトを選択しておきます。
- 実行: メニューバー -> Run As -> Launch on Hardware (System Debugger)、または再生ボタン
- デバッグ: メニューバー -> Debug As -> Launch on Hardware (System Debugger)、または虫ボタン
実行すると、ターミナル上にHello World
と表示されれば成功です。
ハードウェアの変更を反映する
Xilinx SDK上で既にプロジェクトを作成して、ソフト開発を進めている最中に、ハードウェア側(hdfファイル)を変更したとします。その変更をSDKにも反映する必要があります。試しに、UARTのボーレートを115200から9600に変えてみます。
ハードウェアを変更してみる
再びVivadoに戻って、design_1のブロックデザインを開きます。DiagramビューでPSをダブルクリックして、プロパティ画面を開きます。以下のように、UART1のボーレートを9600に変更してみます。
その後、Generate Output Products、Create HDL Wrapper、Generate Bitstream、Export Hardware(include bitstream)します。
SDKに戻る
すると、SDK側の画面に以下のようなウィンドウが表示されて、自動で更新してくれます。
おまけ: 自分でSDKプロジェクトを作る (Xilinx SDK)
ハードウェア屋さんの成果物
趣味でやる場合には自分でハードもソフトもやると思います。その場合には、Vivadoから自分で直接SDKを起動できます。しかし、業務だったりチーム開発の場合にはどうでしょうか。Vivado全体のプロジェクトファイルをソフト/ハード同じところでソース管理していたり、同じパソコンで交互に開発している場合には、問題ないと思いますが、現実的ではないと思います。(もしかしたら、ソース管理共通化はできるかもしれないが、実際の開発現場だとどうしてるんだろう??) 個人的には、ハードウェア屋さんの成果物であるhdfファイルを界面にやり取りするのがいいのかなと思います。
この場合、ソフト屋さんは自分でSDKのプロジェクトを作る必要があります。以後、design_1_wrapper.hdfをインプットとして話を進めます。このファイルはハード屋さんがVivadoで作った成果物です。
hw_platformを作る
Xilinx SDKをスタートメニューから単独で起動する。ワークスペースを適当に設定する。SDK上のメニューバー -> File -> New -> Board Support Packageで、以下のようにhdfファイルを指定する。プロジェクト名は自動的に決まるのでそのまま。これによって、hw_platformフォルダが作られます。これは、先ほどVivadoからLaunch SDKした場合の自動生成と同じになります。
引き続き、BSPの設定をするウィンドウが現れます。BSPはここで作ってもいいのですが、先ほどやったように、Application Projectを作るときにも自動生成できるので、ここではCancelしておきます。ここまで来たら、先ほどのVivadoからLaunch SDKした場合と同じです。好きなようにApplication Projectを作成して実装してください。
ハードウェアの変更を反映する
先ほどと同様に、SDK側でソフト開発中に、ハードウェア(hdf)が更新されたら、その反映をする必要があります。新しいhdfをdesign_1_wrapper_new.hdfとします。
Xilinx SDK内で、Project Explorer上で既に作成済みのhw_platformプロジェクトを右クリックして、"Change Hardware Platform Specification"を選びます。design_1_wrapper_new.hdfを選択します。すると、hw_platformとbspプロジェクトも更新されます。
おまけ2
Xilinx SDKを起動したらまず、Project -> Build Automaticallyのチェックを外しておくと良いと思います。
おまけ3
今回、Vivado上でハードウェアを作成しました。しかし、配置したのはPSだけで、PLに相当する部品は何も配置していません。そのため、実はビットストリームは書き込まないでも動きます。ただしその場合、実行/Debug開始するときに、FPGA書き込みが完了してない(DONE pin is not high)と注意されます。無視してOKです。ちなみに、PSに関する設定はビットストリームファイルではなく、hdfに保存されているようです。
参考資料
https://www.xilinx.com/support/documentation/sw_manuals_j/xilinx2013_4/ug898-vivado-embedded-design.pdf
https://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2015_2/ug1165-zynq-embedded-design-tutorial.pdf