FC2カウンター FPGAの部屋
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Vivado HLS で 2 つの引数から DMA Read する AXI4 Master モジュールを作る2

Vivado HLS で 2 つの引数から DMA Read する AXI4 Master モジュールを作る1”の続き。

前回は、x と y の平方数の和を求める C ソースコードをいろいろとチューニングしていった。しかし、入力の x と y を同じAXI4 インターフェースから取ってくるので、どうしても x と y をRead する DMA がバーストにならないという欠点があった。今回は、AXI4 インターフェースを独立な 3 個にすることで、DMA Read がバーストするようにしてみよう。

さて、AXI4 インターフェースを 3 個にするにはどうするかというと、x , y , result の 3 個の引数に独立な bundle を与えればよい。
今回の sum_of_squares.cpp を示す。

int sum_of_squares(volatile char *x, volatile char *y, volatile int *result){
#pragma HLS INTERFACE m_axi depth=10 port=y offset=slave bundle=y
#pragma HLS INTERFACE m_axi depth=10 port=x offset=slave bundle=x
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=10 port=result offset=slave bundle=result

    LOOP1: for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        char xt = x[i];
        char yt = y[i];

        result[i] = xt*xt + yt*yt;
    }

    return(0);
}


今回の sum_of_squares.cpp を合成した。結果を示す。
sum_of_squares_14_190821.png

PIPELINE の Initiation Interval が 1 クロックになった。これで完璧だ。
Verilog HDL のトップのファイル sum_of_squares.v の module 定義を引用すると、 x , y , result の 3 個のAXI4 インターフェースが実装されているのが分かる。

module sum_of_squares (
        ap_clk,
        ap_rst_n,
        m_axi_x_AWVALID,
        m_axi_x_AWREADY,
        m_axi_x_AWADDR,
        m_axi_x_AWID,
        m_axi_x_AWLEN,
        m_axi_x_AWSIZE,
        m_axi_x_AWBURST,
        m_axi_x_AWLOCK,
        m_axi_x_AWCACHE,
        m_axi_x_AWPROT,
        m_axi_x_AWQOS,
        m_axi_x_AWREGION,
        m_axi_x_AWUSER,
        m_axi_x_WVALID,
        m_axi_x_WREADY,
        m_axi_x_WDATA,
        m_axi_x_WSTRB,
        m_axi_x_WLAST,
        m_axi_x_WID,
        m_axi_x_WUSER,
        m_axi_x_ARVALID,
        m_axi_x_ARREADY,
        m_axi_x_ARADDR,
        m_axi_x_ARID,
        m_axi_x_ARLEN,
        m_axi_x_ARSIZE,
        m_axi_x_ARBURST,
        m_axi_x_ARLOCK,
        m_axi_x_ARCACHE,
        m_axi_x_ARPROT,
        m_axi_x_ARQOS,
        m_axi_x_ARREGION,
        m_axi_x_ARUSER,
        m_axi_x_RVALID,
        m_axi_x_RREADY,
        m_axi_x_RDATA,
        m_axi_x_RLAST,
        m_axi_x_RID,
        m_axi_x_RUSER,
        m_axi_x_RRESP,
        m_axi_x_BVALID,
        m_axi_x_BREADY,
        m_axi_x_BRESP,
        m_axi_x_BID,
        m_axi_x_BUSER,
        m_axi_y_AWVALID,
        m_axi_y_AWREADY,
        m_axi_y_AWADDR,
        m_axi_y_AWID,
        m_axi_y_AWLEN,
        m_axi_y_AWSIZE,
        m_axi_y_AWBURST,
        m_axi_y_AWLOCK,
        m_axi_y_AWCACHE,
        m_axi_y_AWPROT,
        m_axi_y_AWQOS,
        m_axi_y_AWREGION,
        m_axi_y_AWUSER,
        m_axi_y_WVALID,
        m_axi_y_WREADY,
        m_axi_y_WDATA,
        m_axi_y_WSTRB,
        m_axi_y_WLAST,
        m_axi_y_WID,
        m_axi_y_WUSER,
        m_axi_y_ARVALID,
        m_axi_y_ARREADY,
        m_axi_y_ARADDR,
        m_axi_y_ARID,
        m_axi_y_ARLEN,
        m_axi_y_ARSIZE,
        m_axi_y_ARBURST,
        m_axi_y_ARLOCK,
        m_axi_y_ARCACHE,
        m_axi_y_ARPROT,
        m_axi_y_ARQOS,
        m_axi_y_ARREGION,
        m_axi_y_ARUSER,
        m_axi_y_RVALID,
        m_axi_y_RREADY,
        m_axi_y_RDATA,
        m_axi_y_RLAST,
        m_axi_y_RID,
        m_axi_y_RUSER,
        m_axi_y_RRESP,
        m_axi_y_BVALID,
        m_axi_y_BREADY,
        m_axi_y_BRESP,
        m_axi_y_BID,
        m_axi_y_BUSER,
        m_axi_result_AWVALID,
        m_axi_result_AWREADY,
        m_axi_result_AWADDR,
        m_axi_result_AWID,
        m_axi_result_AWLEN,
        m_axi_result_AWSIZE,
        m_axi_result_AWBURST,
        m_axi_result_AWLOCK,
        m_axi_result_AWCACHE,
        m_axi_result_AWPROT,
        m_axi_result_AWQOS,
        m_axi_result_AWREGION,
        m_axi_result_AWUSER,
        m_axi_result_WVALID,
        m_axi_result_WREADY,
        m_axi_result_WDATA,
        m_axi_result_WSTRB,
        m_axi_result_WLAST,
        m_axi_result_WID,
        m_axi_result_WUSER,
        m_axi_result_ARVALID,
        m_axi_result_ARREADY,
        m_axi_result_ARADDR,
        m_axi_result_ARID,
        m_axi_result_ARLEN,
        m_axi_result_ARSIZE,
        m_axi_result_ARBURST,
        m_axi_result_ARLOCK,
        m_axi_result_ARCACHE,
        m_axi_result_ARPROT,
        m_axi_result_ARQOS,
        m_axi_result_ARREGION,
        m_axi_result_ARUSER,
        m_axi_result_RVALID,
        m_axi_result_RREADY,
        m_axi_result_RDATA,
        m_axi_result_RLAST,
        m_axi_result_RID,
        m_axi_result_RUSER,
        m_axi_result_RRESP,
        m_axi_result_BVALID,
        m_axi_result_BREADY,
        m_axi_result_BRESP,
        m_axi_result_BID,
        m_axi_result_BUSER,
        s_axi_AXILiteS_AWVALID,
        s_axi_AXILiteS_AWREADY,
        s_axi_AXILiteS_AWADDR,
        s_axi_AXILiteS_WVALID,
        s_axi_AXILiteS_WREADY,
        s_axi_AXILiteS_WDATA,
        s_axi_AXILiteS_WSTRB,
        s_axi_AXILiteS_ARVALID,
        s_axi_AXILiteS_ARREADY,
        s_axi_AXILiteS_ARADDR,
        s_axi_AXILiteS_RVALID,
        s_axi_AXILiteS_RREADY,
        s_axi_AXILiteS_RDATA,
        s_axi_AXILiteS_RRESP,
        s_axi_AXILiteS_BVALID,
        s_axi_AXILiteS_BREADY,
        s_axi_AXILiteS_BRESP,
        interrupt
);


C/RTL 協調シミュレーションを行った。
sum_of_squares_15_190821.png

Latency は 84 クロックに減っている。

C/RTL 協調シミュレーションの波形を示す。
sum_of_squares_16_190821.png

result の DMA Write と y の DMA Read の波形だ。 y の DMA Read は ARLEN が 3 になっていてバーストで Read しているのが分かる。 x も波形がここにはないが同様にバースト Read してる。

これで、このインターフェースでのチューニングは終了だが、3 個のAXI4 インターフェースが実装されているのがもったいないと感じる。オーバースペックじゃないかな?
x と y は 8 ビットなので、バス幅 32 ビットの内の 8 ビットを 2 個使えば良いのではないか?というコンセプトで次回の検討を行おう。
  1. 2019年08月21日 05:04 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS で 2 つの引数から DMA Read する AXI4 Master モジュールを作る1

Vivado HLS で 2 つの入力のAXI4 Master モジュールを作ってみよう。題材は平方数の和を求めるコードだ。

まずは、ap_int 型を使って作ってみよう。
Source は sum_of_squares.cpp とした。

#include <ap_int.h>

int sum_of_squares(volatile ap_int<8> *x, volatile ap_int<8> *y, volatile ap_int<17> *result){
#pragma HLS INTERFACE m_axi depth=10 port=y offset=slave
#pragma HLS INTERFACE m_axi depth=10 port=x offset=slave
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=10 port=result offset=slave

    for(int i=0; i<10; i++){
        result[i] = x[i]*x[i] + y[i]*y[i];
    }

    return(0);
}


Testbench は sum_of_squares_tb.cpp とした。

// sum_of_squares_tb.cpp

#include <iostream>
#include <ap_int.h>

int sum_of_squares(volatile ap_int<8> *x, volatile ap_int<8> *y, volatile ap_int<17> *result);

int main(){
    ap_int<8> x[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    ap_int<8> y[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    ap_int<17> result[10];

    sum_of_squares(x, y, result);

    for(int i=0; i<10; i++){
        std::cout << "x[" << i << "]= " << (int)x[i] <<
                ", y[" << i << "] = " << (int)y[i] <<
                ", result[" << i << "] = " <<
                result[i] << std::endl;
    }
}


Vivado HLS 2018.3 で sum_of_squares プロジェクトを作成した。使用するFPGA は xc7z010clg400-1 のZYBO Z7-10 を想定している。
sum_of_squares_1_190820.png

C シミュレーションをするとエラーになった。
sum_of_squares_2_190820.png

最初のエラーを貼る。

../../../sum_of_squares.cpp: 関数 ‘int sum_of_squares(volatile ap_int<8>*, volatile ap_int<8>*, volatile ap_int<17>*)’ 内:
../../../sum_of_squares.cpp:10:19: エラー: no match for ‘operator*’ (operand types are ‘volatile ap_int<8>’ and ‘volatile ap_int<8>’)
   result[i] = x[i]*x[i] + y[i]*y[i];


なんと乗算の定義が無い様だ。
なお、”高位合成ユーザーズ ガイド UG902 (v2018.3) 2018 年 12 月 20 日”の 90 ページに

値が複数回更新されるデータ信号を指定するには、volatile 修飾子を使用してください。

と書いてあるので、volatile は必要だ。

エラーを回避するにはどうするかというと、char と int に引数の方を変えてみよう。
sum_of_squares.cpp を示す。

int sum_of_squares(volatile char *x, volatile char *y, volatile int *result){
#pragma HLS INTERFACE m_axi depth=10 port=y offset=slave
#pragma HLS INTERFACE m_axi depth=10 port=x offset=slave
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=10 port=result offset=slave

    for(int i=0; i<10; i++){
        result[i] = x[i]*x[i] + y[i]*y[i];
    }

    return(0);
}


sum_of_squares_tb.cpp を示す。

// sum_of_squares_tb.cpp

#include <iostream>

int sum_of_squares(volatile char *x, volatile char *y, volatile int *result);

int main(){
    char x[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    char y[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int result[10];

    sum_of_squares(x, y, result);

    for(int i=0; i<10; i++){
        std::cout << "x[" << i << "]= " << (int)x[i] <<
                ", y[" << i << "] = " << (int)y[i] <<
                ", result[" << i << "] = " <<
                result[i] << std::endl;
    }
}


C シミュレーションを行った。
sum_of_squares_3_190820.png

今度は成功した。”高位合成ユーザーズ ガイド UG902 (v2018.3) 2018 年 12 月 20 日”のAXI4 Master のサンプルの引数の型が int なのはこのような理由なのだろうか?

C コードの合成を行った。結果を示す。
sum_of_squares_4_190820.png

AXI4 Lite Slave のアドレスマップを示す。

//------------------------Address Info-------------------
// 0x00 : Control signals
//        bit 0  - ap_start (Read/Write/COH)
//        bit 1  - ap_done (Read/COR)
//        bit 2  - ap_idle (Read)
//        bit 3  - ap_ready (Read)
//        bit 7  - auto_restart (Read/Write)
//        others - reserved
// 0x04 : Global Interrupt Enable Register
//        bit 0  - Global Interrupt Enable (Read/Write)
//        others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x10 : Data signal of ap_return
//        bit 31~0 - ap_return[31:0] (Read)
// 0x18 : Data signal of x
//        bit 31~0 - x[31:0] (Read/Write)
// 0x1c : reserved
// 0x20 : Data signal of y
//        bit 31~0 - y[31:0] (Read/Write)
// 0x24 : reserved
// 0x28 : Data signal of result
//        bit 31~0 - result[31:0] (Read/Write)
// 0x2c : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


C/RTL 協調シミュレーションを行った。
sum_of_squares_5_190820.png

0x18 番地(x のアドレス)には 0 、0x20 番地(y のアドレス)には 0xC 、 0x28 番地(result のアドレス)には 0x18 を書いている。
C/RTL 協調シミュレーションの波形を拡大した図を示す。
sum_of_squares_6_190820.png

AXI4 Master Read は、ARLEN が 00 なので単発のアクセス、AXI4 Master Write は AWLEN が 09 なので、バースト・アクセスとなる。
x の値は 2 回 Read されている。 y の値も 2 回 Read されているようだ。

次に、sum_of_squares.cpp の for 文に PIPELINE 指示子を追加してみよう。

int sum_of_squares(volatile char *x, volatile char *y, volatile int *result){
#pragma HLS INTERFACE m_axi depth=10 port=y offset=slave
#pragma HLS INTERFACE m_axi depth=10 port=x offset=slave
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=10 port=result offset=slave

    LOOP1: for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        result[i] = x[i]*x[i] + y[i]*y[i];
    }

    return(0);
}


C コードの合成結果を示す。
sum_of_squares_10_190820.png

約 1/3 程度のLatency になった。

C/RTL 協調シミュレーション結果を示す。
sum_of_squares_8_190820.png

C/RTL 協調シミュレーションの波形を拡大した図を示す。
sum_of_squares_9_190820.png

1 回の演算を行うのに、合計 40 回 Read している。 write は 10 回だ。

それじゃ、このRead のアクセス回数を 1/2 にしてみよう。
Source の sum_of_squares.cpp のコードを以下のように変更した。

int sum_of_squares(volatile char *x, volatile char *y, volatile int *result){
#pragma HLS INTERFACE m_axi depth=10 port=y offset=slave
#pragma HLS INTERFACE m_axi depth=10 port=x offset=slave
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=10 port=result offset=slave

    LOOP1: for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        char xt = x[i];
        char yt = y[i];

        result[i] = xt*xt + yt*yt;
    }

    return(0);
}


C コードの合成結果を示す。
sum_of_squares_11_190820.png

Initiation Interval が 4 クロックから 2 クロックになった。

C/RTL 協調シミュレーションの結果を示す。
sum_of_squares_12_190820.png

C/RTL 協調シミュレーションの波形を示す。
sum_of_squares_13_190820.png

Read が 20 回になった。
  1. 2019年08月20日 05:27 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Ultra96-V2 でカメラ画像をDisplayPort に出力する3(完成)

Ultra96-V2 でカメラ画像をDisplayPort に出力する2(Ultra96-V2 の環境整備)”の続き。

前回は、bin ファイルを作成し、Ultra96-V2 のDebian を起動して、環境の整備を行った。しかし、fclkcfg でエラーが出てしまい、目的の周波数に pl_clk0 を設定することができなかった。pl_clk0 は 100 MHz に設定されたので、XGA 解像度でカメラ画像をDisplayPort に表示することはできたが、HD 解像度で表示することはできなかった。今回は、ikwzm さんがfclkcfg のバグを修正してくれたので、HD 解像度でのDisplayPort 出力を試してみよう。

ikzwm さんの以下のツィートでfclkcfg を修正していただいたのがわかった。ありがとうございました。

ZynqMP-FPGA-Linux v2019.1.2 を緊急リリースしていただいた。

Ubuntu 18.04 のホストパソコンの方で、ZynqMP-FPGA-Linux にgit pull しようとしたが、うまくアップデートできなかった。
よって、一度削除してからもう一度ダウンロードすることにした。
rm -rf ZynqMP-FPGA-Linux
git clone -b v2019.1.0 git://github.com/ikwzm/ZynqMP-FPGA-Linux
cd ZynqMP-FPGA-Linux
git lfs pull


これだけだと v2019.1.2 になってなかったので、次のコマンドを入力した。
git pull git://github.com/ikwzm/ZynqMP-FPGA-Linux v2019.1.2
cam_dp_V2_24_190819.png

これで変更されたのは、image-4.19.0-xlnx-v2019.1-zynqmp_fpga だけだったので、これだけをMicro SD カードのboot パーティションの同じ名前のファイルと入れ替えた。
cam_dp_V2_23_190819.png

Micro SD カードをUltra96-V2 に入れて、電源ON し、Debian をブートした。
cd example/cam_dp_V2/
./lddtorvary.sh
./cam_dp_ov5642 -r 2
./disp_pattern.sh


すると、DisplayPort にHD 解像度のカメラ画像が表示された。
cam_dp_V2_25_190819.png

cam_dp_V2_26_190819.jpg

./lddtorvary.sh を起動した時のメッセージを示す。
cam_dp_V2_27_190819.png

pl_clk0 は 214285713 Hz だそうだ。うまく設定されているようだ。
なお、pl_clk1 は rpll になっているが、DTS ファイルの<&zynqmp_clk 0x48 &zynqmp_clk 1>の最後の 1 が rpll を示すようだ。ここが 0 だと iopll になる。
  1. 2019年08月19日 21:20 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96-V2 でカメラ画像をDisplayPort に出力する2(Ultra96-V2 の環境整備)

Ultra96-V2 でカメラ画像をDisplayPort に出力する1(ブロックデザイン)”の続き。

前回は、Ultra96-V2 でPMOD 拡張ボードに搭載したOV5642 カメラの画像をUltra96-V2 のDisplayPort から出力したいということで、Ultra96-V1 のブロックデザインの内のZynq UltraScale+ MPSoC のDDR の設定をUltra96-V2 用に変更して、論理合成、インプリメンテーション、ビットストリームの生成を行って、成功した。今回は、bin ファイルを作成し、Ultra96-V2 のDebian を起動して、環境の整備を行う。

最初に、Vivado 2018.2 でビットストリームが生成できたので、ハードウェアをエクスポートして、SDK を立ち上げた。 cam_dp_183.sdk ディレクトリに新たに cam_dp_wrapper_hw_platform_1 が生成された。
cam_dp_V2_7_190818.png

カメラ画像をDisplayPortに出力する7(binファイルの生成)”の cam_dp_wrapper.bif と bootgen.sh を作成した。bootgen.sh に実行権限を与えて、実行した。
chmod +x bootgen.sh
./bootgen.sh


cam_dp_wrapper.bin が生成された。これをUltra96-V2 の /home/fpga/examples/cam_dp_V2/ ディレクトリにSFTP でアップロードした。
cam_dp_V2_9_190818.png

次に、Ultra96-V2 の /home/fpga/examples/cam_dp_V2/ ディレクトリに入った。
fpga-load.dts を作った。これからのファイルは、”カメラ画像をDisplayPortに出力する8(Ultra96 での準備)”のコードをコピーして作っている。ただし、fclk01-zynqmp.dts は修正してある。
cam_dp_V2_10_190818.png

fclk01-zynqmp.dts を示す。このファイルは、、”カメラ画像をDisplayPortに出力する8(Ultra96 での準備)”のコードを修正してある。(注)画像の pl_clk0 は 200 MHz ですが、コードの方の 220 MHz に修正済みです。
cam_dp_V2_11_190818.png

/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba_pl@0";
        __overlay__ {
            fclk0 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&zynqmp_clk 0x47 &zynqmp_clk 0>;
                insert-rate   = "220000000";
                insert-enable = <1>;
                remove-rate   = "1000000";
                remove-enable = <0>;
            };
            
            fclk1 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&zynqmp_clk 0x48 &zynqmp_clk 1>;
                insert-rate   = "24000000";
                insert-enable = <1>;
                remove-rate   = "1000000";
                remove-enable = <0>;
            };
        };
    };
};



cam_dp.dts を示す。
cam_dp_V2_12_190818.png

dtc_script.sh を示す。
cam_dp_V2_13_190818.png

lddtovary.sh を示す。
cam_dp_V2_14_190818.png

rmdtovary.sh を示す。
cam_dp_V2_15_190818.png

.sh のファイルに実行権限を与えた。
chmod +x *.sh
cam_dp_V2_16_190818.png

./dtc_script.sh
でDTS ファイルをコンパイルして、DTB ファイルを出力した。
cam_dp_V2_17_190818.png

./lddtovary.sh
を実行してデバイスツリーをロードした。ログを示す。
cam_dp_V2_18_190818.png

fclkcfg でエラーが出ている。

zynqmp_clk_divider_set_rate() set divider failed for pl0_ref_div1, ret = -22


これのせいか? 220 MHz のはずの pl_clk0 が 99999999 Hz になってしまっている。

/sys/class/uio は uio0 〜 uio 9 まであった。この内の uio4 〜 uio9 までが cam_dp.dtb でデバイスツリーに追加した uio だ。
cam_dp_V2_19_190818.png

udmabuf4 もデバイスツリーに追加されていた。
cam_dp_V2_20_190818.png
  1. 2019年08月18日 15:47 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96-V2 でカメラ画像をDisplayPort に出力する1(ブロックデザイン)

Ultra96-V2 のDisplayPort にテストパターンを表示する4(テストパターンを表示できた)”でUltra96-V2 でDisplayPort にテストパターンを表示することができた。今回は、Ultra96-V2 でカメラ画像をDisplayPort に出力してみようと思う。

カメラ画像をDisplayPortに出力する7(ブロックデザインの変更)”の cam_dp_183 の Vivado 2018.3 プロジェクトがあるので、ディレクトリごと Ultra96V2 ディレクトリにコピーして、ディレクトリの名前を cam_dp_V2_183 に変更した。
cam_dp_V2_1_190817.png

Vivado 2018.3 で ~/HDL/Ultra96/Ultra96V2/cam_dp_V2_183/ ディレクトリの cam_dp_183 プロジェクトを開いた。
cam_dp_V2_2_190817.png

今回は、ひでみさんの「FPGAの内容が薄い本2」に書かれているが、Ultra96V1 とUltra96V2 の設定の違いを使用して、Ultra96V1 用のプロジェクトをUltra96-V2 用に変換してみよう。

ブロックデザインのZYNQ UltraScale+ IP をダブルクリックして、設定を開き、Page Navigator から DDR Configuration を開く。
cam_dp_V2_3_190817.png

DDR Configuration 画面で、
DRAM Device Capacity (per 32-bit channel) を 16384 MBits
Row Address Count (Bits) を 16
Dual Rank のチェックボックスをのチェックを無し
に変更した。
cam_dp_V2_4_190817.png

Address Editor を示す。
cam_dp_V2_6_190817.png

変更後に論理合成、インプリメンテーション、ビットストリームの生成を行った。
うまく行ったようだ。結果を示す。
cam_dp_V2_5_190817.png
  1. 2019年08月17日 05:32 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

sudo: unable to resolve host の表示を止める

現在、Ultra96-V2 の ikwzm さんのDebian を使用して、 sudo コマンドを使用すると”sudo: unable to resolve host debian-fpga: Name or service not known”が表示されてしまう。
DisplayPort_test_V2_46_190816.png

ある方に解決方法を教えていただいたのだが、忘れてしまったため、Web を検索してやってみた。忘れないようにブログに書いておく。
sudo: unable to resolve host が表示されたら”を参照させていただきながらやっていく。

まずは、/etc/hosts を確認する。

127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters


/etc/hosts にホスト名を追加する。
sudo sh -c 'echo 127.0.1.1 $(hostname) >> /etc/hosts'

もう一度、/etc/hosts を見ると、ホスト名が追加されていた。

127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

127.0.1.1 debian-fpga


これで、sudo コマンドを実行しても”sudo: unable to resolve host debian-fpga: Name or service not known”が表示されなくなった。感謝。。。
DisplayPort_test_V2_47_190816.png
  1. 2019年08月16日 04:47 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

Ultra96-V2 のDisplayPort にテストパターンを表示する4(テストパターンを表示できた)

Ultra96-V2 のDisplayPort にテストパターンを表示する3(各種スクリプト・ファイルやDTS ファイルの用意)”の続き。

前回は、各種スクリプト・ファイルやDTS ファイルを用意し、DTS ファイルをコンパイルしてDTB ファイルに変換した。今回は、つまずきはあったが、テストパターンをDisplayPort に出力することができた。

最初に、pattarn_gen_axis.c を gcc でコンパイルした。
gcc -o pattern_gen_axis pattern_gen_axis.c
次に、displayport_test_xga1_sync.bin を /lib/firmware/ ディレクトリにコピーした。
sudo cp displayport_test_xga1_sync.bin /lib/firmware/
DisplayPort_test_V2_35_190815.png

./lddtovray.sh
を実行したところエラーが発生した。
lddtovray.sh のコマンドを1個ずつ実行していったところ、fclkcfg でエラーが出ているのが分かった。
fclkcfg の DTS ファイルを下に示す。
DisplayPort_test_V2_27_190814.png

だが、ikwzm さんの”ZynqMP 向け Debian/Linux(v2019.1版) でFPGA クロックの周波数の変更に失敗する件”を見ると、fclkcfg の DTS ファイルの書き方が違っている。ikwzm さんがツィッターで教えていただいたのだが、

大元のデバイスツリーのクロックコントローラーのラベル(シンボル)が v2018.2 では &clk だったのが v2019.1 から &zynqmp_clk に変更されちゃいました。

だそうだ。
という訳で、fclk0-zynqmp.dts を書き換えた。

/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba_pl@0";
        __overlay__ {
            fclk0 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&zynqmp_clk 0x47 &zynqmp_clk 0>;
                insert-rate   = "100000000";
                insert-enable = <1>;
                remove-rate   = "1000000";
                remove-enable = <0>;
            };
        };
    };
};


DisplayPort_test_V2_37_190815.png

./dtc_script.sh
コンパイルしてから、fclkcfg のデバイスツリーをロードしたところ、問題なくロードできた。
下の図に示す。ピンクで囲ったところが、fclkcfg のエラー部分だ。
DisplayPort_test_V2_36_190815.png

DisplayPort_test_V2_38_190815.png

/sys/class/fclk0/ ディレクトリが生成されている。
DisplayPort_test_V2_39_190815.png

uio のデバイスツリーのロードを行った。
sudo mkdir /config/device-tree/overlays/pattern_gen_axis
sudo cp pattern_gen_axis.dtb /config/device-tree/overlays/pattern_gen_axis/dtbo


同様に、/sys/classe/ を見ると、uio0 〜 uio4 があったが、その内の uio4 の name が pattern_gen_axis-uio だった。
DisplayPort_test_V2_40_190815.png

ということは、pattern_gen_axis の uio 番号が違っているので、pattern_gen_axis.c を変更した。
DisplayPort_test_V2_41_190815.png

// pattern_gen_axis.c
// 2019/01/18 by marsee
// 2019/08/15 : Changed to /dev/uio4 for Ultra96-V2. by marsee
//

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

int main(){
    int fd4;
    volatile unsigned *pga;
    int i;

    // uio initialize (uio1)
    fd4 = open("/dev/uio4", O_RDWR|O_SYNC); // pattern_gen_axis IP
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio4 (pattern_gen_axis) open error\n");
        exit(1);
    }
    pga = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (!pga){
        fprintf(stderr, "pattern_gen_axis mmap error\n");
        exit(1);
    }

    pga[4] = 768; // v_size
    pga[6] = 1024; // h_size
    pga[8] = 0x1; // init_done = 1
    
    printf("sizeof volatile unsigned = %d\n", sizeof(volatile unsigned));
    
    printf("v_size = %d, h_size = %d, init_done = %d\n", pga[4], pga[6], pga[8]);
    
    munmap((void *)pga, 0x10000);
    close(fd4);
    
    return(0);
}


もう一度、gcc でコンパイルした。
gcc -o pattern_gen_axis pattern_gen_axis.c
pattern_gen_axis を sudo で実行した。
sudo ./pattern_gen_axis
DisplayPort の設定を行った。
./disp_pattern.sh
DisplayPort_test_V2_42_190815.png

しかし、memwrite が無かった。
Ultra96のDisplayPortを使用するためのテスト3(実機テスト)”から memwrite.c にコードを持ってきた。
DisplayPort_test_V2_43_190815.png

gcc -o memwrite memwrite.c
でコンパイルし、実行したところ、DisplayPort にテストパターンが表示された。良かった。。。
DisplayPort_test_V2_44_190815.png

DisplayPort_test_V2_45_190816.jpg
  1. 2019年08月16日 04:29 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0
»