UltraZed 向け Debian GNU/Linux (v2017.3版) で FPGA をコンフィギュレーション

はじめに
-------------------------------------------------------------

次の記事で UltraZed 向け Debian GNU/Linux (v2017.3版) の構築をしました。

 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(イントロ編)」@Qiita](https://qiita.com/ikwzm/items/a4ebcffdd26ab3e8124d)
 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Boot Loader編)」@Qiita](https://qiita.com/ikwzm/items/9d2a76f9665759df58e7)
 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Linux Kernel編)」@Qiita](https://qiita.com/ikwzm/items/367f49e9b02102e907d8)
 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Debian9 Root File System編)」@Qiita](https://qiita.com/ikwzm/items/a0e88798ed29b30fa003)

また、次の記事で、上の記事で構築したシステムのイメージを紹介しました。

 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) ブートイメージの提供」@Qiita](https://qiita.com/ikwzm/items/c807f0af1b76da9a1585)


この記事では、上の記事で構築したシステムを使って、Linux から FPGA をコンフィギュレーションする例を示します。この記事で紹介する FPGA のデザインやプログラムは次の URL に公開しています。

 * [https://github.com/ikwzm/ZynqMP-FPGA-Linux-Example-0-UltraZed](https://github.com/ikwzm/ZynqMP-FPGA-Linux-Example-0-UltraZed)

Sample FPGA Design
-------------------------------------------------------------

今回 FPGA にコンフィギュレーションする回路は、次の記事で説明したものを使用します。

 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Sample FPGA Design編)」@Qiita](https://qiita.com/ikwzm/items/61316ecec2fc68be4c96)

デザインのブロック図は次のようになっています。

![Fig.1 ZynqMP Sample Design](https://qiita-image-store.s3.amazonaws.com/0/24981/1270d3cc-8228-891b-46f2-84e5a715f4c1.png "Fig.1 ZynqMP Sample Design")

Fig.1 ZynqMP Sample Design

準備
-------------------------------------------------------------

### UltraZed の準備

次の記事を参考に UltraZed に Debian GNU/Linux (v2017.3版) をインストールしてください。

 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) ブートイメージの提供」@Qiita](https://qiita.com/ikwzm/items/c807f0af1b76da9a1585)

### fpga でログイン

Linux が起動したら ユーザー名 fpga でログインします。パスワードは fpga になっています。

```console
debian-fpga login: fpga
Password:
fpga@debian-fpga:~$
```

### リポジトリのダウンロード

サンプルとなる FPGA デザインやプログラムを下記の URL よりダウンロードします。

 * [https://github.com/ikwzm/ZynqMP-FPGA-Linux-Example-0-UltraZed](https://github.com/ikwzm/ZynqMP-FPGA-Linux-Example-0-UltraZed)

ここでは v2017.3 版 を examples/gpio としてダウンロードします。

```console
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 のビットストリームを直接読めません。したがって、まずはビットストリームファイルを変換する必要があります。

 * [「Linux の FPGA Manager で Xilinx のビットストリームファイルを扱う方法」@Qiita](https://qiita.com/ikwzm/items/1bb63be0b86a1e0e56fa)

```console
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 にコンフィギュレーションするファイルを置いておく必要があります。

```console
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:fpga-load.dts
/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 のコンフィギュレーションを行います。

 1. Device Tree Overlay 用ソースファイル(ここでは fpga-load.dts)を dtc(Device Tree Compiler) を使って dtb (ここでは fpga-load.dtb) に変換する。
 2. /config/device-tree/overlays 下に Device Tree Overlay 用のディレクトリ(ここでは fpga) を作る。
 3. 2.で作ったディレクトリ下の dtbo に 1. で作った dtb を書き込む。

これで次のようなカーネルメッセージが出れば、FPGA のコンフィギュレーションは成功です。
 
```console
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 に公開しています。

 * [https://github.com/ikwzm/fclkcfg](https://github.com/ikwzm/fclkcfg)

[「UltraZed 向け Debian GNU/Linux ブートイメージの提供」](https://qiita.com/ikwzm/items/c807f0af1b76da9a1585)をインストールしてあれば、すでに fclkcfg が組み込まれています。

クロックを設定するには、次のような Device Tree Overlay 用のソースファイルを用意します。

```dts:fclk0-zynqmp.dts
/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 を使ってクロックを設定します。

 1. Device Tree Overlay 用ソースファイル(ここでは fclk0-zynqmp.dts)を dtc(Device Tree Compiler) を使って dtb (ここでは fclk0-zynqmp.dtb) に変換する。
 2. /config/device-tree/overlays 下に Device Tree Overlay 用のディレクトリ(ここでは fclk0) を作る。
 3. 2.で作ったディレクトリ下の dtbo に 1. で作った dtb を書き込む。

これで次のようなカーネルメッセージが出れば、FPGA クロックの設定は成功です。

```console
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:uio.dts
/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 の場合と異なり、注意点があります。

  1. target-path に ```"/amba_pl@0"``` を指定します。
  2. address-cells と size-cells がともに 2 であること。これは ZynqMp のアドレスのビット幅が 64bit であるためです。従って reg には <アドレスの上位32bit アドレスの下位32bit サイズの上位32bit サイズの下位32bit> という形で指定します。


次の手順で Device Tree Overlay を使って Uio を設定します。

 1. Device Tree Overlay 用ソースファイル(ここでは uio.dts)を dtc(Device Tree Compiler) を使って dtb (ここでは uio.dtb) に変換する。
 2. /config/device-tree/overlays 下に Device Tree Overlay 用のディレクトリ(ここでは uio) を作る。
 3. 2.で作ったディレクトリ下の dtbo に 1. で作った dtb を書き込む。

これで次のように /dev/uio0、/dev/uio1、/dev/uio2 が出来れば成功です。

```console
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 のプログラムを用意しました。

```python:led_on.py
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 は次の記事で紹介したものです。

 * [「Python と Numpy で UIO を制御」@Qiita](https://qiita.com/ikwzm/items/d7559858d099c86c350c)

上のプログラムを走らせてみて数秒 LED が左右に点滅すれば成功です。

```console
fpga@debian-fpga:~/examples/gpio$ sudo python3 led_on.py
```

後始末
-------------------------------------------------------------

遊び終わったら、Device Tree Overlay で追加したデバイスツリーを、後から追加した順に削除します。

```console
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](https://qiita.com/ikwzm/items/a4ebcffdd26ab3e8124d)
 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Boot Loader編)」@Qiita](https://qiita.com/ikwzm/items/9d2a76f9665759df58e7)
 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Sample FPGA Design編)」@Qiita](https://qiita.com/ikwzm/items/61316ecec2fc68be4c96)
 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Linux Kernel編)」@Qiita](https://qiita.com/ikwzm/items/367f49e9b02102e907d8)
 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) の構築(Debian9 Root File System編)」@Qiita](https://qiita.com/ikwzm/items/a0e88798ed29b30fa003)
 * [「UltraZed 向け Debian GNU/Linux (v2017.3版) ブートイメージの提供」@Qiita](https://qiita.com/ikwzm/items/c807f0af1b76da9a1585)
 * [「Linux の FPGA Manager で Xilinx のビットストリームファイルを扱う方法」@Qiita](https://qiita.com/ikwzm/items/1bb63be0b86a1e0e56fa)
 * [「Python と Numpy で UIO を制御」@Qiita](https://qiita.com/ikwzm/items/d7559858d099c86c350c)
 * [https://github.com/ikwzm/ZynqMP-FPGA-Linux-Example-0-UltraZed](https://github.com/ikwzm/ZynqMP-FPGA-Linux-Example-0-UltraZed)
 * [https://github.com/ikwzm/fclkcfg](https://github.com/ikwzm/fclkcfg)