ZYBO (Zynq) 初心者ガイド (2) Hello Worldプロジェクト

- [1回目: 開発環境の準備](https://qiita.com/take-iwiw/items/966f252f6ca954aff08b)
- __[2回目: Hello Worldプロジェクト](https://qiita.com/take-iwiw/items/24a8a94741fdbb80f62a) <--- 今回の内容__
- [3回目: PSのGPIOでLチカ](https://qiita.com/take-iwiw/items/39d2ed00fa88a1204fce)
- [4回目: PLのAXI GPIOでPSからLチカ](https://qiita.com/take-iwiw/items/a3b935a4e4dbd41593e1)
- [5回目: PLだけでLチカ](https://qiita.com/take-iwiw/items/efcdfca1866b9941fd2a)
- [6回目: 自作IPでLチカ](https://qiita.com/take-iwiw/items/b0f2ce7b4653bc6f32b9)
- [7回目: ブートイメージを作る](https://qiita.com/take-iwiw/items/ece0cdf83e6e1908fad8)
- [8回目: Linux起動する](https://qiita.com/take-iwiw/items/6e6915f7318689818368)
- [9回目: Linuxカーネルを少しカスタマイズする](https://qiita.com/take-iwiw/items/6f2644d16cbfdb021d07)
- [10回目: LinuxのRootFSをカスタマイズする / PythonでHello World](https://qiita.com/take-iwiw/items/94a90047978664159681)
- [11回目: LinuxユーザアプリケーションでLチカ](https://qiita.com/take-iwiw/items/5e4ab9a106acfda2c866)
- [12回目: LinuxカーネルモジュールでLチカ](https://qiita.com/take-iwiw/items/e7efc48d92d7b979efdc)
- [13回目: LAN(Ethernet 0)を使う](https://qiita.com/take-iwiw/items/ac489acaca1ab54d7ce8)
- [14回目: Linuxユーザアプリをデバッグする / RootFSに取り込む](https://qiita.com/take-iwiw/items/8134ca7098622219b177)
- [15回目: Linux起動時にアプリケーションを自動実行させる](https://qiita.com/take-iwiw/items/50065df6cdd1ba8bcbd6)
- [16回目: Linuxから自作IPをUIOで制御する](https://qiita.com/take-iwiw/items/da91ce4dc2a8a8df3c0a)
- [17回目: Linuxで自作IPのデバイスドライバを作る](https://qiita.com/take-iwiw/items/05eb1204cb51ce0a5c03)
- [18回目: IoT化してスマホからLチカ](https://qiita.com/take-iwiw/items/e9311292c5078d785699)

この記事の内容を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回目](https://qiita.com/take-iwiw/items/966f252f6ca954aff08b)を参照。

# 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をクリックしてプロジェクト作成完了です。使用しているボードが違う場合には、適宜置き換えてください。

![01.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/19310b03-baa5-4234-fcef-824dec96f3e6.jpeg)
![02.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/dc9e1c7d-268c-e97d-031c-92a6dea1020b.jpeg)
![03.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/3313fe2a-a6a6-ee78-5ba8-a546a4fb9562.jpeg)

無事プロジェクトが作成されると、以下のような画面になります。

![04.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/d4f1f91b-c58f-ef12-3d51-913c1750da74.jpeg)

# 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とします。

![05.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/e99f81a6-7304-29e9-1d4b-fd0b1702b4be.jpeg)

Diagramビューの"Press the + button to add IP"をクリックして、"ZYNQ7 Processing System"を選択します。すると、PS部が配置されます。そして、画面上の"Run Block Automation"をクリックします。設定Window画面が出ますが、「Apply Board Preset」にチェックがついていることを確認してOKしてください。これによって、プロジェクト作成時に指定したボード(ZYBO)に適したPSが作られて、配置されます。

![06.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/5764909b-e536-f8f4-663b-8ea54d8d126f.jpeg)
![07.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/cd6601a1-b9e1-7f3f-4aaa-0ee9163584db.jpeg)

PS部のプロパティ変更もできます。"Block Properties"の所から変更が出来ます。又は、DiagramビューでPSをダブルクリックすることでも、PSをカスタマイズできます。今回は、何も変更しません。このPSは既にZYBOボードに適した設定になっているためです。例えば、ターミナル出力に使うUART1用のIOは複数の候補から選択することが出来ますが、実際にボード上で接続されているのは、MIO48とMIO49です。今作ったPSもUART1はMIO48とMIO49を使うように設定されています。

設定は変更しませんが、どのようなことが出来るか見てみます。 
PS部のオーバービューを見たり
![08.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/f7f78c67-12e6-8698-ee0a-0df35a5204b7.jpeg)

各種コンフィギュレーションをしたり (例えば、UARTのボーレート変更)
![09.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/c83a9860-3328-81cf-9e69-bb1de08f8f13.jpeg)

ペリフェラル用のIOとして、どのピンを使うかの設定をしたり (MIO(Multiplexed IO)というピンから選ぶ。マイコンによくある、どの機能にするかを選ぶMUXみたいな感じ)
![10.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/4779e475-1971-5dc1-b677-13f2193bf85d.jpeg)

## 作成したブロックデザインをチェックする
PSを配置しただけですが、とにかくブロックデザインを作ってみました。これが問題ないかどうかをチェックします。Diagramビュー上で右クリック -> Validate Designを選ぶことで、チェックできます。すると、こんなシンプルなデザインなのに、なんとエラーが出ていました。M_AXI_GP0_ACLKにクロックが正しく供給されていないのが原因のようです。

![10_1.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/d4d145ee-8b41-1358-9fc3-fac6b3bc1d83.jpeg)

## ブロックデザインを修正する
AXIはIP間を接続するときに使うバスです。PSがマスターとなって、他のスレーブIP(例えば、AXI GPIO)と接続するときに使います。M_AXI_GP0_ACLKはその基になるクロックです。そのため、今回は使わないので、AXI_GP0のマスター機能そのものをOFFにすることでも修正可能です。しかし、どうせそのうち使うので、今回はちゃんとクロックを供給設定してあげることで修正します。ちょうど、PSからFCLK_CLK0というポートが出ています。この設定を見ると、50MHzの出力のようです。周波数などは変更可能ですが、今回はデフォルトのまま使います。

![10_2.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/4783e208-a485-f3a6-6353-8303a2eff78e.jpeg)

このFCLK_CLK0とM_AXI_GP0_ACLKを接続してあげます。Diagramビュー上でPSのピンの近くにマウスカーソルを持っていくと鉛筆アイコンになるので、そのままドラッグして接続するだけです。

![10_3.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/fb3a0abd-29c5-0289-d442-f5ad9130b6b1.jpeg)

この状態で再度Validate Designすると、エラーが消えています。


## ハードウェアを完成させる
以上で、PS部だけを持つブロックデザインが完成。Hello Worldのためには、CPUとUARTだけあればいいので、今回はこれで十分です。このブロックデザインを、最上位デザインとして使います。まず、出力ファイルを生成してソースファイルを作成します。次に、HDLラッパーを作成して全体のデザインフローで使えるようにします。

具体的には、"BLOCK DESIGN" -> "Sources"タブ上で、今回のデザイン("design_1")で右クリック

1. Generate Output Products -> Generate
2. Create HDL Wrapper -> OK

![11.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/f105ea7a-aaf2-cbc2-14c7-f7c4b798c338.jpeg)

1のGenerate Output Productsによって、verilogソースコードが生成されます。2のCreate HDL Wrapperによって最上位HDLファイルが生成されます。これに依って、最上位がdesign_1_wrapper.vとなり、その下にdesign_1.vが来ます。以下のように、Sourcesタブ内で上下関係やソースの中身を確認することが出来ます。

![12.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/9471cc30-4287-8712-60c8-266f3f2d8b0a.jpeg)

また、ProjectSummaryを見ると、自動的にTop module nameが、今生成したdesign_1_wrapperになっていることが分かります。

![13.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/7f8e2dbf-83da-b22e-48b1-4000e8a2258b.jpeg)

## ハードウェアをエクスポートする
ハードウェアが完成したので、これをエクスポートします。ビットストリーム(*.bit)というファイルが出力結果になります。左側のFlow Navigator -> PROGRAM AND DEBUG -> Generate Bitstreamをクリックします。これによって、論理合成&配置配線が行われてビットストリームファイルが生成されます。生成には少し時間がかかります。完了後、ポップアップウィンドウが出ます。生成結果のレポート等を見たければ、ここで選んでください。特に不要ならCancel。成果物はproject_1\project_1.runs\impl_1\design_1_wrapper.bitに保存されます。

![14.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/b64e35f3-a227-c206-5b0d-6e3e0483a144.jpeg)

生成したビットストリームを、ソフトウェア(Xilinx SDK)で使いやすいようにエクスポートします。メニューバー -> File -> Export -> Export Hardware。__Include bitstreamにチェックをつけて__、OK

![15.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/5fa83ba0-337e-aa35-427c-257268175c6a.jpeg)

その結果、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言語

![16.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/15c3081b-c5df-4a68-357d-7323e628c284.jpeg)

HelloWorldというフォルダと、HelloWorld_bspというフォルダが作られます。HelloWorldがこれからメインで実装していくところになります。HelloWorld_bspが、今回使用するハードウェア(ボード)用のライブラリ群になります。UARTを使用したprint関数等が含まれています。

![17.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/3029e85d-2f8e-b2cd-8277-9542dbe7fa10.jpeg)

## ソースコード
Hello WorldをUARTから出力するコードを書きます。が、実は、自動生成されたソースコード上で既に以下のように実装されています。なので、そのままでOKです。

```c:helloworld.c
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にします。

![18.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/66a94cc2-e440-106d-9c48-0bf983bf51a5.jpeg)

## ハードウェア情報を書き込む
まず最初に、ハードウェア情報(ビットストリームファイル)を書き込みます。メニューバー -> Xilinx -> Program FPGAで、以下のウィンドウが表示されるので、Program。これによって、ZYBOは先ほどVivadoで作成したとおりのハードウェア構成になりました。これは、電源をOFFにするまで保たれます。電源をOFF/ONしたりリセットしたら、再度書き込みが必要になります。

![19.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/a2fa8bea-6cce-8aff-a1b7-8bb6b526418c.jpeg)

## プログラムを実行する
ここまで来たら、通常のマイコンと同じです。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に変更してみます。

![30.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/9373dafd-d1e7-bea9-abb6-132fa5056c9a.jpeg)

その後、Generate Output Products、Create HDL Wrapper、Generate Bitstream、Export Hardware(include bitstream)します。 

## SDKに戻る
すると、SDK側の画面に以下のようなウィンドウが表示されて、自動で更新してくれます。

![31.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/64f88dab-9f21-bc2d-c30f-5b3d2ec330d8.jpeg)

# おまけ: 自分で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した場合の自動生成と同じになります。

![20.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/e6ff6e21-f1a1-9edd-a50c-8f2e22faa97f.jpeg)

引き続き、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プロジェクトも更新されます。

![32.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/c6a48aeb-481c-b7aa-88bc-276ea9175830.jpeg)

# おまけ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