19
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ZYBO (Zynq) 初心者ガイド (18)(完) IoT化してスマホからLチカ

Last updated at Posted at 2018-01-17

環境

  • 開発用PC: Windows 10 64-bit
    • Vivado 2017.4 WebPACKライセンス
    • Xilinx SDK 2017.4 (C アプリケーションの実装)
    • Visual Studio Code (Pythonスクリプトの実装)
  • 開発用PC (Linux): Ubuntu 16.04 本家 (日本語版じゃない) (on VirtualBox 5.2.4)
    • PetaLinux 2017.4
  • ターゲットボード: ZYBO (Z7-20)

IoT化してスマホからLチカ

今回は最終回として、これまでやってきた内容を組み合わせて、スマートフォンからZYBO上のLEDやボタンを制御してみます。ラズパイでよくある、こういうやつです(ラズパイ + Bottleでお手軽にIoT環境を作る)。

01.jpg

デモ動画と作り方: https://youtu.be/z613J8RVpog
(Xilinxのブログで紹介されました!! (https://forums.xilinx.com/t5/Xcell-Daily-Blog/Hands-on-Watch-YouTube-video-maker-takeshi-i-create-an-IoT/ba-p/822967 ))

全体像

全体像は以下の通りです。

02.jpg

下から見ていきます。ZYBO Z7-20ボード上には、PLに接続されたLED x 4、ボタン x 4、スイッチ x 4、カラーLED x 2と、PSに接続されたLED x 1、ボタン x 2があります。PL側のLED、ボタン、スイッチの制御用に、myipというIPを作ります。これは、AXI GPIOとほぼ同等ですが、練習のために自作IPとしました。また、カラーLEDのPWM制御用にmypwmというIPを作成します。PS側のLEDはOSの機能でそのまま制御します。ボタンは今回は使いません。(1時間くらハマったけど、ボタンのGPIO956/957の制御が出来なかった)。

自作IPであるmyipmypwmは、User space IO(UIO)として制御します。それぞれ、/dev/uio0/dev/uio1になります。これは、デバイスツリーで設定します。

自作IPの制御用に、Cアプリケーション(myip_controller)を作成します。入出力として名前付きパイプを持ちます。入力パイプで、LED制御コマンド(ON/OFFやカラーLEDのDuty比)を受け付けます。出力パイプで、ボタンとスイッチの状態を出力します。

最上位層にPythonスクリプト(ServerIoT)がいます。ServerIoTは、bottleを使用してサーバーとして動作します。WebAPIとして、setStatusgetStatusをPOST(JSON)形式で提供します。setStatusが呼ばれたら、PLデバイスの制御コマンドをパイプ経由でmyip_controllerに出力します。PSのLEDは直接制御します。getStatusが呼ばれたら、パイプ経由でmyip_controllerからボタンとスイッチの状態を取得して、呼び元にJSON形式で返します。また、公開ルートパスにアクセスされたら、index.htmlを出力します。このindex.htmlがユーザにとってのビューになります。index.html内にボタンなどが配置されており、ボタンが押されるなどのイベントに応じて、main.jsというJavaScriptを呼び出し、このJavaScriptが先ほどのWebAPIを呼び出します。

ポイント

実は、Cアプリケーションを省略して、Pythonだけで/dev/uio0,1の制御をすることも可能です。今回は練習のために、あえてCアプリケーションで実装しました。

CとPythonの連携については、Boost.Pythonやctypesを使用することもできます。この場合、C側は共有ライブラリ(.so)になります。個人的にこのパターンは以前やったことがあるのと、開発が面倒(soのテストアプリが必要)なので、今回はやめました。
代わりに、名前付きパイプを使用して、文字列でやり取りします。これによって、Python側とCアプリケーションがバイナリ的に疎結合になり、テストが非常にやりやすくなります。C側の開発をするときは、入出力がパイプなので、コンソールからのcatやechoで動作確認できます。Python側も同様です。さらに、入出力がパイプになることで、ハードウェア制御が無くなり、ホストPC上で開発/確認ができます。(ただし、パイプを使うので、Windows コマンドプロンプトだと不可。また、PS GPIOの確認はできない)

各ブロックの責務と詳細

  • ServerIoT
    • Pythonスクリプト。WindowsPCで開発。デバッグはmsysとZYBO実機
    • サーバーとして、WebAPIとビューを提供する
    • WebAPI(setStatus)で指示されたとおりに、名前付きパイプにLED制御コマンドを出力。PS GPIOは自分で制御する
    • WebAPI(getStatus)を受けたら、名前付きパイプからボタンとスイッチの状態を取得する。その後、JSON形式にして呼び元(main.js)に返す
  • myip_controller
    • C++アプリケーション。WindowsPC上のXilinx SDKで開発/デバッグ
    • 自作IP(/dev/uio0/dev/uio1)の制御
  • Linuxイメージ (カーネル/RootFS)
    • Ubuntu上のPetaLinuxで作成
    • PythonとC++ライブラリをインストール
    • ServerIoTとmyip_controllerを含む。また、これらを起動デーモンとして開始する
    • デバイスツリー設定(system-user.dtsi)によって、自作IPをUIOデバイスとして認識させる
  • hdf
    • ハードウェア情報 (PSの設定と、PLのビットストリーム)。
    • Windows PC上のVivadoで開発

ソースコード

Build方法

ハードウェア(hdf)やビルド済みのバイナリは、既にPebaLinuxプロジェクトに含まれています。そのため、ビルドするだけであれば、PetaLinux プロジェクト (https://github.com/take-iwiw/ZYBO_IoT_PetaLinux) だけあれば大丈夫です。

開発PCのターミナル
git clone https://github.com/take-iwiw/ZYBO_IoT_PetaLinux.git
cd ZYBO_IoT_PetaLinux/PjIoT
# 下記ファイルの`SERVER_URL`にZYBOのIPアドレスを設定する。コミットされているのは僕の環境の値 (192.168.1.87)
code project-spec/meta-user/recipes-apps/myinit/files/ServerIoT/static/js/main.js &
petalinux-build
petalinux-package --boot --force --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/design_iot_wrapper.bit --u-boot

出来上がった、images/linux/BOOT.binimages/linux/image.ubをFAT32フォーマットのSDカードに書き込みます。その後、同じネットワーク内にあるブラウザからhttp://192.168.1.87:8080/にアクセスします。

Pythonスクリプトを変更したい場合は、project-spec/meta-user/recipes-apps/myinit/files/ServerIoT/を直接編集します。

Cアプリケーション(myip_controller)を変更したい場合は、https://github.com/take-iwiw/ZYBO_IoT_SDK を取得して、Xilinx SDKで変更/デバッグします。出来上がったバイナリ(myip_controller.elf)をPetaLinuxのproject-spec/meta-user/recipes-apps/myinit/files/にコピーします。

ハードウェアデザインを変更したい場合は、https://github.com/take-iwiw/ZYBO_IoT_Vivado を取得して、変更後、hdfを出力します。その後、PetaLinux側にコピーして、petalinux-config --get-hw-description=.した後、再ビルドします。

本プロジェクトの作り方

一からプロジェクトを始める際の、作業の流れを記載します。コードは省略します。代わりに、GitHubへのリンクを載せるようにします。

成果物ベースでのフローは以下のようになります。

image.png

1. ハードウェアの作成 (Vivado on Windows)

Vivadoで新規プロジェクトを作成します。以下のようなハードウェアを作り、ビットストリーム付きのhdfをエクスポートしておきます。
以後、ブロックデザイン名はdesign_iotとします。そのため、出来上がるhdfはdesign_iot_wrapper.hdfとして説明/コマンドなどを記載します。

03.jpg

必要に応じて、この時点でシミュレーションを回して、ハードウェアが期待通りに動いているかを確認します。僕は面倒だったので、SDK上でstandaloneプロジェクトを作り、デバッグ画面でレジスタに読み書きして、期待通りの動作をしているかを確認しました。

完成したdesign_iot_wrapper.hdfを、Ubuntu側にコピーしておきます。

2. ベースとなるLinuxイメージの作成 (PetaLinux on Ubuntu)

Ubuntu上で、新たにPetaLinuxプロジェクトを作ります。先ほど作成したdesign_iot_wrapper.hdfを、~/work/peta/PjIoTにコピーしておきます。そして、このハードウェア情報を基に、プロジェクトのコンフィグを行います。(ビルドはまだ)

開発PCのターミナル
cd ~/work/peta
petalinux-create --type project --template zynq --name PjIoT
cd PjIoT/
petalinux-config --get-hw-description=.

ビルドに進む前に、いくつかやることがあります。
まず、デバイスツリーを変更します。myipmypwmをUIOデバイスとします。

project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
/include/ "system-conf.dtsi"
/ {
    chosen {
        bootargs = "console=ttyPS0,115200 earlyprintk uio_pdrv_genirq.of_id=generic-uio";
    };
};

&myip_0 {
    compatible = "generic-uio";
};

&mypwm_0 {
    compatible = "generic-uio";
};

続いて、RootFSのコンフィグを変えて、必要なツールやライブラリをインストールします。menuconfig上で、pythonとcurlとlibstdc++をインストールします。念のためPythonは、全てのパッケージを入れておきます。(本当は、bottleが使っているのだけを入れるべき)。
設定が終わったら、ビルドします。

開発PCのターミナル
petalinux-config -c rootfs
#	Filesystem Packages  → devel  → python  → python
#	Filesystem Packages  → console  → network  → curl
#	Filesystem Packages  → misc  → gcc-runtime -> libstdc++

petalinux-build
petalinux-package --boot --force --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/design_iot_wrapper.bit --u-boot

04.jpg

完成したイメージ(images/linux/BOOT.binimages/linux/image.ub)をSDカード(FAT32)に入れて、ZYBOを起動します。pythonがインストールされていることを確認します。また、ifconfigでIPアドレスを確認しておきます。

3-a. Cアプリケーションの開発 (Xilinx SDK on Windows)

myip(/dev/uio0)とmypwm(/dev/uio1)を制御するアプリケーションを開発します。僕はクラスを使いたかったので、実際にはC++アプリケーションになります。
Xilinx SDK上で、メニューバー -> File -> New -> Application Projectで、以下のプロジェクトを作ります。

  • ProjectName = myip_controller
  • OS Platform = linux
  • Processor Type = ps7_cortexa9
  • Language = C++
  • Linux System Root / Linux Toolchain = 非チェック

ここ(https://github.com/take-iwiw/ZYBO_IoT_SDK/tree/master/myip_controller )にあるようなコードを実装/ビルドします。その後、TCFでデバッグします。デバッグ方法についてはこちら(https://qiita.com/take-iwiw/items/8134ca7098622219b177 )を参考にしてください。

デバッグ開始前に、ZYBO上で、下記コマンドで名前付きパイプを作っておきます。

ZYBO上のターミナル
mkfifo pipe_c2p
mkfifo pipe_p2c
chmod 666 pipe_p2c
chmod 666 pipe_c2p

パイプによるインターフェースは以下のような文字列にします。

  • pipe_p2c (Python → CアプリへのLEDの制御コマンド)
    • "ON,OFF,ON,OFF,100,100,100,100,100,100"
    • ↑はそれぞれ、LD0,LD1,LD2,LD3,R0,G0,B0,R1,G1,B1、に対応。Duty比は0~100
  • pipe_c2p (Cアプリ → Pythonへのボタンとスイッチの状態通知)
    • "{"btn0":"OFF", "btn1":"OFF", "btn2":"OFF", "btn3":"OFF", "sw0":"OFF", "sw1":"OFF", "sw2":"OFF", "sw3":"OFF"}"

そのため、ZYBOのターミナル上で、以下のようなコマンドによって動作確認をします。

ZYBO上のターミナル(デバッグコマンド例)
echo "ON,OFF,ON,OFF,100,100,100,100,100,100" > pipe_p2c
cat pipe_c2p

このように、名前付きパイプと文字列によるシンプルなインターフェースを採用したため、Python側のコーディングの前に、ほぼ本番と同じ状態でのテストが可能となりました。

3-b. Pythonアプリケーションの開発

WebサーバーとなるPythonスクリプトを開発します。開発場所はどこでもいいです。僕は、最初はWindows上で開発していましたが、途中から動作確認は直絶ZYBOで行いました。Windows上でVSCodeでコーディング → SFTP(拡張機能)でZYBOに自動コピー → ZYBOで実行、という流れです。ただし、ZYBOを再起動したらファイルが消えるのでご注意ください。

コード一式は、こちら(https://github.com/take-iwiw/ZYBO_IoT_PetaLinux/tree/master/PjIoT/project-spec/meta-user/recipes-apps/myinit/files/ServerIoT )にあります。WebサーバやPythonなどの詳細はこの記事(https://qiita.com/take-iwiw/items/3f86281312646fd9d893 )をご参考にしてください。

見た目をよくするために、Bootstrapを取り込んでいます。また、Bottleは、bottle.pyをファイルとして直接配置しています。これは、ZYBO上で追加パッケージのinstallなどをしたくないためです(だから、1ファイルで済むbottleを使用することにしました)。

ある程度出来上がったら、先ほどのCアプリケーションを実行して、結合確認をしてみます。スマホやPCのブラウザから、http://192.168.1.87:8080/ にアクセスして、LED等の制御ができたらOKです。

4. 全てを含んだLinuxイメージの作成 (PetaLinux on Ubuntu)

ここまでの開発では、CアプリケーションはelfバイナリをTCFでデバッグ、PythonスクリプトはSFTPでアップロードしていました。今使用しているイメージでは、RootFSはinitramfsとして、DDR上にマウントされるので、再起動のたびに消えてしまいます。また、実行するのに、毎回手間がかかります。

必要なバイナリやスクリプトを含み、かつ、それらを起動時に自動実行するようにします。なお、Cアプリケーションについては、PetaLinuxでビルドするのではなく、Xilinx SDKでビルド済みの実行ファイルを取り込むことにします。
基本的には、15回目: Linux起動時にアプリケーションを自動実行させる、の通りです。以下コマンドで、myinitという起動用のinit.dデーモンを作ります。レシピと、shスクリプトを編集する必要があります。中身は、(https://github.com/take-iwiw/ZYBO_IoT_PetaLinux/tree/master/PjIoT/project-spec/meta-user/recipes-apps/myinit )をご確認ください。

開発PCのターミナル
petalinux-create -t apps --template install -n myinit --enable
code project-spec/meta-user/recipes-apps/myinit/myinit.bb &
code project-spec/meta-user/recipes-apps/myinit/files/myinit &
code project-spec/meta-user/recipes-apps/myinit/files/myinit_run.sh &

petalinux-createmyinitを作ったら、Xilinx SDKでビルド済みのmyip_controller.elfと、Pythonスクリプト一式をフォルダ(ServerIoT)ごと、project-spec/meta-user/recipes-apps/myinit/files/にコピーしておきます。

レシピと、shスクリプトの編集と、ファイルのコピーが終わったら、下記コマンドで、image.ubを再作成します。

開発PCのターミナル
petalinux-build -c rootfs
petalinux-build -x package

メモ

本来、Cアプリケーション(自作IPの制御)とPythonスクリプト(サーバー)は、別々のデーモンとして動かすべきです。が、今回は横着をして、同一のスクリプト(myinit_run.sh) 内で、Cアプリケーション(自作IPの制御)をバックグラウンドとして動かすことにしました。
なお、名前付きパイプの作成も、myinit_run.sh内で行っています。

Pythonスクリプト(サーバー)の方は、1ファイルだけではなく、htmlなど、複数のファイルを含むディレクトリをインストールする必要があります。そのため、レシピ内で少し工夫が必要でした。(https://github.com/take-iwiw/ZYBO_IoT_PetaLinux/blob/master/PjIoT/project-spec/meta-user/recipes-apps/myinit/myinit.bb )。ただ、この方法で正しいかは不明。

動作確認する

作成したimage.ubを、SDカードに上書きコピーして、ZYBOを起動します。

すると、電源ONするだけで、http://192.168.1.87:8080/ のページが有効になり、LED制御などが出来るはずです。

おわりに

今回は最終回として、今までやってきた内容をほぼ全て詰め込んでみました。また、ZYBOをIoTっぽく使うときのベースとなるプロジェクトにできたと思います。

本連載はこれで終わりです。ツールのインストールから始まり、IPの作成、ベアメタル実装、Linuxまで、一通りの内容を抑えることが出来たと思います。

19
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?