OpenAMP on ZYBO (Zynq) 4回目(完): How to Debug Baremetal Firmware

- [1回目: とりあえずサンプルを動かす](https://qiita.com/take-iwiw/items/ff46792eb107d978cd0b)
- [2回目: 通信方法やメモリマップについて](https://qiita.com/take-iwiw/items/3922ec5cae6aa35c5e81)
- [3回目: How to Debug Linux Application](https://qiita.com/take-iwiw/items/8b589650c15a6f705f35)
- __[4回目: How to Debug Baremetal Firmware](https://qiita.com/take-iwiw/items/5f7c24bd0475274ded23)<--- 今回の内容__

# 本記事について
Linux + ベアメタル(or FreeRTOS)のマルチ環境を、OpenAMPを使用してZYBOで実現させました。

- CPU0: Linux
- CPU1: ベアメタル (or FreeRTOS)

1回目では、ベアメタル(BM)ファームウェアをXilinx SDKでビルドして、バイナリをPetaLinuxでインストールしました。が、実際にはデバッグ作業が必要になりますし、動作確認のために毎回Linuxイメージを作るのは大変です。そこで、今回はXSDKでBMファームウェアを開発(実装、デバッグ)します。

なお、デバッグ方法は試行錯誤の上でやっとできるようになった自己流です。色々探したけれど、ちゃんとしたやり方が見つかりませんでした。

# 環境
- 開発用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) 

# ベアメタルファームウェアを作る
ファームウェア作成までは、1回目と重複しますが、ほぼ同じ内容を載せます。作成するファームウェアはOpenAMP echo-testテンプレートのままです。出来上がるファームウェアは、Linuxから受信した内容をエコーバックして送信します。

## プロジェクトの作成
メニューバー -> File -> New -> Application Projectで、新しいプロジェクトを作成します。重要な設定は、CPU1(ps7_cortexa9_1)で動作させる点です。

- Project Name: my_image_echo_back (何でもいい)
- OS Platform: standalone
- Hardware Platform: design_1_wrapper_hw_platform_0 (Vivadoで作成したもの)
- Processor: ps7_cortexa9_1  ⇐ __重要__
- Language: C
- Templates: OpenAMP echo-test

## bspをカスタマイズする
Project Explorer -> my_image_echo_back_bspで右クリック -> Board Support Package Settingsをクリック。

![05.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/890aa5f6-4cf1-44a1-0028-f42ad7590cad.jpeg)
![06.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/d4ec25f8-5bdf-a070-aa29-a0c291c7d3a9.jpeg)

ps7_cortexa9_1を選択して、extra_compiler_flagsのValueに` -DUSE_AMP=1`を追加します。
また、openampを選択して、WITH_PROXYをfalseに設定します。これは、Remote Procedure Call (RPC)機能を使う時にはtrueにする必要があります。今回は使用しないので、falseにします。(が、別にデフォルトのままでも大丈夫なようです。コードサイズが増えるだけっぽい)

最後に、Project Explorer -> my_image_echo_back_bspで右クリック -> Re-generate BSP Sourcesをクリックします (念のため、clean buildした方がいいかも)

## 念のためリンカスクリプトを確認する
DDR領域が0x3E00_0000からになっていることを確認します。

## ファームウェアの作成
ソースコードは何も変えずに、ビルドします。(デフォルトでオートビルドになっている)
`my_image_echo_back.elf`が作成されたことを確認しておきます。

# ベアメタルファームウェアをデバッグする
## 前置き
通常のデバッグでは、デバッガがCPUにアタッチしてプログラムをロードして、CPUを開始します。が、OpenAMPの場合はそれはLinuxの役目になります。これが競合してもうまく動くように、かなり無理矢理なことをします。

## デバッグ設定
- my_image_echo_back.elfで右クリック -> Debug As -> Debug Configurations、を開きます
- `Xilinx C/C++ applications (system Debugger)`の下に、`System Debugger using Debug_my_image_echo_back.elf on Local`が無ければ、ダブルクリックして作ります
- Target Setupタブで、下記チェックを外します。これは、PSの設定自体はLinuxが行うためです
	- Run ps7_init
	- Run ps7_post_config
- ApplicationタブはデフォルトのままでOKなはずですが、念のため、下図のようになっているかを確認します
- ひとまず、Applyをクリックして、Closeします

![01.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/9a89f251-5d7e-f5a3-b365-c3f8620daa82.jpeg)
![02.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/ba68ab11-9589-c881-bc18-087c7574dc4f.jpeg)

__追記__
[コメント欄で情報をいただきました。](https://qiita.com/take-iwiw/items/5f7c24bd0475274ded23#comment-931a86a4f6fa534d4d2f)
Debug TypeをAttach to running targetに設定すれば、次節のトリッキーな操作をしないでよさそうです。

## デバッグをする
_ここからトリッキーになります_

0. SDカードからLinux起動するように、JP5はSDに設定します
1. ZYBOの電源OFF->ONをします。または、PS_RSTボタンを押します
2. その直後に(またはほぼ同時のタイミングで)、デバッグを開始します
	- my_image_echo_back.elfで右クリック -> Debug As -> Launch on Hardware (System Debugger)
	- main関数の先頭でbreakが張られて、CPU1は停止状態になります
	- `Hit any key to stop autoboot`表示されているくらいまでには開始できているといい
	- 初回は、パースペクティブの選択などでもたつくのでご注意ください
3. Linuxの起動を待ちます
	- この状態で起動したLinuxはCPU0だけで動いています。なぜなら、Linux起動時にはCPU1は停止状態だから
	- 念のため、`cat /proc/cpuinfo`などで確認しておきます
4. BMファームウェア(elfファイル)をZYBOにコピーします
	- 例えば、 elfファイルと同じフォルダ(C:\vivado\project_openamp\project_openamp.sdk\my_image_echo_back\Debug)で適当なターミナルを開きま、下記のようなコマンドでアップロードします
	- `scp  -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null my_image_echo_back.elf root@192.168.1.87:/lib/firmware/.`
	- いろいろとオプションがついているのは、sshのhost情報が毎回変わってしまい、通常通りに接続すると接続失敗するためです
5. コピーした`my_image_echo_back.elf`で、OpenAMPを開始します
	- このとき、「Linux的にはCPU1でBMをロードして実行開始したつもりだけど、実際にはCPU1はデバッガによって停止中」というのがポイントになります

	```sh:ZYBOターミナル(OpenAMP開始コマンド)
	modprobe rpmsg_user_dev_driver
	echo my_image_echo_back.elf > /sys/class/remoteproc/remoteproc0/firmware
	echo start > /sys/class/remoteproc/remoteproc0/state
	```

6. `rpmsg_read_cb`関数の先頭あたりにブレークポイントを張っておく
	- 確認用に、受信時にブレークするようにしてみます
	- これはテスト用なので、何でもいいです。やらなくてもいいです
7. XSDKで停止中のBM(CPU1)をrunする
	- 成功したら以下のようなログも出力されます
		- `Init remoteproc resource succeeded`
	- また、Linux側に下記デバイスファイルが作られます
		- `/dev/rpmsg0`
8. Linuxデモアプリを実行してみる
	- `echo_test` をLinux側のターミナルで実行します
	- すると、XSDK上で先ほどはったブレークポイントで止まって、変数やメモリを確認できます

![03.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/068e56aa-53fb-8fb1-c9f8-8557b589db44.jpeg)


- うまくいかない場合は、タイミングを変えるなど何回かトライしてみてください
- Linux起動時に待ち合わせの仕組みなどを入れるともっとスムーズにいくんだろうけど、そんな技術力はないです

# ベアメタルファームウェアとLinuxアプリケーションの両方をデバッグする
上記手順の9の所で、前回作成したLinuxアプリケーション(my_echo_test.elf)のデバッグを開始します。
2つのSystem Debuggerを走らせることが出来ます。デバッグ時にはこれらを切り替えながら作業します。(Resume/Suspendボタン等は共通なので、操作したい方のSystem Debuggerを選ぶのを忘れないようにする)

![04.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/f241bae7-6c8e-136d-e9f5-857f8a218c32.jpeg)

# (おまけ)既存プロジェクトをOpenAMP対応する
既存の非OpenAMPのベアメタルプロジェクトを、OpenAMP対応します。
既存プロジェクトは、Processor = ps7_cortexa9_1、Language = C、である必要があります。

1. Project Explorer -> 既存プロジェクト_bspで右クリック -> Board Support Package Settingsをクリック
	- Overviewの所で、下記Supported Librariesにチェック
		- llibmetal
		- openamp
	- ps7_cortexa9_1のextra_compiler_flagsに` -DUSE_AMP=1`を追加
2. Project Explorer -> 既存プロジェクト_bspで右クリック -> Re-generate BSP Sourcesをクリック
	- 念のためclean buildした方がいいかも
3. Linker Scriptを確認。DDR領域をLinux側のデバイスツリー設定と同じになるように調整します
4. 参考用にOpenAMPテンプレートのプロジェクトを作成して、ソースをコピペする

# メモ
## OpenAMPを有効にしたプロジェクトを、XSDKから直接起動/デバッグするとき
Linux経由じゃなくて、XSDKから通常のBMアプリのようにデバッグしたいときは、` -DUSE_AMP=1`を消しておく。残しておくと、vTaskDelayでフリーズした

### uart printについて
- LinuxからBMファームウェアを起動したときは、xil_printfは無効になる
    - proxyデバイスを使えば、Linux経由でUARTターミナルに出力できるらしい
- XSDKからBMファームウェアを直接起動したときは、xil_printfは使える
    - putchar, getcharは使えなかった。呼ぶと変な挙動になった(vTaskDelayでフリーズした)。XUartPs_RecvByteは使えた

__と思ったら、UARTがLinuxとBMのどっちに使われるかは、BM側で`hil_poll()`が呼ばれるタイミングに依存しているっぽい__

## 実際のところ
XSDKからOpenAMP状態のベアメタルアプリケーションのデバッグはとても面倒。
実際には、まずは純粋な非OpenAMPアプリケーションとして、BMアプリケーションをXSDKでしっかりデバッグ。その後、単純にscpでBMバイナリをLinuxにコピーして、OpenAMPを開始するのが効率的だと思います。
BM側のデバッグ情報は、運が良ければUART出力されます。または、Linux側にrpmsg経由で送るという手もあります。
いずれにしろ、Linuxとの通信に絡むところ以外はBMアプリ単品で完成させてから、OpenAMPとしてLinuxと結合させた方がいいです。

## 作例
ポータブル Mandelbrot集合 with ZYBO (Zynq)
(https://qiita.com/take-iwiw/items/07adef3350fa4045a2d2 )

# 参考
https://forums.xilinx.com/t5/Embedded-Linux/how-can-I-debug-the-baremetal-application-in-AMP-mode/td-p/739251