LoginSignup
2
1

udmabuf を試してみる (Ultra96V2編)

Last updated at Posted at 2021-04-03

はじめに

iwkzm氏のudmabufを試してみたので、自分用備忘録です。

なお、udmabuf のドライバ名は udmabuf → u-dma-buf と名称変更された経緯があり、古い環境を利用する方は読み替えて頂ければと思います。

udmabuf を試してみる (ZYBO-Z7編)とよく似た内容となっていますが、Device Tree Overlay のやり方などで Zynq-7000 と ZynqMP とで細かい部分で差異があるあるのでご注意ください。

事前準備

環境

今回の環境は下記の通り。

Debianイメージは一度起動SDを作ってしまえば Vivado だけでもいろいろできるのが素敵です。

Ultra96v2側の準備

bootgen を使うのでインストールしておきます。

git clone https://github.com/Xilinx/bootgen  
cd bootgen/  
make  
sudo cp bootgen /usr/local/bin/

他にも make や dtc など使うので、不足があれば随時 sudo apt install してください。

ソースコードの所在

今回は拙作の Jelly の1プロジェクトとして追加しています。

git clone https://github.com/ryuz/jelly -b v2.0.2

で取得でき、/projects/ultra96v2/ultra96v2_udmabuf_sample/ 以下が今回のプロジェクトです。

PL用bitstreamの作成

PS用のbitstreamは PC(WindowsやLinuxなど)で Vivado を使って行います。

Vivado のプロジェクトは
/projects/ultra96v2_udmabuf_sample/syn/vivado2019.2
のにあります。

ultra96v2_udmabuf_sample.xpr が vivado2019.2 のプロジェクトファイルで、 Block Design は 同じディレクトリにある design_1.tcl に export しております。
(design_1.tcl を実行すれば Block Design が作れるはずですが、一度今あるものをプロジェクトから消してから tcl 実行が必要かもしれません。)

合成すると、ultra96v2_udmabuf_sample.bit が出来上がります。
このファイルを projects/ultra96v2_udmabuf_sample/app にコピーしておいてください。

なお、回路の方は本記事の本質ではないので飛ばしますが、重要な点としてメモリマップのみ。

image.png

PS部からは LPDDR4-SDRAM にアクセスするための 128bit幅 のAXI4のバススレーブと、0x00_A000_0000 番地からアサインした、ペリフェラルアクセス用の64bit幅のAXI4Liteのバスマスターを出しております。

あとは ultra96v2_udmabuf_sample.v の方で WISHBONE バスに変換した後に下記のようになるようにアドレスを割り当てています。

  • テスト用簡易DMA0 0x00_A000_0000 - 0x00_A000_07FF
  • テスト用簡易DMA1 0x00_A000_0800 - 0x00_A000_0FFF
  • LED制御レジスタ 0x00_A000_8000 - 0x00_A000_87FF

ソフト側の作成と実行

Ultra96V2側のソフトの開発です。
projects/ultra96v2_udmabuf_sample/app を Ultra96 のどこか適当な箇所にコピーします。
Ultra96V2側の作業は Debian のブートイメージで起動したあと、常に起動したまま行うことが可能で、運用したままPLとソフトをアップデートすることも可能なのがこのブートイメージの素晴らしいところです。

Ultra96V2 の debian でも git は動きますので、こちらでも clone する手があります。
(なお、この app ディレクトリ以下は VS code Remote Development を使ってセルフコンパイル開発してそのままpushしています。)

とりあえず動かしてみる

sudoできるユーザーで app ディレクトリに移動してください。

make run

とすればひとまず動くように作っております。
途中、sudo コマンドを使っているのでパスワードを聞かれると思いますが入力ください。

Device Tree overlay

ここから本記事のメインの部分です。
今回は Device Tree overlay によって

  • PS部がPLに供給する fabric clock の設定
  • PS部とPL部を繋ぐAXIバスのバス幅などの設定
  • bitfile のダウンロード
  • レジスタアクセスの為の uio の割り当て
  • メモリ領域割り当ての為の udmabuf の割り当て

のなどの機能を担っています。

dts ファイル

ここで ultra96v2_udmabuf_sample.dtsファイルの作成が重要となります。

順にみていきたいと思います。
なお、dtsファイルのコンパイルは、実行環境で行うことが必要なようです(内部で既存のDevice Treeのシンボルを参照する為)。

bitstream 指定

    fragment@0 {
        target = <&fpga_full>;
        __overlay__ {
            #address-cells = <2>;
            #size-cells = <2>;
            firmware-name = "ultra96v2_udmabuf_sample.bit.bin";
        };
    };

上のように指定します。この時、ultra96v2_udmabuf_sample.bit.bin は bitstream から bootgen で生成されたファイルであり、/lib/firmware に置かれている必要があります。

bootgen の使い方としては、下記のような ultra96v2_udmabuf_sample.bif に対して

ultra96v2_udmabuf_sample.bif
all:
{
    ultra96v2_udmabuf_sample.bit
}

bootgenを用いて

bootgen -image ultra96v2_udmabuf_sample.bif -arch zynqmp -process_bitstream bin

と実行することによって得られます。

クロックと AXIのバス幅

 fragment@1 {
        target-path = "/amba_pl@0";
        
        #address-cells = <2>;
        #size-cells = <2>;
        __overlay__ {
            #address-cells = <2>;
            #size-cells = <2>;
            afi0 {
                compatible    = "xlnx,afi-fpga";
                config-afi    = <0 0>, 
                                <1 0>,
                                <2 0>, 
                                <3 0>,
                                <14 0x0500>;
               /* 0: S_AXI_HPC0_FPD(read)  : 0:128bit, 1:64bit, 2:32bit */
               /* 1: S_AXI_HPC0_FPD(write) : 0:128bit, 1:64bit, 2:32bit */
               /* 2: S_AXI_HPC1_FPD(read)  : 0:128bit, 1:64bit, 2:32bit */
               /* 3: S_AXI_HPC1_FPD(write) : 0:128bit, 1:64bit, 2:32bit */
               /* 14: M_AXI_HPM0_FPD[9:8], M_AXI_HPM0_FPD[11:10] 
                                           : 0:32bit, 1:64bit, 2:128bit */
            };
            clocking0: clocking0 {
                #clock-cells = <0>;
                assigned-clock-rates = <100000000>;
                assigned-clocks = <&zynqmp_clk 71>;
                clock-output-names = "fabric_clk";
                clocks = <&zynqmp_clk 71>;
                compatible = "xlnx,fclk";
            };
        };

の config-afi の部分が AXI バスのバス幅の設定です。
これはこちらの記事を参考にさせて頂きました。

また、clocking0 の部分がクロックで、pclk0 を 100MHz に設定しています。
これはこちらの記事を参考にさせて頂きました。

uioとudmabuf

続いて uio と udmabuf です。

    fragment@2 {
        target-path = "/amba";
        __overlay__ {
            #address-cells = <0x1>;
            #size-cells = <0x1>;
            
            uio_pl_peri {
                compatible = "generic-uio";
                reg = <0xa0000000 0x08000000>;
            };

            udmabuf4 {
                compatible = "ikwzm,udmabuf-0.10.a";
                minor-number = <4>;
                size = <0x00400000>;
            };
        };
    };

今回はペリフェラル領域をまとめて一個の uio に割り当てています。
開始アドレス 0xa0000000番地から サイズ 0x08000000 バイトの領域が uio_pl_peri という名前の uio として生成されます。

また udmabuf4 という名前で、0x00400000 バイトの CMA(Continuous Memory Allocator) を確保してもらうように指定しています。udmabuf を用いることで、連続した物理メモリアドレスを割り当ててもらうことが可能になります。

dtcでのコンパイル

dtc -I dts -O dtb -o ultra96v2_udmabuf_sample.dtbo ultra96v2_udmabuf_sample.dts

とすることで ultra96v2_udmabuf_sample.dtbo を得ることができます。

Overlay

いよいよ overlay です

configfs の mount

初めに configfs をマウントします。

sudo mkdir -p /configfs
sudo mount -t configfs configfs /configfs

詳しくはこちらこちらを参考にさせて頂いております。

ファームウェアのコピー

必要なものを /lib/firmware にコピーします。

sudo mkdir -p /lib/firmware
sudo cp ultra96v2_udmabuf_sample.bit.bin /lib/firmware
sudo cp ultra96v2_udmabuf_sample.dtbo /lib/firmware

overlay

次に overlay を行います。

sudo sh -c "echo 0 > /sys/class/fpga_manager/fpga0/flags"
sudo mkdir /configfs/device-tree/overlays/full
sudo sh -c "echo -n ultra96v2_udmabuf_sample.dtbo > /configfs/device-tree/overlays/full/path"

この段階で bitstream は書き込まれ、動作を開始しています。

状態確認

状態を確認するには

cat /configfs/device-tree/overlays/full/status

でできるようで applied と表示されればよいようです。

役目を終えたファイルは削除してよいようです。

sudo rm /lib/firmware/ultra96v2_udmabuf_sample.dtbo
sudo rm /lib/firmware/ultra96v2_udmabuf_sample.bit.bin

アプリケーションの実行

ここでアプロケーションを実行します。
/dev 以下に uio や dmabuf に対応するデバイスがが追加されているはずなのでそれらを開いてアクセスすることができます。

このやり方は別の記事で紹介しております。

詳しくはmain.cppをお読みください。

うまく動けば、udmabuf領域にPLのコアからと、Cortex-A53 の双方からアクセスして、データがやり取りできることが確認できます。
また、uio にマップした RADIO_LED もソフトウェアから点滅させています。

Device Tree Overlay の解除

すこし自信のないところなのですが

sudo rmdir /configfs/device-tree/overlays/full

と削除すると、解除できるようです。

おしらせ

2020/10/30 にて Qrunch がサービス終了したので移転してきた記事となります。
一時退避場所:https://github.com/ryuz/qrunch_blog

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1