FC2カウンター FPGAの部屋 FPGA+SoC+Linux実践勉強会での課題をやってみた6(udmabuf、実機テスト)
FC2ブログ

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

FPGAの部屋

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

FPGA+SoC+Linux実践勉強会での課題をやってみた6(udmabuf、実機テスト)

FPGA+SoC+Linux実践勉強会での課題をやってみた5(FPGA Region)”の続き。

前回は、Vivado HLS 2017.3 で作成した 2 乗倍するDMAIP をVivado 2017.3 のブロック・デザインでインスタンスして構成した回路で Device Tree Overlay でデバイスツリー・オーバーレイで、 FPGA Region を使用して、ビット・ファイルをコンフィギュレーションした。今回は、それに加えて udmabuf を実装し、udmabuf を使用し、更にアプリケーションソフトを書いて、dma_pow2 IP を動作させてみよう。

FPGA+SoC+Linux実践勉強会資料”の 94 ページの「デバイスの追加 - DMA バッファの確保 (1)」のコードを fpga_dma_pwo2.dts にコピー&ペーストして、fpga_udma_dma_pow2.dts とした。そして、size を 64 Kバイトの領域に変更した。
fpga_udma_dma_pow2.dts を示す。

/dts-v1/; /plugin/;
/ {
  fragment@1 {
    target-path = "/amba/fpga-region0";
    #address-cells = <1>;
    #size-cells = <1>;
    __overlay__ {
      #address-cells = <1>;
      #size-cells = <1>;
      firmware-name = "test_dma_wrapper.bin";
      dma_pow2@43c00000 { 
        compatible = "generic-uio";
        reg = <0x43c00000 0x10000>;
        #interrupts = <0x0 0x1d 0x4>;
      };
      udmabuf0@0x00 {
        compatible = "ikwzm,udmabuf-0.10.a";
        device-name = "udmabuf0";
        size = <0x00010000>;
      }; 
    };
  };
};


dtbocfg.rb を使用して、デバイスツリー・オーバーレイを行う。ZYBO Z7 のPL にtest_dma_wrapper.bin がダウンロードされて、dma_pow2 の uio ドライバが実装され、udmabuf0 も実装されるはずだ。
コマンドとしては、
sudo dtbocfg.rb -i test_dma --dts fpga_udma_dma_pow2.dts
を実行した。
ls /config/device-tree/overlays
を実行すると test_dma ディレクトリが生成されていた。
ls /sys/devices/soc0/amba/amba\:fpga-region0/
を実行すると、43c00000.dma_pow2 が生成されているのが分かった。
FPGA-SoC-Linux4ZYBO_Z7_73_171214.png

ls /dev を実行すると uio0 と udmabuf0 が見えた。
FPGA-SoC-Linux4ZYBO_Z7_74_171214.png

dma_pow2 IP を使用するためのアプリケーションソフト test_dma.c を作成した。
test_dma.c を示す。

// test_dma.c
// 2017/12/12 by marsee
//

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

int main(){
    int fd0, fd1, fd2;
    
    volatile unsigned int *dma_pow2_0;
    volatile unsigned int *cma_buffer;
    
    char  attr[1024];
    unsigned long  phys_addr;
    int i;
    
    // dma_pow2_0 (UIO0)
    fd0 = open("/dev/uio0", O_RDWR); // dma_pow2_0 interface AXI4 Lite Slave
    if (fd0 < 1){
        fprintf(stderr, "/dev/uio0 (dma_pow2_0) open error\n");
        exit(-1);
    }
    dma_pow2_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd0, 0);
    if (!dma_pow2_0){
        fprintf(stderr, "dma_pow2_0 mmap error\n");
        exit(-1);
    }
    
    // udmabuf0
    fd1 = open("/dev/udmabuf0", O_RDWR); // frame_buffer, The chache is enabled. 
    if (fd1 == -1){
        fprintf(stderr, "/dev/udmabuf0 open error\n");
        exit(-1);
    }
    cma_buffer = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!cma_buffer){
        fprintf(stderr, "cma_buffer mmap error\n");
        exit(-1);
    }
    
    // phys_addr of udmabuf0
    fd2 = open("/sys/class/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fd2 == -1){
        fprintf(stderr, "/sys/class/udmabuf/udmabuf0/phys_addr open error\n");
        exit(-1);
    }
    read(fd2, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd2);
    printf("phys_addr = %x\n", (int)phys_addr);
    
    dma_pow2_0[6] = phys_addr;    // 0x18 Data signal of in_r
    dma_pow2_0[8] = phys_addr+sizeof(int)*10;    // 0x20 Data signal of out_r
    
    for(i=0; i<10; i++)
        cma_buffer[i] = i;
    
    dma_pow2_0[0] = 1// Start
    
    while(!(dma_pow2_0[0] & 0x2));    // wait done signal
    
    printf("in[] =  ");
    for(i=0; i<10; i++)
        printf("%2d ", cma_buffer[i]);
    printf("\n");
    
    printf("out[] = ");
    for(i=10; i<20; i++)
        printf("%2d ", cma_buffer[i]);
    printf("\n");
    
    munmap((void *)dma_pow2_0, 0x10000);
    munmap((void *)cma_buffer, 0x10000);

    close(fd0);
    close(fd1);
    
    return(0);
}


PS からのPL のクロックはFCLK_CLK0 は 100 MHz で出力されるように設定されているということなので、test_dma を実行してみよう。
最初に gcc でコンパイルを行った。
gcc -o test_dma test_dma.c
エラーは無かった、というかエラーが発生しないようにデバックしたのだ。
./test_dma で実行したところ、/dev/uio0 が開けなかった。
しまった、uio0 と udmabuf のパーミッションの設定で、ユーザーには開けなかったんだった。
sudo chmod 666 /dev/uio0 /dev/udmabuf0
を実行して、uio0 と udmabuf のパーミッションを設定して、ユーザーでも開けるように変更した。
もう一度、./test_dma を実行した。
FPGA-SoC-Linux4ZYBO_Z7_75_171214.png

in[] を 2乗した値が out[] に出力されているのが分かる。成功だ。ACP ポートを使用しているので、udmabuf をキャッシュ・オンにしているのだが、きちんとARMプロセッサが読めているようだ。
  1. 2017年12月14日 04:57 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/4002-b6cf31af
この記事にトラックバックする(FC2ブログユーザー)