ZYBO (Zynq) 初心者ガイド (14) Linuxユーザアプリをデバッグする / rootfsに取り込む

- [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)

この記事の内容を5分で見る ( https://youtu.be/n2yYwEIjD2Y の後半)

# 環境
- 開発用PC: Windows 10 64-bit 
	- Vivado 2017.4 WebPACKライセンス
	- Xilinx SDK 2017.4
- 開発用PC (Linux): Ubuntu 16.04 本家 (日本語版じゃない) (on VirtualBox 5.2.4)
	- PetaLinux 2017.4
- ターゲットボード: ZYBO (Z7-20) 

# Linuxユーザアプリをデバッグする / rootfsに取り込む
[11回目](https://qiita.com/take-iwiw/items/5e4ab9a106acfda2c866)で、LチカするLinuxユーザアプリケーションを作りましたが、動かすためには毎回image.ubを作る必要があり、開発効率が悪いものでした。[前回](https://qiita.com/take-iwiw/items/ac489acaca1ab54d7ce8)、ZYBOのLANが使えるようになり、開発用PCとネットワーク接続ができるようになりました。今回は、ネットワーク越しにTCFという機能を使用して、Linuxユーザアプリケーションをデバッグしてみようと思います。

開発の流れは、以下の通りです。

- ベースとなるLinuxイメージ(BOOT.bin、image.ub)の作成 (PetaLinux on Ubuntu)
- Linuxユーザアプリケーションの開発(実装、ビルド、デバッグ) (Xilinx SDK on Windows)
- 開発したアプリケーションを含むrootfs(image.ub)の再作成 (PetaLinux on Ubuntu)

_つまり、Linuxユーザアプリケーションの開発自体はWindows PCだけでできます！_

## TCFとは
TCF (Target Communication Framework)とは、デバッグ機能に加えて、リモートファイルアクセスやシェルアクセス機能を提供してくれるフレームワークです。実際に僕たちが使うのは、Xilinx System Debuggerになります。この、Xilinx System DebuggerがTCFを使用しています。

![01.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/6167df18-835d-5026-0b37-5619299cf6be.jpeg)
https://www.xilinx.com/video/soc/debug-linux-application-using-xilinx-sdk.html

# LANを有効にしたハードウェアを作る
TCFを使うためには、ターゲット(ZYBO)と開発用PC(Windows)がネットワーク接続されている必要があります。[前回](https://qiita.com/take-iwiw/items/ac489acaca1ab54d7ce8)の内容を参考に、ETH0のMDIO接続を修正した、PSだけを配置したハードウェアを作成して、hdfファイルをエクスポートします。

作成したhdfファイル(`project_1.sdk/design_1_wrapper.hdf`)は、PetaLinuxで使うので、Ubuntu側にフォルダごとコピーしておきます。(もしかしたら、Xilinx SDKでhardware_platformを作るのに必要かもしれない。今回は不要)

# ベースとなるLinuxイメージを作る
いつも通り、全てデフォルトのまま作ればOKです。なんの編集もいりません。SimplePSというプロジェクトを作る場合のコマンド一式です。

```sh:開発用PCのターミナル
cd ~/work/peta
petalinux-create --type project --template zynq --name SimplePS
cd SimplePS/
petalinux-config --get-hw-description=../project_1.sdk
petalinux-build
petalinux-package --boot --force --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/design_1_wrapper.bit --u-boot
```

## TCFが有効になっているか確認する (見るだけ)
↑で既にビルド完了しているので、順番が前後してしまいますが、ちゃんとTCFが有効になっていることを確認します(デフォルトで有効になっているはずです)。`petalinux-config -c rootfs`でrootfSの設定を確認します。Filesystem Packages -> misc -> tcf-agent -> tcf-agentにチェックがついていることを確認してください。、

![02.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/ee71b617-72cf-4a4e-c31b-ad79e4ec4c62.jpeg)

### ノート
ug1144-petalinux-tools-reference-guide.pdfによると、console/network -> dropbear -> dropbear-openssh-sftp-serverも必要らしいです。が、デフォルトでOFFでしたし、OFFのままでも問題ありませんでした。何か問題があれば試してみてください。


## Linux起動する
作成したBOOT.binとimage.ubをSDカードにコピーして、ZYBOを起動します。Linuxが起動して、開発用PCとネットワーク接続できていること(pingやssh接続)を確認してください。また、ZYBO上で`ifconfig`して、IPアドレスを確認しておいてください。今回は、ZYBOのIPアドレス=192.168.1.87として、説明を続けます。

ここまでの手順は、基本的には[前回](https://qiita.com/take-iwiw/items/ac489acaca1ab54d7ce8)と同じです。

# Linuxユーザアプリケーションを開発する
_この作業は全てWindows上でできます。Ubuntuは不要です。_

## プロジェクトを作る
Xilinx SDKを起動します。メニューバー -> File -> New -> Application Projectを開きます。今回は、Lチカをするアプリケーションを作るので、Project nameはblinkとします。OS Platformはlinuxとし、Processor Typeはps7_cortexa9。Linux System RootとLinux Toolchainは未選択でOKです。

![03.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/b2549b2b-8f75-bfc3-2299-1a1e7f2f1a21.jpeg)

### ノート
https://www.xilinx.com/video/soc/debug-linux-application-using-xilinx-sdk.html やug1144-petalinux-tools-reference-guide.pdfの説明だと、hdfからhardware_platformを作る必要があるようでしたが、無くても大丈夫でした。

## 実装する
helloworld.cというテンプレートファイルが作られているので、今回はこれをそのまま使います。[11回目](https://qiita.com/take-iwiw/items/5e4ab9a106acfda2c866)と同様に、以下のコードを貼り付けます。これは、PSのGPIO913 (MIO7)を使用して、LED(LD4)を1秒間隔でチカチカさせるプログラムです。

ハンマーボタンをクリックしてビルドしておきます。

```c:helloworld.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>

int main(int argc, char **argv)
{
    printf("Hello World!\n");

    int fd;

    /* 1. GPIO913を使用可能にする */
    fd = open("/sys/class/gpio/export", O_WRONLY);
    write(fd, "913", 3);
    close(fd);

    /* 2. GPIO913を出力設定する */
    fd = open("/sys/class/gpio/gpio913/direction", O_WRONLY);
    write(fd, "out", 3);
    close(fd);

    /* 3. GPIO913に1(High)を出力する */
    fd = open("/sys/class/gpio/gpio913/value", O_WRONLY);
    write(fd, "1", 1);

    while(1) {
        write(fd, "0", 1);
        usleep(1*1000*1000);
        write(fd, "1", 1);
        usleep(1*1000*1000);
    }

    /* 4. 使い終わったので閉じる */
    close(fd);

    return 0;
}
```

### インクルードファイルの設定
__これは、やらなくても問題ありません。また、もしかしたら間違えているかもしれません__
(後述の方法の方が正しいかも)

ビルド自体は、既に通っているのですが、エディタがヘッダファイルを見つけられていません。気持ち悪いし、定義にジャンプも使えないのが不便なので、インクルードパスを追加しておきます。Project Explorer -> blink(プロジェクト名) -> 右クリック -> Properties -> C/C++ General -> Paths and Symbolsを選び、IncludesのGNU Cに、`C:\Xilinx\SDK\2017.4\gnu\aarch32\nt\gcc-arm-linux-gnueabi\arm-linux-gnueabihf\libc\usr\include`をAddします。

ここで間違ったパスを指定したらビルドエラーになります。指定すべきパスは、実際のビルドに使用されているのと同じパスですが、それがどこで指定されているかは見つけられませんでした。。。↑のパスだとビルドも通ったし、雰囲気もあっているっぽいので、正しいと思います。(もしかしたら、違うかも。不安だったら、この設定はやらないで大丈夫です。エディタ上で警告が出るだけです。)

![04.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/15382a71-3bd0-409a-1665-4a359681e145.jpeg)


__おそらく下記方法の方が正しい__

- PetaLinux側で、`zip -r plnx_arm.zip build/tmp/sysroots/plnx_arm`でSystem Rootを圧縮 (シンボリックリンクは実体化する)
- XSDKのあるWindows側でplnx_arm.zipを解凍
- XSDKで新規アプリケーションプロジェクト(OS Platform=linux)作成時に、Linux System Rootにチェックを付けて、C:\vivado\project_openamp\project_openamp.sdk\sysroots\plnx_armを指定

場合によっては以下も必要かも

- Project Explorer -> プロジェクト -> 右クリック -> Properties -> ARM v7 Linux gcc linker -> Miscellaneuous -> Linker Flagsに以下を追加
    - `--sysroot=C:\vivado\project_openamp\project_openamp.sdk\sysroots\plnx_arm`
- 追加ライブラリがある場合は、ARM v7 Linux gcc linker -> Libraries -> Libraries (-l)に、追加。


## ターゲット上で実行/デバッグする
メニューバー -> Run -> Debug Configurationsを開く。Xilinx C/C++ applications (System Debugger)をダブルクリック。新しいデバッグ設定が作られるので、Target SetUpタブで、`Linux Application Debug`を選び、Newをクリック。New Target Connectionを以下のように設定。

- Target Name = SimplePS (何でもいい)
- Type = Linux TCF Agent (グレーアウトされてるはず)
- Host = 192.168.1.87 (先ほど、Zybo上で確認したIPアドレス)
- Port = 1534 (変更していなければ、デフォルトのまま)

![05_2.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/69b2aee3-dd53-ba78-fc3c-44ea7e35abfd.jpeg)
![05.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/de4eb015-fdd6-82f4-0811-9d91fb3919cf.jpeg)

その後、Debugをクリックすると、デバッグが開始される(Debug Perspectiveに移行)。後は、普通にデバッグが出来ます。

![06.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/54956105-5fe8-bf33-2b8b-1069a44ad0eb.jpeg)

- メモ
	- printfの出力はUARTターミナルではなく、このXilinx SDKのDebug Perspective内のConsoleに出力される
	- "Run"でも実行できるが、実行しっぱなしになってしまうので、"Debug"の方が便利。間違えてRunしてしまったら、ターミナル上から`kill -9`する


# 作成したLinuxユーザアプリケーションをrootfsに取り込む
_この作業は、再度Ubuntu上でやります_

今回はさらっと流しましたが、実際の開発では、上述のXilinx SDKでの実装とデバッグがメインになるはずです。そして、アプリケーションの開発が完了して、リリースするときには、Linuxイメージのrootfsに取り込む必要があります。取り込む方法には、以下の2つがあります。

- ソースコードをPetaLinuxに持ってきて、PetaLinuxでビルド、rootfsに取り込む ([11回目](https://qiita.com/take-iwiw/items/5e4ab9a106acfda2c866)と同じ)
- Xilinx SDKでビルドしたバイナリ(blink.elf)をPetaLinuxに持ってきて、PetaLinuxでrootfsに取り込む

どちらも一長一短あると思います。実際の開発現場でどうやっているか不明ですが、ここでは両方のやり方を紹介しようと思います。

## ソースコードを持ってくる (Build-time Compiled Application)
PetaLinuxのプロジェクトディレクトリ(~/work/peta/SimplePS)内で、以下コマンドでblink1というユーザアプリケーションを作ります。すると、`project-spec/meta-user/recipes-apps/blink1/`にCのテンプレートプロジェクトが作られるので、`project-spec/meta-user/recipes-apps/blink1/files/blink1.c`を先ほどのコードに書き換えます。必要に応じて、他のソースコードを追加したり、Makefileを書き換えてください。

```sh:開発PCのターミナル
petalinux-create -t apps --template c --name blink1 --enable
code project-spec/meta-user/recipes-apps/blink1/files/blink1.c &
```

この後、`petalinux-build -x package`をすればよいのですが、バイナリを持ってくるバージョンもまとめて作ってしまいます。

## バイナリを持ってくる (Pre-built Application)
PetaLinuxのプロジェクトディレクトリ(~/work/peta/SimplePS)内で、以下コマンドでblink2というユーザアプリケーションを作ります。この場合は、Cアプリケーションではなく、シェルスクリプトなどを取り込む(installする)ための設定になっています。`project-spec/meta-user/recipes-apps/blink2/files/`に、Hello World的なシェルスクリプトファイル(`blink2`)が作られているので、それを消して、先ほどXilinx SDKで作成したバイナリ(`blink.elf`)をコピーします。また、`project-spec/meta-user/recipes-apps/blink2/blink2.bb`を編集して、`blink2`を`blink.elf`に置換します。

```sh:開発PCのターミナル
petalinux-create -t apps --template install --name blink2 --enable
code project-spec/meta-user/recipes-apps/blink2/blink2.bb  &
```

```txt:blink2.bb
SRC_URI = "file://blink.elf \
	"

S = "${WORKDIR}"

do_install() {
	     install -d ${D}/${bindir}
	     install -m 0755 ${S}/blink.elf ${D}/${bindir}
}
```

## rootfsを作る
下記コマンドで、image.ubを再作成します。

```sh:開発PCのターミナル
petalinux-build -x package
```

## 確認する
SDカードにimage.ubを上書きコピーしてZYBOを起動します。すると、以下のように、2パターンで作成したバイナリがどちらも`/usr/bin`にインストールされていることが分かります。blink1の方は、PetaLinux側でビルドされたバイナリです。blink.elfの方はWindowsのXilinx SDKでビルドされたバイナリです。

実行すると、Hello Worldメッセージのあとに、LEDがチカチカします。どちらも動作は同じです。

```sh:ZYBOのターミナル
root@SimplePS:~# ls /usr/bin/blink* -la
-rwxr-xr-x    1 root     root          3488 Jan 13 08:09 /usr/bin/blink.elf
-rwxr-xr-x    1 root     root          3500 Jan 13 08:09 /usr/bin/blink1
root@SimplePS:~# blink1
Hello World!

^C
root@SimplePS:~# blink.elf
Hello World!
^C
```

blink.elfの方はデバッグ情報付きのはずなのにファイルサイズが小さいのが気になります。「ソースコードを持ってくる」パターンだと、デバッグ時とリリース時で挙動が変わるリスクがあります。「バイナリを持ってくる」パターンだと、バージョン管理(今取り込んでいるアプリはどのソースで作られたのか? の追従性)に注意が必要そうです。

# 参考
https://japan.xilinx.com/video/hardware/how-to-create-linux-applications.html
https://www.xilinx.com/video/soc/debug-linux-application-using-xilinx-sdk.html
https://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2017_2/ug1144-petalinux-tools-reference-guide.pdf