ZYNQ に GPIO 回路を接続し Linux 上で割込みを受け付けてみる(後編)
前編で作成した回路を確認するためのソフトウェア環境(Linux)を作成する。 尚、今回はVivado に含まれる hsi (Hardware Software Interface)という CUI ツールを使用し、一環してコマンドラインによる手順をとってみた。
準備
確認した環境は Ubuntu の 64 bit だが、Xilinx の開発ツールは 32 bit 向けのため、予め以下を実施。
% sudo apt-get install ia32-lib
また、開発ツールのパスを通すため、
% source /opt/Xilinx/Vivado/2015.2/settings64.sh
を行っておく。
更に、開発ツールは gmake を期待するため、以下のように対処する。
% sudo ln -s /usr/bin/make /usr/bin/gmake
ZYBO 用 Linux イメージの取得
今回は、公開されているビルド済みイメージを拝借・流用する。
% git clone https://github.com/ucb-bar/fpga-images-zybo.git
clone したリポジトリから使用するファイルは以下の3点。
fpga-images-zybo/boot_image/u-boot.elf fpga-images-zybo/uImage fpga-images-zybo/uramdisk.image.gz
FSBL の作成
ZYNQ 用のブートローダである FSBL (Fast Stage Boot Loader) を作成する。
% mkdir fsbl-build && cd fsbl-build % hsi ****** hsi v2015.2 (64-bit) **** SW Build 1266856 on Fri Jun 26 16:35:25 MDT 2015 ** Copyright 1986-2015 Xilinx, Inc. All Rights Reserved. hsi% open_hw_design /path/to/gpio-sample/gpio-sample.sdk/zybo_wrapper.hdf zybo_wrapper hsi% generate_app -hw zybo_wrapper -os standalone -proc ps7_cortexa9_0 -app zynq_fsbl -compile -sw fsbl -dir fsbl-build hsi% exit
zybo_wrapper.hdf
は前編の最後でエクスポートした H/W 情報のファイルで、/path/to/gpio-sample/
は Vivado で作成したプロジェクトのディレクトリ。
また、生成された FSBL は fsbl-build/executable.elf
(ELF フォーマット)で、後ほど使用する。
Device tree の作成
前編でエクスポートした H/W 情報を基に、Device tree を作成する。
% mkdir device-tree && cd device-tree % git clone git://github.com/Xilinx/device-tree-xlnx.git % hsi hsi% open_hw_design /path/to/gpio-sample/gpio-sample.sdk/zybo_wrapper.hdf hsi% set_repo_path ./device-tree-xlnx hsi% create_sw_design device-tree -os device_tree -proc ps7_cortexa9_0 device-tree hsi% generate_target -dir ./ WARNING: ps7_ethernet_0: No reset found WARNING: ps7_i2c_0: No reset found WARNING: ps7_usb_0: No reset found hsi% exit % dtc -I dts -O dtb -o devicetree.dtb ./system.dts
今回は不要だが、必要に応じて、dtc をかける前に system.dts を編集する(bootargs 等)。 尚、dtc は Ubuntu パッケージのものでOK。
boot.bin の作成
boot.bin は FSBL、FPGA の bit ファイル、ユーザプログラムの3つをパックしたバイナリファイル。ZYNQ は起動デバイスから boot.bin をロードしてジャンプする。
まず、boot.bin の構成を定義するファイルを以下の内容で作成する。
the_ROM_image: { [bootloader]/path/to/fsbl-build/executable.elf /path/to/gpio-sample/gpio-sample.sdk/zybo_wrapper.bit /path/to/fpga-images-zybo/boot_image/u-boot.elf }
1行目に最初に作成した FSBL、2行目に前編で生成した FPGA 用の bit ファイル、3行目には u-boot (ELFフォーマット)を指定。
上記ファイルを boot.bif として保存し、以下のようにして boot.bin の作成。
% bootgen -image boot.bif -w on -o i boot.bin
microSD カードにコピーして起動
作成した boot.bin 及び devicetree.dtb と、流用する uImage 及び ramdisk-image を microSD カード(FATフォーマット)にコピーする。
% cp /path/to/boot.bin SDCARD % cp /path/to/devicetree.dtb SDCARD % cp /path/to/fpga-images-zybo/uImage SDCARD % cp /path/to/fpga-images-zybo/uramdisk.image.gz SDCARD
microSD カードを ZYBO に挿入して、JP5(起動方法を選択するジャンパ)を SD にショートし、電源を投入する。 ホストから /dev/ttyUSB* を 115200bps で開き、root (パスワード: root) でログイン可能。 (当然ながら電源投入後でないと ttyUSB が見えないので注意)
GPIO の設定
起動した Linux カーネルには、既にドライバを含む GPIO サブシステムが備わっており、sysfs 経由で設定と操作が行える。
LED の端子一覧と、Linux カーネルが管理するGPIO 番号の対応は以下のとおり。
端子 | GPIO 番号 |
---|---|
LD0(M14) | 898 |
LD1(M15) | 899 |
LD2(G14) | 900 |
LD3(D18) | 901 |
上記を基に、設定を行う。
for i in `seq 898 901`; do echo $i > /sys/class/gpio/export echo out > /sys/class/gpio/gpio$i/direction done
正しく設定できたか確認するため、LED を全て点灯してみる。(0 で消灯)
for i in `seq 898 901`; do echo 1 > /sys/class/gpio/gpio$i/value done
プッシュボタンは以下のとおり。
端子 | GPIO 番号 |
---|---|
BTN0(R18) | 902 |
BTN1(P16) | 903 |
BTN2(V16) | 904 |
BTN3(Y16) | 905 |
プッシュボタンの設定。割り込み設定も行う。
for i in `seq 902 905`; do echo $i > /sys/class/gpio/export echo in > /sys/class/gpio/gpio$i/direction echo rising > /sys/class/gpio/gpio$i/edge done
正しく設定できていれば、ボタンを押している間に以下の値が1になる。
for i in `seq 902 905`; do cat /sys/class/gpio/gpio$i/value done
割り込みの確認
最終目的である、追加した GPIO の割り込みを Linux から確認する。
sysfs 経由の GPIO インターフェイスは、poll
によって割り込みを確認することができる。
BTN0 の割り込みを待ち受ける以下のプログラムを作成した。(エラー処理などは省略)
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <poll.h> int main(void) { struct pollfd sw; char buf[1]; sw.fd = open("/sys/class/gpio/gpio902/value", O_RDONLY); sw.events = POLLPRI; while (1) { poll(&sw, 1, -1); lseek(sw.fd, 0, SEEK_SET); read(sw.fd, buf, 1); printf("pushed!\n"); } }
% arm-xilinx-linux-gnueabi-gcc gpio-int.c -o gpio-int
これを ZYBO 上で実行すると、BTN0 を押したタイミングで pushd! が無事に表示された。
おしまい
Xilinx の開発ツールと、ZYNQ の仕組みがだんだんわかってきた。次は、Verilog で 何らかの IP を新たに作成して動かしてみたい。