Python
Linux
Debian
FPGA
arm64

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


はじめに

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

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

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


Sample FPGA Design

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

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

Fig.1 ZynqMP Sample Design

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 用のソースファイルを用意します。


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 のコンフィギュレーションは成功です。

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 用のソースファイルを用意します。


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 クロックの設定は成功です。

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 用のソースファイルを用意します。


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 が出来れば成功です。

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


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 は次の記事で紹介したものです。

上のプログラムを走らせてみて数秒 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


参考