Python
Linux
Debian
FPGA
arm64

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

はじめに

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

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

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

Sample FPGA Design

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

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

Fig.1 ZynqMP Sample Design

Fig.1 ZynqMP Sample Design

UltraZed 向け Debian GNU/Linux (v2018.2版) で FPGA にロードするためには、Bitstream File を Binary File に変換する必要があります。Binary File への変換は、次のような bif file を用意して、Vivado-SDK v2018.2 の bootgen コマンドを使います。

design_1_wrapper.bif
all:
{
    [destination_device = pl] design_1_wrapper.bit
}
vivado% bootgen -image design_1_wrapper.bif -arch zynqmp -w -o design_1_wrapper.bin

Binary File の作り方の詳細は以下の URL を参照してください。

準備

UltraZed の準備

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

fpga でログイン

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

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

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

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

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

fpga@debian-fpga:~$ mkdir examples
fpga@debian-fpga:~$ cd examples
fpga@debian-fpga:~/examples$ git clone https://github.com/ikwzm/ZynqMP-FPGA-Linux-Example-0-UltraZed gpio
fpga@debian-fpga:~/examples$ cd gpio
fpga@debian-fpga:~/examples/gpio$ git checkout v2018.2

FPGA のコンフィギュレーション

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        = <&clk 0x47>;
                insert-rate   = "100000000";
                insert-enable = <1>;
                remove-rate   = "1000000";
                remove-enable = <0>;
            };
        };
    };
};

ここでは clocks で ZynqMP の PL CLOCK[0] を指定しています。&clk はクロック制御ドライバのシンボル名、0x47 は PL CLOCK[0] のインデックス番号です。また、この Device Tree が挿入されたとき PL CLOCK[0] は 周波数 100MHz のクロックを出力するように設定しています。

なお、「UltraZed 向け Debian GNU/Linux (v2017.3版) で FPGA をコンフィギュレーション」 で説明した fclk0-zynqmp.dts とは clocks の記述が違うことに注意してください。v2017.3版では <&clkc 0x47> でしたが、v2018.3版では <&clk 0x47> となっています。

次の手順で 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>;

            uio1: uio@80000000 {
                compatible = "generic-uio";
                reg = <0x0 0x80000000 0x0 0x10000>;
                    };
            uio2: uio@80010000 {
                compatible = "generic-uio";
                reg = <0x0 0x80010000 0x0 0x10000>;
                    };
            uio3: 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/uio1、/dev/uio2、/dev/uio3 が出来れば成功です。

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
crw------- 1 root root 245, 2 Dec 31 10:20 /dev/uio3

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

なお、「UltraZed 向け Debian GNU/Linux (v2017.3版) で FPGA をコンフィギュレーション」 で説明した led_on.py とは指定した uio のデバイスドライバ名が違うことに注意してください。v2017.3 では Uio('uio1') でしたが v2018.3 では Uio('uio2') になっています。

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

注意

Binary File Format について

次で示す記事で v2017.3版 での方法を示しました。

v2018.2 版では Binary File のフォーマットが異なっていることに注意してください。v2017.3 では fpga-bit-to-bin.py という Python のスクリプトを使って変換した Binary File を使いましたが、v2018.2 からは Vivado-SDK の bootgen で変換した Binary File を使う必要があります。

なお、v2018.2 版で 2017.3 版と同様の fpga-bit-to-bin.py を使って変換した Binary File を扱うには、次のように fpga_manager のフラグに 0x20 を設定します。

fpga@debian-fpga:~/examples/negative$ sudo echo 20 > /sys/class/fpga_manager/fpga0/flags

参考