FC2カウンター FPGAの部屋 kv260_median_platform のメディアン・フィルタを KV260 の Petalinux から動作させる24
fc2ブログ

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

FPGAの部屋

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

kv260_median_platform のメディアン・フィルタを KV260 の Petalinux から動作させる24

kv260_median_platform のメディアン・フィルタを KV260 の Petalinux から動作させる23”の続き。

前回は、”axi dma をシンプル DMA モードで動作させる方法”を踏まえて、バグを含んでいると思われる”kv260_median_platform のメディアン・フィルタを KV260 の Petalinux から動作させる7”の median_pf.cpp を修正して、KV260 の Petalinux 2022.1 環境で make して、実行してみたが、動作しなかった。その後、試行錯誤の結果、axi dma をリセットしなければ、median_pf が動作することを確認した。今回は、Vitis で前回のソフトウエアを動かそうとしたが、OpenCV ライブラリが使用できなかったので、BMP ファイルを扱うようにソフトウエアを変更した。Vitis で median_pf_bmp アプリケーション・プロジェクトを作成し、アプリケーション・ソフトウエアを書いて、ビルドを行った。ビルドが成功したので、できあがった median_pf_bmp.elf ファイルを Petalinux 2022.1 が起動する KV260 にアップロードし、動作させたところ成功した。

median_pf アクセラレーション・プラットフォームを使用して、median_pf_bmp アプリケーション・プロジェクトを作成する。
Vitis 2022.1 を起動して、ワークスペースを KRIA_KV260/2022.1/kv260_median_platform/kv260_median_pkg に設定した。

File メニューから New -> Application Project... を選択した。

Platform 画面
kv260_median プラットフォームを選択する。
KV260_custom_platform_197_221029.png

Application Project Detail 画面
Application project name に median_pf_bmp と入力する。
KV260_custom_platform_198_221029.png

Domain 画面
sysroot path: に kv260_median_platform/kv260_median_pkg/sysroots/cortexa72-cortexa53-xilinx-linux を指定した。
Root FS: に kv260_median_platform/kv260_median_plnx/images/linux/rootfs.ext4 を指定した。
Kernel Image: に kv260_median_platform/kv260_median_plnx/images/linux/Image を指定した。
KV260_custom_platform_199_221029.png

Templates 画面
Empty Application (C++) を選択した。
Finish ボタンをクリックした。
KV260_custom_platform_200_221029.png

median_pf_bmp アプリケーション・プロジェクトが生成された。
KV260_custom_platform_201_221029.png

Vitis 2022.1 の median_pf_bmp_system -> median_pf_bmp -> src を右クリックし、右クリックメニューから New -> File を選択する。
KV260_custom_platform_202_221029.png

Create New File ダイアログで File name: に median_pf_bmp.cpp を入力する。
KV260_custom_platform_203_221029.png

median_pf_bmp.cpp の中身を書いた。
KV260_custom_platform_204_221029.png

更に bmp_header.h を追加する。
KV260_custom_platform_205_221029.png

KV260_custom_platform_206_221029.png

median_pf_bmp_system のビルドを行って成功した。簡単に書いているけど、プログラムの意図を忘れていたので、時間が掛かってしまった。。。
KV260_custom_platform_207_221030.png

KRIA_KV260/2022.1/kv260_median_platform/kv260_median_pkg/median_pf_bmp/Debug ディレクトリに median_pf_bmp.elf が生成された。
KV260_custom_platform_211_221030.png

KV260 の Petalinux 2021.1 を起動した。
~/kv260_median ディレクトリに下に median_pf_bmp ディレクトリを作成した。
cd ~/kv260_median
mkdir median_pf_bmp


median_pf_bmp.elf とノイズ入りの test2.bmp ファイを SFTP で ~/kv260_median/median_pf_bmp ディレクトリに送った。

KV260 の Petalinux 上で、ホーム・ディレクトリに行って、 u-dma-buf をロードする。
cd
sudo insmod u-dma-buf.ko udmabuf0=3000000


すでにロードされているハードウェアをアンロードして、vadd をロードする。
sudo xmutil unloadapp
sudo xmutil loadapp vadd


KV260 で ~/kv260_median/median_pf_bmp ディレクトリに行って、medianf_pf_bmp を実行した。
cd ~/kv260_median/median_pf_bmp/
sudo ./median_pf_bmp.elf test2.bmp median_filter.bmp


median_filter.bmp ファイルが生成された。
ホストパソコン上に SFTP で median_filter.bmp ファイルを転送した。
KV260_custom_platform_209_221030.png

median_filter.bmp ファイルを示す。問題無さそうだ。ノイズも除去できている。メディアン・フィルタで処理されたことが分かる。
KV260_custom_platform_210_221030.jpg

median_pf_bmp.cpp を貼っておく。

// median_pf_bmp.cpp
// 2022/10/28 by marsee
// I referred to http://independence-sys.net/main/?p=2209

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

#include "bmp_header.h"

#define BLOCK_SIZE    4096
#define MIDEAIN_REG_ADDR        0x80020000
#define AXI_DMA_REG_ADDR        0x80010000
#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 MEDIAN_CONTROL      0x00
#define MEDIAN_FUNCTION_R   (0x18 >> 2)
#define MEDIAN_ROW_SIZE     (0x20 >> 2)
#define MEDIAN_COL_SIZE     (0x28 >> 2)

volatile uint32_t *reg;

int main(int argc, char **argv){
    int fd;
    volatile uint32_t *median_reg, *axi_dma_reg;
    volatile uint8_t *pict_buf;
    int fd_udmabuf;
    u_int32_t fd_paddr;
    unsigned char  attr[1024];
    unsigned long  phys_addr;
    long x, y;
    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw;
    int32_t blue, green, red;

    if (argc != 3){
        fprintf(stderr, "Usage : ./median_filer <input image file name> <output image file name>\n");
        exit(-1);
    }

    if ((fbmpr = fopen("test2.bmp", "rb")) == NULL){ // test.bmp をオープン
        fprintf(stderr, "Can't open test.bmp by binary read mode\n");
        exit(1);
    }
    // Read bmp header
    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);

    int size_in_words = bmpihr.biWidth * bmpihr.biHeight;
    int size_in_bytes = size_in_words * IMAGE_CHANNEL;

    fd = open("/dev/mem", O_RDWR | O_SYNC);
    if (fd == -1){
        fprintf(stderr, "/dev/mem open error\n");
        exit(-1);
    }

    // median_filter registers
    median_reg = (uint32_t *)mmap(NULL, BLOCK_SIZE,
                PROT_READ | PROT_WRITE, MAP_SHARED,
                fd, MIDEAIN_REG_ADDR );
    if ((int64_t)median_reg == -1){
        fprintf(stderr,"/dev/mem map error for median_filter registers\n");
        exit(-1);
    }

    // axi_dma registers
    axi_dma_reg = (uint32_t *)mmap(NULL, BLOCK_SIZE,
                PROT_READ | PROT_WRITE, MAP_SHARED,
                fd, AXI_DMA_REG_ADDR );
    if ((int64_t)axi_dma_reg == -1){
        fprintf(stderr,"/dev/mem map error for axi_dma registers\n");
        exit(-1);
    }

    // udmabuf0
    fd_udmabuf = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled.
    if (fd_udmabuf == -1){
        fprintf(stderr, "/dev/udmabuf0 open errorn");
        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);

    pict_buf = (volatile uint8_t *)mmap(NULL, size_in_bytes*2, PROT_READ|PROT_WRITE, MAP_SHARED, fd_udmabuf, 0);
    if (pict_buf == MAP_FAILED){
        fprintf(stderr, "org_mat mmap error\n");
        exit(-1);
    }
    volatile uint8_t *median = &pict_buf[size_in_bytes];

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (y=0; y<bmpihr.biHeight; y++){
        for (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;
            pict_buf[index] = blue;
            pict_buf[index+1] = green;
            pict_buf[index+2] = red;
        }
    }
    fclose(fbmpr);

    // Halting Run DMA
    axi_dma_reg[MM2S_CONTROL_REG] = 1; // MM2S DMA Controll Reg. Run
    axi_dma_reg[S2MM_CONTROL_REG] = 1; // S2MM DMA Control Reg. Run

    uint32_t median_mat_addr = (uint32_t)phys_addr+size_in_bytes;
    uint32_t org_mat_addr = (uint32_t)phys_addr;
    // axi dma settings
    axi_dma_reg[S2MM_DESTINATION_ADDR] = median_mat_addr;
    axi_dma_reg[MM2S_START_ADDR] = org_mat_addr;
    axi_dma_reg[S2MM_LENGTH_REG] = size_in_bytes;
    axi_dma_reg[MM2S_LENGTH_REG] = size_in_bytes;

    // median filter start
    median_reg[MEDIAN_COL_SIZE] = bmpihr.biWidth;
    median_reg[MEDIAN_ROW_SIZE] = bmpihr.biHeight;
    median_reg[MEDIAN_FUNCTION_R] = 3;  // median filter for AXI DMA
    median_reg[MEDIAN_CONTROL] = 1;         // ap_start

    // DMA completion detection
    uint32_t mm2s_status_reg = axi_dma_reg[MM2S_STATUS_REG] & MM2S_IDLE_MASK;
    while(mm2s_status_reg != MM2S_IDLE_MASK){
        mm2s_status_reg = axi_dma_reg[MM2S_STATUS_REG] & MM2S_IDLE_MASK;
    }

    uint32_t s2mm_status_reg = axi_dma_reg[S2MM_STATUS_REG] & S2MM_IDLE_MASK;
    while(s2mm_status_reg != S2MM_IDLE_MASK){
        s2mm_status_reg = axi_dma_reg[S2MM_STATUS_REG] & S2MM_IDLE_MASK;
    }

    // Write to median_filter.bmp
    // ハードウェアのソーベルフィルタの結果を median_filter.bmp へ出力する
    if ((fbmpw=fopen("median_filter.bmp", "wb")) == NULL){
        fprintf(stderr, "Can't open median_filter.bmp by binary write mode\n");
        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 (y=0; y<bmpihr.biHeight; y++){
        for (x=0; x<bmpihr.biWidth; x++){
            uint32_t index = (((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x)*IMAGE_CHANNEL;
            blue = median[index];
            green = median[index+1];
            red = median[index+2];

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

    return(0);
}

  1. 2022年10月30日 07:58 |
  2. Vitis
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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