Zynqでプログラミング(1) - Hello World -

# この記事について
Zynqのプログラミングを行うとき、ユーザーガイドを見たり、Googleで検索する。
でも実際に必要な情報はあまり見つからない。
さらにXILINX公式のフォーラムも、解決に至っていない投稿ばかり…
そこで、私の知識をメモ代わりに投稿する。また、シリーズで紹介しようと思う。
(私はプログラミング初心者のため、初心者向けの記事になると思う。)


# まず、Zynqって何？
これは、Qiitaでもよく記事にされているのでさらっと紹介。

* Zynq
 * XILINX社がリリースしている、PS(Processing System)部とばれるCPUと、PL(Programmable Logic)部と呼ばれるFPGAがセットになったSoC(System on Chip)デバイスのこと。
 * この記事では、開発の方針としてPS部は**C言語**、PL部は**VHDL**を使用。

* Vivado
XILINXが提供しているZynq開発用ツール(無償ライセンス有)。


# 開発環境

## 開発用PC
* Windows10 64bit
* メモリ：32GB
* SSD：512GB

## 使用する評価ボード
ZYBO Z7-20
参考サイト：[XILINX公式 ZYBO Z7-20](https://japan.xilinx.com/products/boards-and-kits/1-pukio3.html)


## ツールのインストール
* Vivado(私は2018.2を使用)
XILINXの開発環境であるVivadoとSDKをインストールする。
こちらも、よく記事にされているのでそちらを参照。
参考サイト：[ZYBO (Zynq) 初心者ガイド (1) 開発環境の準備](https://qiita.com/iwatake2222/items/966f252f6ca954aff08b)
※ZYBO Z7-20のボードファイルのコピペを忘れないようにすること！

* TeraTerm(私はver4.90を使用)
フリーのターミナルソフト。シリアル通信によるデバッグに使用する。

# Hello Worldを画面表示
HelloWorldの表示は、(上記サイトなど)多くのサイトで取り上げられているが、最初のため細かく説明する。

## 1.　プロジェクトの作成
Vivadoでプロジェクトを作成する。Vivadoを開いて「Create Project」を選択。
![fig1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/588f814a-1cc0-d79a-6e53-15df7fa9c532.png)
開かれたウィンドウを順番に設定していく。
![fig2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/fc5c6494-82b0-c02b-5c8f-9fa84270543f.png)
「Project name」と「Project location」を設定する。
![fig3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/d2ec9dad-9c5d-c6af-ad9d-9c8b74b25943.png)
「RTL Project」を選択する。
![fig4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/fa08cd60-1e9e-39fc-af8b-94be62a68c72.png)
「Target Language」は「VHDL」とする。
![fig5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/944a140b-b134-a07c-7461-36ba7d2b392f.png)
「Add Constraints」は特に設定しなくてよい。
![fig6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/ab8a428e-aa13-0624-66a4-dda3d6a89904.png)
「Board」タブで「Zybo Z7-20」を選択する。
![fig7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/b92d7ff1-6355-92ef-d9d3-ab09710b3a28.png)
内容を確認し、問題なければ「Finish」。
![fig8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/8e541a91-2821-5cec-f94a-5cce57542c05.png)

## 2.　ブロックデザインの作成
プロジェクトが作成されると、↓のような画面が出てくる。「Create Block Design」を選択してブロックデザインを作成する。
![fig9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/c70cff89-c9cb-d578-3358-78501cf3207b.png)
ウィンドウが開かれるため、「Design name」を設定して「OK」。(ここでは「design_1」(デフォルトのまま)とした。)
![fig10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/43d55f46-88d8-0828-9569-9bb04e156f46.png)
「Diagram」タブで右クリックし、「Add IP」を選択することでIPコアを追加する。
「ZYNQ7 Processing System」を選択する。これがPS部のIPコア。「PS部のIP」と呼ぶことにする。
IPコアは、FPGAの機能をひとまとまりにしたもので、ブロックデザインはIPコアをグラフィカルに線で接続して設計する。
今回はPS部の機能しか使わないのでとりあえずこれだけでOK。
![fig11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/fddb5b0c-2b5f-2de8-b8d7-441b611cf615.png)
「Run Block Automation」ではPS部のIPをZYBO Z7-20向けに設定を変更してくれる。
![fig12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/e038eca4-8350-b3f4-2e0c-544c17bf3c50.png)
特になにもせず、「OK」。
![fig13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/be00cb14-5095-acba-04b9-8bbbb36f863e.png)
すると、PS部のIPからDDRメモリとIOへのバスが追加された。
「FCLK_CLK0」から線を出して「M_AXL_GPO_ACLK」に接続する。これでブロックデザインは完成。簡単だ。

* 赤枠の「Validate Design」では、ブロックデザインのチェックができる。
* 青枠の「Regenerate Layout」では、IPを自動できれいに配置させてくれる。
![fig14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/0b526ae4-f552-a11c-0a4d-ba1c1ba9530e.png)

「Source」タブの「Design Sources」＞「design_1(design_1.bd)」を右クリックして「Create HDL Wrapper」を選択し、wrapper(ラッパー)ファイルを作成する。
![fig15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/c6780b5e-817b-b4e8-57ec-376448be68c0.png)

## 3.　論理合成～ビットストリーム生成まで
wrapperファイルができたら、論理合成、配置配線、ビットストリームの生成を行う。これらを一気に実行するには、右下の「Generate Bitstream」を選択する。
「No Imolementation Result Available」ウィンドウが表示さるが、「配置配線してないよ！論理合成と配置配線もセットでやるよ？」とのことなので「Yes」を選択する。
![fig17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/e9600284-faa7-2e4d-8eff-001ca287fc96.png)
「Launch Runs」ウィンドウが表示されるが、そのまま「OK」でよい。
![fig18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/23707e21-7045-4019-8a57-6b91f005ee33.png)
「Bitstream Generation Complete」ウィンドウが表示されれば、論理合成、配置配線、ビットストリームの生成が完了。
このウィンドウは「Cancel」で閉じる。
![fig19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/f5a11375-306d-84c5-49b8-f8ce62f8edc3.png)


## 4.　SDKの起動
Vivadoのメニュー「File」＞「Export」＞「Export Hardware」より、hdf(ハンドオフ)ファイルをSDKのフォルダにエクスポートする。
![fig20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/57ff2120-b8ca-3951-710b-516013f71248.png)
「Export Hardware」ウィンドウが表示されるので、「Include bitstream」にチェックを入れて「OK」。
これでプロジェクトフォルダに、「helloworld(プロジェクト名).sdk」が作られ、ファルダ内にhdfファイルが作られる。このhdfファイルにはbitファイルが含まれている。
![fig21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/8d33f89f-bcd3-5524-8903-b48f462ef96b.png)
Vivadoのメニュー「File」＞「launch SDK」よりSDKを起動する。「launch SDK」ウィンドウも「OK」で良い。
![fig22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/70abca26-2c41-cc01-000e-7ff783a0fcb5.png)


## 5.　アプリケーションの作成
SDKが開いたら、まずアプリケーションプロジェクトを作成する。
SDKのメニュー「File」＞「New」＞「Application Project」を選択する。
![fig23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/2b643eda-cf97-8ef0-686b-f81b39ef81a9.png)
「Project name」を設定する。(ここでは、「hello_app」とした。)それ以外は、デフォルトのまま「Next」。
![fig24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/4bec7101-e09f-4ae4-d31d-f7e6123d9cc2.png)
「Hello World」を選択すると、HelloWorldを表示するソースコードが自動で作られる。
![fig25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/9875c2cc-4561-0f1a-3281-a13225e1f3af.png)
「Project Explorer」の「hello_app」＞「src」＞「helloworld.c」が、ソースコード。

* hello_app ： アプリケーションプロジェクト
* hello_app_bsp ： hello_appのBSP(ボードサポートパッケージ)

![fig26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/c58d6ca9-aab4-2aeb-9271-a6f88e8a9bfe.png)

```c:helloworld.c
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"


int main()
{
    init_platform();

    print("Hello World\n\r");

    cleanup_platform();
    return 0;
}
```

## 6.　アプリケーションの実行
アプリケーションを実行するために、まずZYBO Z7-20をPCに接続しておく。
1. ZYBO基板上のジャンパJP5の「JTAG」をショート
2. ZYBO基板電源近くのJ12(microUSB)とPCをケーブルで接続
3. ZYBOの電源を投入
4. TeraTermを起動し、ポート番号(私の場合はCOM9)とボーレート(115200)を合わせ接続
![fig27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/7b0218ee-2bdc-2197-d1d2-89b35638f088.png)
SDKに戻り、「Program FPGA」よりFPGAをZynqに焼きこむ。
![fig28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/e1f1ac60-88e1-f01f-43fd-2aaaf4ab3bbd.png)
「Program FPGA」ウィンドウが表示されるが、そのまま「Program」。
すると、ZYBOのDONE(LD12)緑LEDが点灯する。これでFPGAの焼きこみはOK。
![fig29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/bf15af3d-cef6-5ccf-adff-1efd035f3342.png)
今回はデバッグモードでアプリケーションを実行する。
「hello_app」＞「Debug As」＞「Debug Configurations...」を選択。
![fig30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/9c8c92a0-7233-c1a2-7f31-11d5781a5632.png)
「Xilinx C/C++ Apptication(GDB)」を右クリックして、「New」を選択。
![fig31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/23dbd4e4-837a-5270-caf0-240e0848b12f.png)
ウィンドウが変わり、bit、tclファイル、elfファイル等の確認ができる。これで「Debug」。
![fig32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/55436fb2-2748-e64a-1db0-e54855484fb4.png)
すると、↓のようなウィンドウが表示されるが「OK」で良い。
![fig33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/86559290-aedf-85ba-b6b0-a4e0d8e2058b.png)
ウィンドウが変わり、Runを選択するとアプリケーションが実行される。
![fig34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/4103a8b8-0ec3-1c7c-fb87-df0a60887bd0.png)
TeraTermを確認すると、「Hello World」が表示されている。これで終了！
![fig35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/784284df-4711-66d9-e2da-0f5aff4a3344.png)

プロジェクト作成から、アプリケーション実行までの流れは以上のような感じである。

## 補足.　2回目以降の実行
2回目以降の実行は、↓のようにSDKウィンドウのRunの右の▼から実行するアプリを選べば、実行できる。
![fig36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512428/02ccb89f-4045-8a7c-8a61-4a627d5119cd.png)


# SDKのエラーやbitファイル再生成時は・・・
* SDKのエラーが突然出た(「ライブラリが参照できない」など)
一度SDKを終了して、Vivadoからもう一度SDKを起動するとエラーがなくなることがある。

* bitファイルを生成しなおす場合
一度Vivadoプロジェクトの「プロジェクト名.sdk」のフォルダを全て削除してからbitファイルを再生成する。
その後、もう一度SDKをVivadoから起動し、アプリケーションプロジェクトも再生成する。
(本当にこの方法しかないのだろうか・・・かなり面倒・・・)

* Vivado 2019.2
Vivado 2019.2以降は、SDKのツールがなくなり、Vitisというものになったようだ。
(この記事を書く意味とは・・・)