はじめに
次の記事で UltraZed 向け Debian GNU/Linux (v2017.3版) の構築をしました。
- 「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(イントロ編)」@Qiita
- 「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Boot Loader編)」@Qiita
- 「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Linux Kernel編)」@Qiita
- 「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Debian9 Root File System編)」@Qiita
また、次の記事で、上の記事で構築したシステムのイメージを紹介しました。
この記事では、上の記事で構築したシステムを使って、Linux から FPGA をコンフィギュレーションする例を示します。この記事で紹介する FPGA のデザインやプログラムは次の URL に公開しています。
Sample FPGA Design
今回 FPGA にコンフィギュレーションする回路は、次の記事で説明したものを使用します。
デザインのブロック図は次のようになっています。
Fig.1 ZynqMP Sample Design
準備
UltraZed の準備
次の記事を参考に UltraZed に Debian GNU/Linux (v2017.3版) をインストールしてください。
fpga でログイン
Linux が起動したら ユーザー名 fpga でログインします。パスワードは fpga になっています。
debian-fpga login: fpga
Password:
fpga@debian-fpga:~$
リポジトリのダウンロード
サンプルとなる FPGA デザインやプログラムを下記の URL よりダウンロードします。
ここでは v2017.3 版 を examples/gpio としてダウンロードします。
fpga@debian-fpga:~$ mkdir examples
fpga@debian-fpga:~$ cd examples
fpga@debian-fpga:~/examples$ git clone -b v2017.3 https://github.com/ikwzm/ZynqMP-FPGA-Linux-Example-0-UltraZed gpio
fpga@debian-fpga:~/examples$ cd gpio
fpga@debian-fpga:~/examples/gpio$ git checkout v2017.3
FPGA のコンフィギュレーション
Binary File への変換
今回構築した Debian GNU/Linux には FPGA Reagion が組み込まれています。残念ながら、次の記事のとおり FPGA Regsion と FPGA Manager の組み合わせでは Xilinx のビットストリームを直接読めません。したがって、まずはビットストリームファイルを変換する必要があります。
fpga@debian-fpga:~/examples/gpio$ python3 fpga-bit-to-bin.py -f design_1_wrapper.bit design_1_wrapper.bin
Design name: b'design_1_wrapper;UserID=0XFFFFFFFF;Version=2017.2.1\x00'
Full bitstream
Partname b'xczu3eg-sfva625-1-i\x00'
Date b'2017/12/24\x00'
Time b'10:39:58\x00'
Found binary data: 5568668
Flipping data...
Writing data...
Binary File を /lib/firmware へコピー
FPGA Region では /lib/firmware にコンフィギュレーションするファイルを置いておく必要があります。
fpga@debian-fpga:~/examples/gpio$ sudo cp design_1_wrapper.bin /lib/firmware
Device Tree Overlay による FPGA のコンフィギュレーション
FPGA Region では Device Tree を使って FPGA をコンフィギュレーションします。そこで次のような Device Tree Overlay 用のソースファイルを用意します。
/dts-v1/;
/ {
fragment@0 {
target-path = "/fpga-full";
__overlay__ {
firmware-name = "design_1_wrapper.bin";
};
};
};
target-path が "/fpga-full" であることに注意してください。これは Linux 起動時に読み込んだ Device Tree で指定した fpga-region のシンボル名です。
次の手順で Device Tree Overlay による FPGA のコンフィギュレーションを行います。
- Device Tree Overlay 用ソースファイル(ここでは fpga-load.dts)を dtc(Device Tree Compiler) を使って dtb (ここでは fpga-load.dtb) に変換する。
- /config/device-tree/overlays 下に Device Tree Overlay 用のディレクトリ(ここでは fpga) を作る。
- 2.で作ったディレクトリ下の dtbo に 1. で作った dtb を書き込む。
これで次のようなカーネルメッセージが出れば、FPGA のコンフィギュレーションは成功です。
fpga@debian-fpga:~/examples/gpio$ dtc -I dts -O dtb -o fpga-load.dtb fpga-load.dts
fpga@debian-fpga:~/examples/gpio$ sudo mkdir /config/device-tree/overlays/fpga
fpga@debian-fpga:~/examples/gpio$ sudo cp fpga-load.dtb /config/device-tree/overlays/fpga/dtbo
[ 1462.560122] fpga_manager fpga0: writing design_1_wrapper.bin to Xilinx ZynqMP FPGA Manager
FPGA のクロックの設定
FPGA をコンフィギュレーションするだけでは FPGA 側の回路は動きません。なぜなら FPGA へ供給するクロックの設定が終わっていないからです。
ここでは fclkcfg を使ってクロックを設定します。fclkcfg は筆者が作ったデバイスドライバで、次の URL に公開しています。
「UltraZed 向け Debian GNU/Linux ブートイメージの提供」をインストールしてあれば、すでに fclkcfg が組み込まれています。
クロックを設定するには、次のような Device Tree Overlay 用のソースファイルを用意します。
/dts-v1/;/plugin/;
/ {
fragment@0 {
target-path = "/amba";
__overlay__ {
fclk0 {
compatible = "ikwzm,fclkcfg-0.10.a";
clocks = <&clkc 0x47>;
insert-rate = "100000000";
insert-enable = <1>;
remove-rate = "1000000";
remove-enable = <0>;
};
};
};
};
ここでは clocks で ZynqMP の PL CLOCK[0] を指定しています。&clkc
はクロック制御ドライバのシンボル名、0x47 は PL CLOCK[0] のインデックス番号です。また、この Device Tree が挿入されたとき PL CLOCK[0] は 周波数 100MHz のクロックを出力するように設定しています。
次の手順で Device Tree Overlay を使ってクロックを設定します。
- Device Tree Overlay 用ソースファイル(ここでは fclk0-zynqmp.dts)を dtc(Device Tree Compiler) を使って dtb (ここでは fclk0-zynqmp.dtb) に変換する。
- /config/device-tree/overlays 下に Device Tree Overlay 用のディレクトリ(ここでは fclk0) を作る。
- 2.で作ったディレクトリ下の dtbo に 1. で作った dtb を書き込む。
これで次のようなカーネルメッセージが出れば、FPGA クロックの設定は成功です。
fpga@debian-fpga:~/examples/gpio$ dtc -I dts -O dtb -o fclk0-zynqmp.dtb fclk0-zynqmp.dts
fpga@debian-fpga:~/examples/gpio$ sudo mkdir /config/device-tree/overlays/fclk0
fpga@debian-fpga:~/examples/gpio$ sudo cp fclk0-zynqmp.dtb /config/device-tree/overlays/fclk0/dtbo
[ 1830.238976] fclkcfg amba:fclk0: driver installed.
[ 1830.243617] fclkcfg amba:fclk0: device name : fclk0
[ 1830.248737] fclkcfg amba:fclk0: clock name : pl0
[ 1830.253678] fclkcfg amba:fclk0: clock rate : 99999999
[ 1830.259085] fclkcfg amba:fclk0: clock enabled : 1
[ 1830.263833] fclkcfg amba:fclk0: remove rate : 1000000
[ 1830.269125] fclkcfg amba:fclk0: remove enable : 0
Uio の準備
FPGA にコンフィギュレーションした回路にアクセスするには UIO を使います。UIO を使うために次のような Device Tree Overlay 用のソースファイルを用意します。
/dts-v1/;
/ {
fragment@0 {
target-path = "/amba_pl@0";
#address-cells = <2>;
#size-cells = <2>;
__overlay__ {
#address-cells = <2>;
#size-cells = <2>;
uio0: uio@80000000 {
compatible = "generic-uio";
reg = <0x0 0x80000000 0x0 0x10000>;
};
uio1: uio@80010000 {
compatible = "generic-uio";
reg = <0x0 0x80010000 0x0 0x10000>;
};
uio2: uio@80020000 {
compatible = "generic-uio";
reg = <0x0 0x80020000 0x0 0x10000>;
};
};
} ;
} ;
Zynq の場合と異なり、注意点があります。
- target-path に
"/amba_pl@0"
を指定します。 - address-cells と size-cells がともに 2 であること。これは ZynqMp のアドレスのビット幅が 64bit であるためです。従って reg には <アドレスの上位32bit アドレスの下位32bit サイズの上位32bit サイズの下位32bit> という形で指定します。
次の手順で Device Tree Overlay を使って Uio を設定します。
- Device Tree Overlay 用ソースファイル(ここでは uio.dts)を dtc(Device Tree Compiler) を使って dtb (ここでは uio.dtb) に変換する。
- /config/device-tree/overlays 下に Device Tree Overlay 用のディレクトリ(ここでは uio) を作る。
- 2.で作ったディレクトリ下の dtbo に 1. で作った dtb を書き込む。
これで次のように /dev/uio0、/dev/uio1、/dev/uio2 が出来れば成功です。
fpga@debian-fpga:~/examples/gpio$ dtc -I dts -O dtb -o uio.dtb uio.dts
fpga@debian-fpga:~/examples/gpio$ sudo mkdir /config/device-tree/overlays/uio
fpga@debian-fpga:~/examples/gpio$ sudo cp uio.dtb /config/device-tree/overlays/uio/dtbo
fpga@debian-fpga:~/examples/gpio$ ls -la /dev/uio*
crw------- 1 root root 245, 0 Dec 31 10:20 /dev/uio0
crw------- 1 root root 245, 1 Dec 31 10:20 /dev/uio1
crw------- 1 root root 245, 2 Dec 31 10:20 /dev/uio2
LED を点滅させてみる
次のような Python のプログラムを用意しました。
from uio import Uio
import numpy as np
import time
import signal
class LED:
def __init__(self):
self.uio = Uio('uio1')
self.regs = self.uio.regs()
self.regs.write_word(4, 0)
self.pattern = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02]
self.index = 0
def run(self):
self.regs.write_word(0, self.pattern[self.index])
if self.index < len(self.pattern)-1:
self.index = self.index + 1
else:
self.index = 0;
if __name__ == '__main__':
led = LED()
for i in range(100):
led.run()
time.sleep(0.1)
ここで import している uio.py は次の記事で紹介したものです。
上のプログラムを走らせてみて数秒 LED が左右に点滅すれば成功です。
fpga@debian-fpga:~/examples/gpio$ sudo python3 led_on.py
後始末
遊び終わったら、Device Tree Overlay で追加したデバイスツリーを、後から追加した順に削除します。
fpga@debian-fpga:~/examples/gpio$ sudo rmdir /config/device-tree/overlays/uio
fpga@debian-fpga:~/examples/gpio$ sudo rmdir /config/device-tree/overlays/fclk0
[ 2149.037235] fclkcfg amba:fclk0: change rate : 992064
[ 2149.042497] fclkcfg amba:fclk0: change enable : 0
[ 2149.047353] fclkcfg amba:fclk0: driver unloaded
fpga@debian-fpga:~/examples/gpio$ sudo rmdir /config/device-tree/overlays/fpga
参考
- 「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(イントロ編)」@Qiita
- 「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Boot Loader編)」@Qiita
- 「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Sample FPGA Design編)」@Qiita
- 「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Linux Kernel編)」@Qiita
- 「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Debian9 Root File System編)」@Qiita
- 「UltraZed 向け Debian GNU/Linux (v2017.3版) ブートイメージの提供」@Qiita
- 「Linux の FPGA Manager で Xilinx のビットストリームファイルを扱う方法」@Qiita
- 「Python と Numpy で UIO を制御」@Qiita
- https://github.com/ikwzm/ZynqMP-FPGA-Linux-Example-0-UltraZed
- https://github.com/ikwzm/fclkcfg