Help us understand the problem. What is going on with this article?

OpenAMP on ZYBO (Zynq) 1回目: とりあえずサンプルを動かす

More than 1 year has passed since last update.

本記事について

Linux + ベアメタル(or FreeRTOS)のマルチ環境を、OpenAMPを使用してZYBOで実現させます。

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

基本的には、ug1186-zynq-openamp-gsg_2018.pdfの内容と同じです。ただし、このドキュメントはZCU102ボードをターゲットにしていることと、あらかじめBSPが用意されている前提で書かれています。本記事では、ZYBOを対象に、作業内容が一から(ハードウェア作成から)分かるように記載しました。

まずは、サンプルプログラムである、echo_testを動かせるようにします。

環境

  • 開発用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)

手順は一から記載します。ただし、VivadoとPetaLinuxの基本的な説明は省略します。必要に応じて、こちらの記事を参照してください。

事前知識

まず最初に事前知識に説明です。具体的なやり方を先に知りたい方は、ここに飛んでください。

マルチプロセッサのコンフィギュレーション (AMP/SMP)

ZYBOにはCortex-A9のコアが2つ搭載されています(CPU0, CPU1)。
なお、本記事内でCPU, コア, プロセッサといった単語は全て同じ意味とします(本来は区別すべきですが、元ドキュメントや図に合わせました)。

AMP (ベアメタル/FreeRTOS)

XSDKで、ベアメタル(OS無し)またはFreeRTOSとしてプロジェクトを作成した場合は、シングルコア動作となります。CPU0とCPU1のどちらで動かすかはプロジェクト作成時に指定できます。また、XSDK上で2つプロジェクトを作り、FSBLやローダの設定をちゃんとすることで、CPU0, CPU1でそれぞれ別々のファームウェアを動かすことが出来ます。この場合は、AMP(Asymmetrical multi processing)動作となり、各ファームウェアは決められたCPUでのみ動作します。このとき、L1キャッシュのコヒーレンシも保たれません。ちなみに、L2キャッシュがどうなるかは不明。

01.jpg

SMP (Linux)

PetaLinuxで、通常通りにLinuxイメージを作成した場合は、SMP(Symmetrical multi processing)動作となります。通常のPCと同じ動きになります。Linux上の各プロセスは、CPUの空き状況や優先度に応じて、CPU0,CPU1に動的にスケジューリングされます。同じプロセスでも、ある時はCPU0で動き、ある時はCPU1で動くというようになります。このとき、動作するCPUが変わってもL1キャッシュのコヒーレンシは保たれます。

AMP (Linuxとベアメタル(or FreeRTOS))

開発するプロダクトの性質に応じて、Linuxとベアメタルを動かしたいというケースが出てきます。例えば、以下のような処理が必要な場合が考えられます。

  • Linux: USBやネットワーク周りの処理。UI関係の処理
  • ベアメタル: リアルタイム性の高いデバイス制御

このとき、例えば、CPU0でLinuxを動かし、CPU1でベアメタルを動かしたい、となります。また通常は、各CPUで動作する処理は協調して動く必要があります。そのため、CPU間通信機能も必要になります。
これらを実現するために、OpenAMP を使用します。

02.jpg

その他

巷には、Linux上の一つのプロセスとしてベアメタルプログラムやRTOSタスクを走らせたり、逆にRTOS上でLinuxを動かすといった方法もあります。

また、ハイパーバイザを使うという方法もあるそうです。

OpenAMP

OpenAMPとは、The Multicore Associationによって管理されている、マルチプロセッサ用のオープンなフレームワークです。
OpenAMPによって、以下のことが可能になります(他にも色々あると思うが、今回使うものだけ)。

  • Linuxからベアメタル(or FreeRTOS)用ファームウェア(elfバイナリ)のロードを行う
  • 通信機能の提供

重要な点として、OpenAMPを使うときは、ベースとなるOSはLinuxになります。まずCPU0(ホストプロセッサ)でLinuxを起動して、CPU1(リモートプロセッサ)にベアメタル側のファームウェア(リモートアプリケーション)をロードします。

OpenAMP コンポーネント

OpenAMPは下記3つのコンポーネントを持ちます。

  • virtIO
    • 共有メモリの管理
  • remoteproc
    • リモートプロセッサのライフサイクル管理。ファームウェアをロードしたりする
  • RPMsg
    • 異なるコアで動作するプロセス間の通信機能(IPC: Inter-Process Communication)

Libmetalライブラリ

LibmetalはOpenAMPによって提供されるライブラリです。LibmetalはLinux, FreeRTOS, ベアメタル環境で使用可能です。
Libmetalライブラリが、デバイスアクセス、割り込み、メモリアクセスといったハードウェアを抽象化したAPIを提供します。
OpenAMPの各コンポーネントがLibmetalライブラリを使用します。

05_2.jpg

プロセッサ間のメッセージ通信の仕組み

03.jpg

基本的なプロセッサ間通信の流れとしては、以下のような感じです。

  1. 送信側プロセッサが、共有メモリ(Shared Memory)にデータを書く
  2. 送信側プロセッサが、プロセッサ間割り込み(IPI: Inter Processor Interrupt)を発生させ、受信側プロセッサに通知する

OpenAMPを使用したAMP環境の構築

ここから、実際にLinux+ベアメタルのAMP環境を作っていきます。作業の流れは以下のようになります。

  1. ハードウェアの作成 (Vivado)
    • 特別なことは不要
  2. ベアメタル (or FreeRTOS) 用ファームウェアの作成 (XSDK)
  3. Linuxイメージの作成 (PetaLinux)
    • OpenAMPを有効にする
    • 2で作成したファームウェアをインストールする
    • デバイスツリーの編集

ハードウェアの用意 (on Vivado)

まずVivadoで、PSだけを配置したハードウェアを作ります。デザインの名前はデフォルトのままで、design_1にします。また、必要に応じてEthernet 0の設定を修正しておいてください。こちらを参照

04.jpg

hdfをエクスポートして(ビットストリーム込みで)、Ubuntu側にコピーしておきます。コピー先は~/work/peta/design_1_wrapper.hdfとします。
また、次の作業のために、メニューバー -> File -> Launch SDKで、XSDKを起動します。

ベアメタルファームウェアの作成 (on XSDK)

echo_test用サンプルプロジェクトの作成

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

  • Project Name: my_echo_test (何でもいい)
  • 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_echo_test_bspで右クリック -> Board Support Package Settingsをクリック。

05.jpg
06.jpg

ps7_cortexa9_1を選択して、extra_compiler_flagsのValueに-DUSE_AMP=1を追加します。

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

ファームウェアの作成

ソースコードは何も変えずに、ビルドします。(デフォルトでオートビルドになっている)

作成されたmy_echo_test.elfをUbuntu側にコピーしておきます。

Linuxイメージを作る (on PetaLinux in Ubuntu)

PetaLinuxプロジェクトを作る

下記コマンドで、PjOpenAmpというプロジェクトを作成します。そして、先ほどVivadoで作成したハードウェアで設定をします。コンフィグ設定画面では何もせずにExitします。

コマンド
cd ~/work/peta
petalinux-create --type project --template zynq --name PjOpenAmp
cd PjOpenAmp
petalinux-config --get-hw-description=~/work/peta

Kernelコンフィグ

Kernelのコンフィギュレーションをします。ただ、これはデフォルト設定でOKなはずなので、確認だけ行います。

コマンド
petalinux-config -c kernel

下記設定が有効になっていることを確認してください。

  • Enable loadable module supportが、[*]
  • Device Drivers > Generic Driver Options > Userspace firmware loading supportが、-*-
  • Device Drivers > Remoteproc drivers > Support ZYNQ remoteprocが、<M>

07.jpg

rootfsコンフィグ

rootfsのコンフィギュレーションをします。

コマンド
petalinux-config -c rootfs

下記のように設定してください。libmetalとOpenAMPを有効にします。また、テスト用にテストアプリをインストールします(これはなくてもOK)。もしかしたら、packagegroup-petalinux-openampだけで大丈夫かもしれません。

  • Filesystem Packages > misc > sysfsutils > libsysfsを、[*]
  • Filesystem Packages > libs > libmetal > libmetalを、[*]
  • Filesystem Packages > misc > packagegroup-petalinux-openamp > packagegroup-petalinux-openampを、[*]
  • Filesystem Packages > misc > openamp-fw-echo-testd > openamp-fw-echo-testdを、[*]
  • Filesystem Packages > misc > openamp-fw-mat-muld > openamp-fw-mat-muldを、[*]
  • Filesystem Packages > misc > openamp-fw-rpc-demo > openamp-fw-rpc-demoを、[*]

08.jpg

リモートアプリケーション(ベアメタルファームウェア)を含める

先ほどXSDKで作成したベアメタルファームウェアである、my_echo_test.elfを取り込みます。
まず、MyRemoteAppEchoTestという名前の、ファイル取り込みだけをするアプリケーションを作成します。そこに、バイナリファイルをコピーします。最後に、レシピ(MyRemoteAppEchoTest.bb)を編集します。

これによって、my_echo_test.elfが/lib/firmware/my_echo_test.elfにインストールされます。

コマンド
petalinux-create -t apps --template install -n MyRemoteAppEchoTest --enable
cp ~/work/peta/my_echo_test.elf project-spec/meta-user/recipes-apps/MyRemoteAppEchoTest/files/.
code project-spec/meta-user/recipes-apps/MyRemoteAppEchoTest/MyRemoteAppEchoTest.bb &
MyRemoteAppEchoTest.bb
SUMMARY = "Simple MyRemoteAppEchoTest application"
SECTION = "PETALINUX/apps"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "file://my_echo_test.elf \
    "

S = "${WORKDIR}"
INSANE_SKIP_${PN} = "arch"

do_install() {
    install -d ${D}/lib/firmware
    install -m 0644 ${S}/my_echo_test.elf ${D}/lib/firmware/my_echo_test.elf
}
FILES_${PN} = "/lib/firmware/my_echo_test.elf"

デバイスツリーを編集する

割り込み番号や、リモートアプリケーション用メモリ領域の設定のため、デバイスツリーを編集します。これは、ug1186-zynq-openamp-gsg_2018.pdfに記載されている内容そのままです。

コマンド
code project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi &
project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
/include/ "system-conf.dtsi"
/ {
    reserved-memory {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;
        rproc_0_reserved: rproc@3e000000 {
            no-map;
            reg = <0x3e000000 0x01000000>;
        };
    };
    amba {
        elf_ddr_0: ddr@0 {
            compatible = "mmio-sram";
            reg = <0x3e000000 0x400000>;
        };
    };
    remoteproc0: remoteproc@0 {
        compatible = "xlnx,zynq_remoteproc";
        firmware = "firmware";
        vring0 = <15>;
        vring1 = <14>;
        srams = <&elf_ddr_0>;
    };
};

ビルドしてイメージを完成させる

コマンド
petalinux-build
petalinux-package --boot --force --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/design_1_wrapper.bit --u-boot

上記コマンドで生成された、images/linux/BOOT.BINimages/linux/image.ubを、SDカード(FAT32)にコピーします。

自分で作成したエコーテストを試す

先ほど作成したSDカードをZYBOにさして、ZYBOのJP5をSDカード起動に設定します。そして、電源ONします。
UARTターミナルから、以下コマンドを実行します。

ZYBOのUARTターミナル(開始)
modprobe rpmsg_user_dev_driver
echo my_echo_test.elf > /sys/class/remoteproc/remoteproc0/firmware
echo start > /sys/class/remoteproc/remoteproc0/state
echo_test

すると、このように動いていることが分かります。

echo_test実行結果
root@PjOpenAmp:~# echo_test
 Echo test start
~省略~
 1 - Send data to remote core, retrieve the echo and validate its integrity ..
 2 - Quit this application ..
 CMD>1
 sending payload number 0 of size 9
echo test: sent : 9
 received payload number 0 of size 9
~省略~
 echo test: sent : 478
 received payload number 470 of size 478

 sending payload number 471 of size 479
echo test: sent : 479
 received payload number 471 of size 479
 **************************************
 Test Results: Error count = 0

Linux側のアプリケーションとベアメタル側のファームウェアが通信しています。
確認できたらファームウェアを停止します。これによって、OpenAMP動作も停止します。

ZYBOのUARTターミナル(停止)
echo stop > /sys/class/remoteproc/remoteproc0/state

備考

おそらく不要ですが、場合によっては modprobe zynq_remoteproc が最初に必要かもしれません。
OpenAMPのメッセージ通信用のモジュールをアンロードする場合は、 modprobe -r rpmsg_user_dev_driver を実行してください。

AMPになっていることを確認してみる

起動直後に、/proc/cpuinfoを見ると、CPU0とCPU1があります。しかし、echo start > /sys/class/remoteproc/remoteproc0/state後に見ると、CPU0しかないことが分かります。

root@PjOpenAmp:~# cat /proc/cpuinfo
processor       : 0
model name      : ARMv7 Processor rev 0 (v7l)
-省略-

processor       : 1
model name      : ARMv7 Processor rev 0 (v7l)
-省略-

Hardware        : Xilinx Zynq Platform

-///////////////////////////////////-
-echo start > /sys/class/remoteproc/remoteproc0/state 実行後-
-///////////////////////////////////-

root@PjOpenAmp:~# cat /proc/cpuinfo
processor       : 0
-省略-

Hardware        : Xilinx Zynq Platform

デモアプリを試す

順番が逆になってしまいましたが、自分でファームウェアを作らないでも、デモアプリを使ってOpenAMPを試すことができます。それを実行してみます。

rootfsでopenamp-fw-XXXを有効にしたことで、以下のバイナリ(ファームウェア)が/lib/firmwareにインストールされています。ちなみに、自作のmy_echo_test.elfも同じ場所にインストールされています。

  • /lib/firmware/image_echo_test
  • /lib/firmware/image_matrix_multiply
  • /lib/firmware/image_rpc_demo

image_echo_testを試す

image_echo_testはmy_echo_test.elfと同じ動作をします。自作のmy_echo_test.elfがうまく動かない場合は、image_echo_testを試すことで、問題の切り分けが出来るかもしれません。

ZYBOのUARTターミナル
modprobe rpmsg_user_dev_driver
echo image_echo_test > /sys/class/remoteproc/remoteproc0/firmware
echo start > /sys/class/remoteproc/remoteproc0/state
echo_test
echo stop > /sys/class/remoteproc/remoteproc0/state

image_matrix_multiplyを試す

ZYBOのUARTターミナル
modprobe rpmsg_user_dev_driver
echo image_matrix_multiply > /sys/class/remoteproc/remoteproc0/firmware
echo start > /sys/class/remoteproc/remoteproc0/state
mat_mul_demo
echo stop > /sys/class/remoteproc/remoteproc0/state

image_rpc_demoを試す

proxy_appを実行するだけで、ファームウェアのロードなどを行ってくれるようです。そのため、事前に他のファームウェアをロードしていた場合には、終了させておく必要があります。

ZYBOのUARTターミナル
echo stop > /sys/class/remoteproc/remoteproc0/state
modprobe -r rpmsg_user_dev_driver
proxy_app

おわりに

ひとまずコードの中身や仕組みは置いといて、手順としてOpenAMP環境を作れるようにしました。次回は実際にコードをいじってみようと思います。

参考

そういえば

msysやmingwのbinにパスが通っていると、XSDKでOpenAMPプロジェクトを作成したときにフリーズする可能性があるのでご注意ください。

iwatake2222
クソコード、放置するのも、同罪です (自分への戒め)
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした