FC2カウンター FPGAの部屋 ZUBoard 1CG の i4filters プロジェクトの回路を Petalinux で動作させる13
fc2ブログ

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

FPGAの部屋

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

ZUBoard 1CG の i4filters プロジェクトの回路を Petalinux で動作させる13

ZUBoard 1CG の i4filters プロジェクトの回路を Petalinux で動作させる12”の続き。

ZUBoard 1CG の i4filters プロジェクトの回路を Petalinux で動作させる5”で作成した Vitis 2022.2 のアプリケーション・プロジェクトに C 言語のソースコードを書いて、PYNQ で動作させている回路で、動かしてみよう。

最初に、Micro SD カードを書き換える必要がある。
Vivado 2022.2 の i4filters プロジェクトのビット・ファイルが入った BOOT.BIN に入れ替える必要があるので、Micro SD カードの BOOT.BIN, boot.scr, image.ub を入れ替えた。
Micro SD カードの BOOT.BIN, boot.scr, image.ub を消去した。
ZUBoard1CG/Avnet_2022_2/petalinux/projects/zub1cg_i4filters/images/linux の BOOT.BIN, boot.scr, image.ub を MicroSD カードにコピーした。
zub1cg_i4filters_92_231009.png

zub1cg_i4filters_93_231009.png

Micro SD カードを ZUBoard 1CG に入れて電源 ON + SW7 を押してブートした。
Petalinux 2022.2 が起動した。
ifconfig で IP アドレスを表示させた。
zub1cg_i4filters_94_231009.png

HDL/2023.1/zub1cg/i4filters/vitis_work ディレクトリの下に upload_files ディレクトリを作成し、HDL/2023.1/zub1cg/i4filters_peta/vitis_work/upload_files の test2.bmp, u-dma-buf.ko をコピーした。
zub1cg_i4filters_95_231009.png

FillZilla で test2.bmp, u-dma-buf.ko をホーム・ディレクトリにコピーした。
zub1cg_i4filters_96_231009.png

u-dma-buf.ko を insmod でロードした。
sudo insmod u-dma-buf.ko udmabuf0=2880000
zub1cg_i4filters_100_231009.png

なお、この場合のメモリ使用量は 800 ピクセル x 600 行 x 3 バイト x 2 = 2880000 バイトとなる。

Vitis 2022.2 の zub1cg_i4filters_system -> zub1cg_i4filters -> src に bmp_header.h と zub1cg_i4filters.c の 2 つのソースファイルを書いた。
トンカチ・ボタンをクリックして、ビルドを行ったところ、成功した。
zub1cg_i4filters_97_231009.png

Vitis 2022.2 の Explorer の zub1cg_i4filters_peta_system を右クリックし右クリックメニューから Debug As -> Debug Configurations... を選択した。

Debug Configurations ダイアログが開いた。
System Project Debug を右クリックし、右クリックメニューから New Configuration を選択した。

System Project Debug の下に SystemDebugger_zub1cg_i4filters_system が生成された。

Linux TCF Agent の New ボタンをクリックして、新しい TCF Agent のエントリを作成する。
Target Connection Details ダイアログが表示された。
Host には ZUBoard 1CG の Petalinux の IP アドレスを入力した。

Test Connection ボタンをクリックした。
connection successful! ダイアログが表示された。

OK ボタンをクリックして、Target Connection Details ダイアログを閉じた。
Debug Configurations ダイアログに戻った。

Remote Working Directory: に /home/petalinux を入力した。
zub1cg_i4filters_97_231009.png

Apply ボタンをクリックし、Debug ボタンをクリックすると、ソフトウェアが起動して、最初の行で止まっている。
zub1cg_i4filters_99_231009.png

Resume ボタンをクリックし、ソフトウェアを最後まで走らせた。
正常終了したようだ。
zub1cg_i4filters_101_231009.png

終了後、output_img.bmp ファイルが生成されていた。
zub1cg_i4filters_102_231009.png

output_img.bmp ファイルを FileZilla でパソコンにダウンロードした。
zub1cg_i4filters_103_231009.png

output_img.bmp ファイルはソーベル・フィルタ処理後の画像だった。
成功だ。。。
zub1cg_i4filters_104_231009.png

zub1cg_i4filters_105_231009.jpg

最後に zub1cg_i4filters.c のソースコードを貼っておく。

// zub1cg_i4filters.c
// 2023/10/04 by marsee
//

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

#include "bmp_header.h"

char INPUT_IMG_FILE[] = "test2.bmp";
char OUTPUT_IMG_FILE[] = "output_img.bmp";

#define BLOCK_SIZE      4096
#define IMAGE_WIDTH     800
#define IMAGE_HEIGHT    600
#define IMAGE_CHANNEL   3
#define MAT_IMGAGE_BUF  (IMAGE_WIDTH*IMAGE_HEIGHT*IMAGE_CHANNEL)

#define MM2S_CONTROL_REG        0x00
#define MM2S_STATUS_REG         (0x4 >> 2)
#define MM2S_START_ADDR         (0x18 >> 2)
#define MM2S_LENGTH_REG         (0x28 >> 2)
#define S2MM_CONTROL_REG        (0x30 >> 2)
#define S2MM_STATUS_REG         (0x34 >> 2)
#define S2MM_DESTINATION_ADDR   (0x48 >> 2)
#define S2MM_LENGTH_REG         (0x58 >> 2)
// bits 1 - idle
#define MM2S_IDLE_MASK  0x2
#define S2MM_IDLE_MASK  0x2

#define GUSSIAN_CONTROL     0x00
#define GUSSIAN_FUNCTON_R   (0x18 >> 2)
#define GUSSIAN_ROW_SIZE    (0x20 >> 2)
#define GUSSIAN_COL_SIZE     (0x28 >> 2)

#define MEDIAN_CONTROL      0x00
#define MEDIAN_FUNCTION_R   (0x18 >> 2)
#define MEDIAN_ROW_SIZE     (0x20 >> 2)
#define MEDIAN_COL_SIZE     (0x28 >> 2)

#define COLOR_CONVERTER_CONTROL     0x00
#define COLOR_CONVERTER_FUNCTION_R  (0x18 >> 2)
#define COLOR_CONVERTER_ROW_SIZE    (0x20 >> 2)
#define COLOR_CONVERTER_COL_SIZE    (0x28 >> 2)
#define COLOR_CONVERTER_RED_MAG     (0x30 >> 2)
#define COLOR_CONVERTER_GREEN_MAG   (0x38 >> 2)
#define COLOR_CONVERTER_BLUE_MAG    (0x40 >> 2)

#define SOBEL_CONTROL       0x00
#define SOBEL_FUNCTION_R    (0x18 >> 2)
#define SOBEL_ROW_SIZE      (0x20 >> 2)
#define SOBEL_COL_SIZE      (0x28 >> 2)

volatile uint32_t *reg;

int main(){
    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw;
    volatile uint8_t *rd_bmp, *wr_bmp;
    uint32_t blue, green, red;
    int fd4, fd5, fd6, fd7, fd8, fd9;
    volatile uint32_t *axi_dma;
    volatile uint32_t *color_converter_RGB24;
    volatile uint32_t *gaussian_axis_RGB24;
    volatile uint32_t *median_axis_RGB24;
    volatile uint32_t *sobel_axis_RGB24;
    volatile uint8_t *image_buf;
    u_int32_t fd_paddr;
    unsigned char  attr[1024];
    unsigned long  phys_addr;

    // Image file open
    if ((fbmpr = fopen(INPUT_IMG_FILE, "rb")) == NULL){ // test.bmp をオープン
        fprintf(stderr, "Can't open %s by binary read mode\n", INPUT_IMG_FILE);
        exit(1);
    }
    // bmpヘッダの読み出し
    fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
    fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
    fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
    uint32_t image_all_pixels = bmpihr.biHeight * bmpihr.biWidth;
    uint32_t image_all_bytes = image_all_pixels * IMAGE_CHANNEL;

    // udmabuf0
    fd9 = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled.
    if (fd9 == -1){
        fprintf(stderr, "/dev/udmabuf0 open error\n");
        exit(-1);
    }
    image_buf = (volatile uint8_t *)mmap(NULL, 2*image_all_bytes, PROT_READ|PROT_WRITE, MAP_SHARED, fd9, 0);
    if (image_buf == -1){
        fprintf(stderr, "frame_buffer_bmdc mmap error\n");
        exit(-1);
    }

    // phys_addr of udmabuf0
    fd_paddr = open("/sys/class/u-dma-buf/udmabuf0/phys_addr", O_RDONLY);
    if (fd_paddr == -1){
        fprintf(stderr, "/sys/class/u-dma-buf/udmabuf0/phys_addr open errorn");
        exit(-1);
    }
    read(fd_paddr, (void *)attr, 1024);
    sscanf((const char *)attr, "%lx", &phys_addr);
    close(fd_paddr);
    printf("phys_addr = %x\n", (unsigned int)phys_addr);

    // ピクセルを入れるメモリを定義する
    rd_bmp = image_buf;
    wr_bmp = & image_buf[image_all_bytes];

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = fgetc(fbmpr);
            green = fgetc(fbmpr);
            red = fgetc(fbmpr);
            uint32_t index = (((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x)*IMAGE_CHANNEL;
            rd_bmp[index] = blue;
            rd_bmp[index+1] = green;
            rd_bmp[index+2] = red;
        }
    }
    fclose(fbmpr);

    // uio のオープン
    // axi_dma (UIO 4)
    fd4 = open("/dev/uio4", O_RDWR); // axi_dma interface AXI4 Lite Slave
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio4 (axi_dma) open error\n");
        exit(-1);
    }
    axi_dma = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (!axi_dma){
        fprintf(stderr, "axi_dma mmap error\n");
        exit(-1);
    }

    // color_converter_RGB24 (UIO 5)
    fd5 = open("/dev/uio5", O_RDWR); // color_converter_RGB24 interface AXI4 Lite Slave
    if (fd5 < 1){
        fprintf(stderr, "/dev/uio5 (color_converter_RGB24) open error\n");
        exit(-1);
    }
    color_converter_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd5, 0);
    if (!color_converter_RGB24){
        fprintf(stderr, "color_converter_RGB24 mmap error\n");
        exit(-1);
    }

    // gaussian_axis_RGB24 (UIO 6)
    fd6 = open("/dev/uio6", O_RDWR); // gaussian_axis_RGB24 interface AXI4 Lite Slave
    if (fd6 < 1){
        fprintf(stderr, "/dev/uio6 (gaussian_axis_RGB24) open error\n");
        exit(-1);
    }
    gaussian_axis_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd6, 0);
    if (!gaussian_axis_RGB24){
        fprintf(stderr, "gaussian_axis_RGB24 mmap error\n");
        exit(-1);
    }

    // median_axis_RGB24 (UIO 7)
    fd7 = open("/dev/uio7", O_RDWR); // median_axis_RGB24 interface AXI4 Lite Slave
    if (fd7 < 1){
        fprintf(stderr, "/dev/uio7 (median_axis_RGB24) open error\n");
        exit(-1);
    }
    median_axis_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd7, 0);
    if (!median_axis_RGB24){
        fprintf(stderr, "median_axis_RGB24 mmap error\n");
        exit(-1);
    }

    // sobel_axis_RGB24 (UIO 8)
    fd8 = open("/dev/uio8", O_RDWR); // sobel_axis_RGB24 interface AXI4 Lite Slave
    if (fd8 < 1){
        fprintf(stderr, "/dev/uio8 (sobel_axis_RGB24) open error\n");
        exit(-1);
    }
    sobel_axis_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd8, 0);
    if (!sobel_axis_RGB24){
        fprintf(stderr, "sobel_axis_RGB24 mmap error\n");
        exit(-1);
    }

    // gaussian_axis_RGB24
    gaussian_axis_RGB24[GUSSIAN_ROW_SIZE] = bmpihr.biHeight;    // row_size
    gaussian_axis_RGB24[GUSSIAN_COL_SIZE] = bmpihr.biWidth;    // col_size
    gaussian_axis_RGB24[GUSSIAN_FUNCTON_R] = 2;     // function_r, ORG_IMGwAxiDma
    //gaussian_axis_RGB24[GUSSIAN_FUNCTON_R] = 3;   // function_r, GAUSSIANwAxiDma

    // median_axis_RGB24
    median_axis_RGB24[MEDIAN_ROW_SIZE] = bmpihr.biHeight;    // row_size
    median_axis_RGB24[MEDIAN_COL_SIZE] = bmpihr.biWidth;     // col_size
    //median_axis_RGB24[MEDIAN_FUNCTION_R] = 2; // function_r, ORG_IMGwAxiDma
    median_axis_RGB24[MEDIAN_FUNCTION_R] = 3;   // function_r, MEDIANwAxiDma

    // color_converter_RGB24
    color_converter_RGB24[COLOR_CONVERTER_ROW_SIZE] = bmpihr.biHeight;  // row_size
    color_converter_RGB24[COLOR_CONVERTER_COL_SIZE] = bmpihr.biWidth;   // col_size
    color_converter_RGB24[COLOR_CONVERTER_FUNCTION_R] = 2;      // function_r, ORG_IMGwAxiDma
    //color_converter_RGB24[COLOR_CONVERTER_FUNCTION_R] = 3;    // function_r, COLOR_CONVwAxiDma
    color_converter_RGB24[COLOR_CONVERTER_RED_MAG] = 0x2000;    // 32.0, ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>
    color_converter_RGB24[COLOR_CONVERTER_GREEN_MAG] = 0x0100;  // 1.0, ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>
    color_converter_RGB24[COLOR_CONVERTER_BLUE_MAG] = 0x0100;   // 1.0, ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>

    // sobel_axis_RGB24
    sobel_axis_RGB24[SOBEL_ROW_SIZE] = bmpihr.biHeight; // row_size
    sobel_axis_RGB24[SOBEL_COL_SIZE] = bmpihr.biWidth;  // col_size
    //sobel_axis_RGB24[SOBEL_FUNCTION_R] = 2;   // function_r, ORG_IMGwAxiDma
    sobel_axis_RGB24[SOBEL_FUNCTION_R] = 3;     // function_r, MEDIANwAxiDma

    // DMA Start
    // MM2S Channel
    axi_dma[MM2S_CONTROL_REG] = 1;              // MM2S_DMACR, Run/Stop bit(bit 0) = 1
    axi_dma[MM2S_START_ADDR] = phys_addr;       // MM2S_SA
    axi_dma[MM2S_LENGTH_REG] = image_all_bytes; // MM2S_LENGTH(bytes), Start
    // S2MM Channel
    axi_dma[S2MM_CONTROL_REG] = 1;              // S2MM_DMACR, Run/Stop bit(bit 0) = 1
    axi_dma[S2MM_DESTINATION_ADDR] = phys_addr + image_all_bytes; // S2MM_SA
    axi_dma[S2MM_LENGTH_REG] = image_all_bytes; // S2MM_LENGTH(bytes), Start
    // Image IPs start
    gaussian_axis_RGB24[GUSSIAN_CONTROL] = 1;           // start
    median_axis_RGB24[MEDIAN_CONTROL] = 1;              // start
    color_converter_RGB24[COLOR_CONVERTER_CONTROL] = 1; // start
    sobel_axis_RGB24[SOBEL_CONTROL] = 1;                // start

    // Waiting for DMA to finish
    while(!(axi_dma[S2MM_STATUS_REG] & S2MM_IDLE_MASK)) ;   // Waiting Idle bit (S2MM_DMASR, bit 1)

    // Write filtered image file
    if ((fbmpw=fopen(OUTPUT_IMG_FILE, "wb")) == NULL){
        fprintf(stderr, "Can't open %s by binary write mode\n", OUTPUT_IMG_FILE);
        exit(1);
    }
    // BMPファイルヘッダの書き込み
    fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpw);
    fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpw);
    fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpw);
    fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);

    // RGB データの書き込み、逆順にする
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            uint32_t index = (((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x)*IMAGE_CHANNEL;
            blue = wr_bmp[index];
            green = wr_bmp[index+1];
            red = wr_bmp[index+2];

            fputc(blue, fbmpw);
            fputc(green, fbmpw);
            fputc(red, fbmpw);
        }
    }
    fclose(fbmpw);

    munmap((void *)image_buf, 2*image_all_bytes);
    munmap((void *)axi_dma, 0x10000);
    munmap((void *)gaussian_axis_RGB24, 0x10000);
    munmap((void *)median_axis_RGB24, 0x10000);
    munmap((void *)color_converter_RGB24, 0x10000);
    munmap((void *)sobel_axis_RGB24, 0x10000);

    close(fd4);
    close(fd5);
    close(fd6);
    close(fd7);
    close(fd8);
    close(fd9);

    return(0);
}

  1. 2023年10月09日 08:34 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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