前回は、CDC でUnsafe を 0 にすることを目標にaxis2video_out.v の Verilog HDL コードを修正した。今回は、アプリケーション・ソフトを作成して、回路を動作させてみよう。
最初に、ビットストリームの生成を行ったので、ホストパソコンで、fpga_dp.bin を作成した。
cd ~/Docker/vivado182ub16/masaaki/ultra96_design/ultra96_design_dp/ultra96_design.runs/impl_1/
bootgen -image fpga.bif -arch zynqmp -w -o fpga_dp.bin
fpga_dp.bin を生成した。
”Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する8(ブロックデザインの変更)”にも書いたが、v4l2.dts を書き換えた。
/dts-v1/;/plugin/;
/ {
fragment@0 {
target-path = "/amba_pl@0";
#address-celss = <2>;
#size-cells = <2>;
__overlay__ {
v4l2 {
compatible = "fixstars,zynq-v4l2-1.0";
#interrupt-cells = <0x3>;
device-name="v4l2";
interrupt-parent = <&gic>;
interrupts = <0x0 0x59 0x4>;
};
axi_vdma_uio {
compatible = "generic-uio";
reg = <0x0 0xA0010000 0x0 0x1000>;
};
display_dmar_axis_vga_uio {
compatible = "generic-uio";
reg = <0x0 0xA0030000 0x0 0x10000>;
};
disp_gpio_uio {
compatible = "generic-uio";
reg = <0x0 0xA0011000 0x0 0x1000>;
};
gpio_uio {
compatible = "generic-uio";
reg = <0x0 0xA0012000 0x0 0x1000>;
};
};
};
};
fpga-load.dts も fpga_dp.bin を使うように書き換えた。
/dts-v1/;
/ {
fragment@0 {
target-path = "/fpga-full";
__overlay__ {
firmware-name = "fpga_dp.bin";
};
};
};
余計な部分はあるが、”カメラ画像をDisplayPortに出力する9(アプリを作成、完成)”を参照して、 pcam5c_disp_dp.cpp を作成した。ソースコードを示す。
// pcam5c_disp_dp.cpp
// 2019/07/24 by marsee
//
// This software converts the left and right of the camera image to BMP file.
// -b : bmp file name
// -n : Start File Number
// -h : help
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#define PIXEL_NUM_OF_BYTES 4
#define NUMBER_OF_WRITE_FRAMES 3
#define SVGA_HORIZONTAL_PIXELS 800
#define SVGA_VERTICAL_LINES 600
#define SVGA_ALL_DISP_ADDRESS (SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
#define SVGA_3_PICTURES (SVGA_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)
#define XGA_HORIZONTAL_PIXELS 1024
#define XGA_VERTICAL_LINES 768
#define XGA_ALL_DISP_ADDRESS (XGA_HORIZONTAL_PIXELS * XGA_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
#define XGA_3_PICTURES (XGA_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)
#define HD_HORIZONTAL_PIXELS 1920
#define HD_VERTICAL_LINES 1080
#define HD_ALL_DISP_ADDRESS (HD_HORIZONTAL_PIXELS * HD_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
#define HD_3_PICTURES (HD_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)
int main(int argc, char *argv[]){
int opt;
int c, help_flag=0;
char bmp_fn[256] = "bmp_file";
char attr[1024];
unsigned long phys_addr;
int file_no = -1;
int fd1, fd2, fd3, fd4;
volatile unsigned int *axi_vdma_uio, *display_dmar_axis_vga_uio, *disp_gpio_uio, *gpio_uio;
int active_frame;
int resolution;
int all_disp_addr;
uint32_t row, col;
int disp_active_frame=0;
resolution = 1; // XGA
while ((opt=getopt(argc, argv, "b:n:h:r:")) != -1){
switch (opt){
case 'b':
strcpy(bmp_fn, optarg);
break;
case 'n':
file_no = atoi(optarg);
printf("file_no = %d\n", file_no+1);
break;
case 'r':
resolution = atoi(optarg);
break;
case 'h':
help_flag = 1;
break;
}
}
if(resolution == 0){
printf("SVGA\n");
} else if(resolution == 1){
printf("XGA\n");
} else {
printf("HD\n");
}
// all_disp_addr
switch(resolution){
case 0 :
all_disp_addr = SVGA_ALL_DISP_ADDRESS;
row = SVGA_VERTICAL_LINES; col = SVGA_HORIZONTAL_PIXELS;
break;
case 1 :
all_disp_addr = XGA_ALL_DISP_ADDRESS;
row = XGA_VERTICAL_LINES; col = XGA_HORIZONTAL_PIXELS;
break;
default : // 2
all_disp_addr = HD_ALL_DISP_ADDRESS;
row = HD_VERTICAL_LINES; col = HD_HORIZONTAL_PIXELS;
break;
}
// axi_vdma_uio IP
fd1 = open("/dev/uio1", O_RDWR|O_SYNC); // Read/Write, The chache is disable
if (fd1 < 1){
fprintf(stderr, "/dev/uio1 (axi_vdma_uio) open error\n");
exit(-1);
}
axi_vdma_uio = (volatile unsigned *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
if (!axi_vdma_uio){
fprintf(stderr, "axi_vdma_uio mmap error\n");
exit(-1);
}
// display_dmar_axis_vga_uio IP
fd2 = open("/dev/uio2", O_RDWR|O_SYNC); // Read/Write, The chache is disable
if (fd2 < 1){
fprintf(stderr, "/dev/uio2 (display_dmar_axis_vga_uio) open error\n");
exit(-1);
}
display_dmar_axis_vga_uio = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
if (!display_dmar_axis_vga_uio){
fprintf(stderr, "display_dmar_axis_vga_uio mmap error\n");
exit(-1);
}
// disp_gpio_uio IP
fd3 = open("/dev/uio3", O_RDWR|O_SYNC); // Read/Write, The chache is disable
if (fd3 < 1){
fprintf(stderr, "/dev/uio3 (disp_gpio_uio) open error\n");
exit(-1);
}
disp_gpio_uio = (volatile unsigned *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
if (!disp_gpio_uio){
fprintf(stderr, "disp_gpio_uio mmap error\n");
exit(-1);
}
// gpio_uio IP
fd4 = open("/dev/uio4", O_RDWR|O_SYNC); // Read/Write, The chache is disable
if (fd4 < 1){
fprintf(stderr, "/dev/uio4 (gpio_uio) open error\n");
exit(-1);
}
gpio_uio = (volatile unsigned *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
if (!gpio_uio){
fprintf(stderr, "gpio_uio mmap error\n");
exit(-1);
}
uint32_t framebuf0, framebuf1, framebuf2;
framebuf0 = axi_vdma_uio[43]; // 0xac
framebuf1 = axi_vdma_uio[44]; // 0xb0
framebuf2 = axi_vdma_uio[45]; // 0xb4
printf("framebuf0 = %x; framebuf1 = %x; framebuf2 = %x\n", framebuf0, framebuf1, framebuf2);
display_dmar_axis_vga_uio[4] = framebuf0; // 0x10, fb0_V
display_dmar_axis_vga_uio[6] = framebuf1; // 0x18, fb1_V
display_dmar_axis_vga_uio[8] = framebuf2; // 0x20, fb2_V
display_dmar_axis_vga_uio[10] = row; // 0x28, row_V
display_dmar_axis_vga_uio[12] = col; // 0x30, col_V
disp_gpio_uio[0] = 1; // disp_dmar_axis_vga start(init_done = 1)
c = getc(stdin);
while(c != 'q'){
switch ((char)c) {
case 'f':
printf("active frame = %d\n", gpio_uio[0]);
break;
}
c = getc(stdin);
}
return(0);
}
Ultra96 上のDebian で g++_opencv コマンドで pcam5c_disp_dp.cpp をコンパイルした。
g++_opencv pcam5c_disp_dp.cpp
~/examples/Pcam5C_DP/ ディレクトリで以下のコマンドを実行した。
sudo ./init_camera.sh
sudo ./pcam5c_disp_dp
f リターン・キーを押すと、VDMA が使用しているフレームバッファ番号が表示される。それによると 1, 2, 3 の 3 個だった。 0 〜 2 だと思っていたので、失敗した。disp_dmar_axis_vga IP を修正する必要がある。
それ以前に、フレームバッファのアドレスから見たフレームバッファ領域は、0xe1000 のようだ。
0xe1000 は、921600 / 640 / 480 = 3 バイトなので、現在の私のdisp_dmar_axis_vga IP ではうまく行かないのがわかった。私の考えるフォーマットは4バイト、32ビット単位となっているのだ。
また、”カメラ画像をDisplayPortに出力する9(アプリを作成、完成)”の ./disp_pattern.sh をコピーして実行したが、DisplayPort の画面は真っ暗だった。
コメント