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

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

FPGAの部屋

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

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

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

前回は、vadd.bit.bin を KV260 の Petalinux にアップロードし、KV260 上でロードして、ILA ダッシュボードを開いてデバッグする。とりあえず、median_axis_RGB_0 の設定を確認した。今回は、AXI DMA の設定が間違っていることに気付いて、アプリケーション・ソフトウェアを修正したら、median_filter.jpg がノイズを除去した画像ファイルになったが、色が違っていた。

medianf_pf.cpp の AXI DMA を MM2S_DMACR.RS = 1 に修正した。

// medianf_pf.cpp
// 2022/05/30 by marsee
// I referred to http://independence-sys.net/main/?p=2209
// 2022/06/06 : Added udmabuf0.

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs/imgcodecs.hpp"

#define BLOCK_SIZE    4096
#define MIDEAIN_REG_ADDR        0x80020000
#define AXI_DMA_REG_ADDR        0x80010000
#define IMAGE_WIDTH         800
#define IMAGE_HEIGHT            600
#define MAT_IMGAGE_BUF      (IMAGE_WIDTH*IMAGE_HEIGHT*3)

#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  0xfffffffd
#define S2MM_IDLE_MASK  0xfffffffd 

#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;
    uint32_t phy_addr;
    uint32_t phy_addr_base;
    int addr, wd;
    uint32_t write_data;
    cv::Mat in_img, median_img;
    int fd_udmabuf;
    u_int32_t fd_paddr;
    unsigned char  attr[1024];
    unsigned long  phys_addr;
    
    if (argc != 3){
        fprintf(stderr, "Usage : ./median_filer <input image file name> <output image file name>\n");
        exit(-1);
    }
    
    in_img = cv::imread(argv[1], 1);
    median_img.create(cv::Size(in_img.cols, in_img.rows), CV_8UC3);
    
    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);

    uint32_t total_bytes = in_img.total()*in_img.channels();
    uint32_t in_img_total_bytes = (in_img.total()*in_img.channels()+4096) & 0xfffff000; // 4k byte boundary
    printf("in_img_total_bytes = %d\n", in_img_total_bytes);

    pict_buf = (volatile uint8_t *)mmap(NULL, in_img_total_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);
    }
    
    // Copy Mat data from in_img to org_mat
    uint8_t *in_img_data = in_img.data;
    for(int i=0; i<total_bytes; i++){
        pict_buf[i] = in_img_data[i];
    }
    
    // Resetting DMA
    axi_dma_reg[MM2S_CONTROL_REG] = 4; // MM2S DMA Controll Reg. Reset
    axi_dma_reg[S2MM_CONTROL_REG] = 4; // S2MM DMA Control Reg. Reset
    
    // 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+in_img_total_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] = total_bytes;
    axi_dma_reg[MM2S_LENGTH_REG] = total_bytes;
    
    // median filter start
    median_reg[MEDIAN_COL_SIZE] = in_img.cols;
    median_reg[MEDIAN_ROW_SIZE] = in_img.rows;
    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 == 0){
        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 == 0){
        s2mm_status_reg = axi_dma_reg[S2MM_STATUS_REG] & S2MM_IDLE_MASK;
    }
    
    // Copy median image data from median_mat to megian_img
    uint8_t *median_img_data = median_img.data;
    for(int i=0; i<total_bytes; i++){
        median_img_data[i] = pict_buf[in_img_total_bytes+i];
    }

    // Write to median_filter.jgp
    cv::imwrite(argv[2], median_img);
    
    return(0);
}


KV260 で ~/opencv/examples/median_pf/build/ ディレクトリに行って、make を実行する。
cd ~/opencv/exampels/median_pf/build/
make


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

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


KV260 で ~/opencv/examples/median_pf/build/ ディレクトリに行って、medianf_pf を実行した。
cd ~/opencv/exampels/median_pf/build/
sudo ./medianf_pf test2.jpg median_filter.jpg

kv260_median_platform_189_220613.png

median_filter.jpg が生成された。
ホスト・パソコンに SFTP して median_filter.jpg を見るとノイズは取れているが、色がおかしかった。RGB じゃなく BGR の様だ。
kv260_median_platform_190_220613.jpg
  1. 2022年06月13日 04:45 |
  2. KRIA KV260 Vision AI Starter Kit
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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