caminf_axi_iic@0x41600000 {
compatible = "generic-uio";
reg = < 0x41600000 0x10000>;
};
caminf_axi_vdma_0@43010000 {
compatible = "generic-uio";
reg = < 0x43010000 0x10000 >;
};
caminf_axis_switch_0@0x43c10000 {
compatible = "generic-uio";
reg = < 0x43c10000 0x10000 >;
};
caminf_axis_switch_1@0x43c20000 {
compatible = "generic-uio";
reg = < 0x43c20000 0x10000 >;
};
caminf_lap_filter_axis_0@0x43c30000 {
compatible = "generic-uio";
reg = < 0x43c30000 0x10000>;
};
caminf_mt9d111_inf_axis_0@0x43C40000 {
compatible = "generic-uio";
reg = < 0x43C40000 0x10000>;
};
bitmap_disp_cntrler_axi_master_0@0x43c00000 {
compatible = "generic-uio";
reg = < 0x43c00000 0x10000>;
};
dviin_axi_vdma_0@0x43000000 {
compatible = "generic-uio";
reg = < 0x43000000 0x10000>;
};
/* * disp_test.c * * Created on: 2016/01/20 * Author: marsee */
#include <stdio.h>
#include <stdlib.h>
#include "xaxivdma.h"
#include "xil_io.h"
#include "xparameters.h"
#include "sleep.h"
#define NUMBER_OF_WRITE_FRAMES 3 // Note: If not at least 3 or more, the image is not displayed in succession.
#define PIXEL_NUM_OF_BYTES 4
#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 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 DVI_INPUT_FRAME_BUFFER_ADDRESS 0x10000000
#define CAMERA_FRAME_BUFFER_ADDRESS 0x10900000
static XAxiVdma_DmaSetup Vdma_dvi_WriteCfg;
//static XAxiVdma_DmaSetup Vdma_cam_WriteCfg;
void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) {
mt9d111_i2c_axi_lites[64] = 0x2; // reset tx fifo ,address is 0x100, i2c_control_reg
mt9d111_i2c_axi_lites[64] = 0x1; // enable i2c
}
void cam_i2x_write_sync(void) {
// unsigned c;
// c = *cam_i2c_rx_fifo;
// while ((c & 0x84) != 0x80)
// c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
usleep(1000);
}
void cam_i2c_write(volatile unsigned *mt9d111_i2c_axi_lites, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
mt9d111_i2c_axi_lites[66] = 0x100 | (device_addr & 0xfe); // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
mt9d111_i2c_axi_lites[66] = write_addr;
mt9d111_i2c_axi_lites[66] = (write_data >> 8)|0xff; // first data
mt9d111_i2c_axi_lites[66] = 0x200 | (write_data & 0xff); // second data
cam_i2x_write_sync();
}
int main(){
// AXI VDMA Initialization sequence
XAxiVdma_Config *XAxiVdma_dvi_Config;
XAxiVdma XAxiVdma_dvi;
int XAxiVdma_dvi_Status;
//XAxiVdma_Config *XAxiVdma_cam_Config;
//XAxiVdma XAxiVdma_cam;
//int XAxiVdma_cam_Status;
// AXI VDMA for dvi_input Initialization sequence
XAxiVdma_dvi_Config = XAxiVdma_LookupConfig(XPAR_DVI_INPUT_AXI_VDMA_0_DEVICE_ID); // Look up the hardware configuration for a device instance
if (XAxiVdma_dvi_Config == NULL){
fprintf(stderr, "No AXI VDMA for dvi_input found\n");
return(-1);
}
XAxiVdma_dvi_Status = XAxiVdma_CfgInitialize(&XAxiVdma_dvi, XAxiVdma_dvi_Config, XAxiVdma_dvi_Config->BaseAddress); // Initialize the driver with hardware configuration
if (XAxiVdma_dvi_Status != XST_SUCCESS){
fprintf(stderr, "XAxiVdma_CfgInitialize() for dvi_input failed\n");
return(-1);
}
XAxiVdma_Reset(&XAxiVdma_dvi, XAXIVDMA_WRITE);
while(XAxiVdma_ResetNotDone(&XAxiVdma_dvi, XAXIVDMA_WRITE)) ;
XAxiVdma_dvi_Status = XAxiVdma_SetFrmStore(&XAxiVdma_dvi, NUMBER_OF_WRITE_FRAMES, XAXIVDMA_WRITE); // Set the number of frame store buffers to use.
Vdma_dvi_WriteCfg.VertSizeInput = XGA_VERTICAL_LINES;
Vdma_dvi_WriteCfg.HoriSizeInput = XGA_HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES;
Vdma_dvi_WriteCfg.Stride = XGA_HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES; // Indicates the number of address bytes between the first pixels of each video line.
Vdma_dvi_WriteCfg.FrameDelay = 0; // Indicates the minimum number of frame buffers the Genlock slave is to be behind the locked master. This field is only used if the channel is enabled for Genlock Slave operations. This field has no meaning in other Genlock modes.
Vdma_dvi_WriteCfg.EnableCircularBuf = 1; // Indicates frame buffer Circular mode or frame buffer Park mode. 1 = Circular Mode Engine continuously circles through frame buffers.
Vdma_dvi_WriteCfg.EnableSync = 0; // Enables Genlock or Dynamic Genlock Synchronization. 0 = Genlock or Dynamic Genlock Synchronization disabled.
Vdma_dvi_WriteCfg.PointNum = 0; // No Gen-Lock
Vdma_dvi_WriteCfg.EnableFrameCounter = 0; // Endless transfers
Vdma_dvi_WriteCfg.FixedFrameStoreAddr = 0; // We are not doing parking
XAxiVdma_dvi_Status = XAxiVdma_DmaConfig(&XAxiVdma_dvi, XAXIVDMA_WRITE, &Vdma_dvi_WriteCfg);
if (XAxiVdma_dvi_Status != XST_SUCCESS){
fprintf(stderr, "XAxiVdma_DmaConfig() failed\n");
return(-1);
}
// Frame buffer(AXI4 VDMA of dvi_input) address set
unsigned int frame_addr = (unsigned int)DVI_INPUT_FRAME_BUFFER_ADDRESS;
int i;
for (i=0; i<NUMBER_OF_WRITE_FRAMES; i++){
Vdma_dvi_WriteCfg.FrameStoreStartAddr[i] = frame_addr;
frame_addr += XGA_HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES * XGA_VERTICAL_LINES;
}
XAxiVdma_dvi_Status = XAxiVdma_DmaSetBufferAddr(&XAxiVdma_dvi, XAXIVDMA_WRITE, Vdma_dvi_WriteCfg.FrameStoreStartAddr);
if (XAxiVdma_dvi_Status != XST_SUCCESS){
fprintf(stderr, "XAxiVdma_DmaSetBufferAddr() failed\n");
return(-1);
}
// VDMA start
XAxiVdma_dvi_Status = XAxiVdma_DmaStart(&XAxiVdma_dvi, XAXIVDMA_WRITE);
if (XAxiVdma_dvi_Status != XST_SUCCESS){
fprintf(stderr, "XAxiVdma_DmaStart() for dvi_input failed\n");
return(-1);
}
// AXI VDMA for Camera module setup
// axis_switch_1, 1to2 ,Select M00_AXIS
// Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x40), 0x0);
Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x80000000); // disable
Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers
// axis_switch_0, 2to1, Select S00_AXIS
// Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR+0x40), 0x0);
Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers
volatile unsigned int *axi_vdma_cam = XPAR_CAMERA_INTERFACE_AXI_VDMA_0_BASEADDR;
// AXI VDMA Initialization sequence
axi_vdma_cam[12] = 0x4; // S2MM_VDMACR (S2MM VDMA Control Register Offset 30h) is 0x4
while ((axi_vdma_cam[12] & 0x4) == 0x4) ; // Reset is progress
axi_vdma_cam[12] = 0x4; // S2MM_VDMACR (S2MM VDMA Control Register Offset 30h) is 0x4
while ((axi_vdma_cam[12] & 0x4) == 0x4) ; // Reset is progress
axi_vdma_cam[18] = 0x3; // S2MM_FRMSTORE (0x48) register
axi_vdma_cam[12] = 0x00010002; // S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1)
axi_vdma_cam[41] = 0xc80; // S2MM Horizontal Size Register(S2MM_HSIZE)0xc80 = 3200dec = 800 x 4
axi_vdma_cam[42] = 0xc80; // S2MM Frame Delay and Stride Register(S2MM_FRMDLY_STRIDE)0xc80 = 3200dec = 800 x 4
axi_vdma_cam[43] = CAMERA_FRAME_BUFFER_ADDRESS; // S2MM Start Address (1 to 16) Start Address 1
axi_vdma_cam[44] = CAMERA_FRAME_BUFFER_ADDRESS+SVGA_ALL_DISP_ADDRESS; // S2MM Start Address (1 to 16) Start Address 2
axi_vdma_cam[45] = CAMERA_FRAME_BUFFER_ADDRESS+2*SVGA_ALL_DISP_ADDRESS; // S2MM Start Address (1 to 16) Start Address 3
axi_vdma_cam[12] = 0x00010003; // S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1, Run/stop = 1)
while((axi_vdma_cam[13] & 0x1) == 0x1) ; // Halt? (S2MM_VDMASR 0x34)
axi_vdma_cam[40] = 0x258; // S2MM Vertical Size (S2MM_VSIZE Offset 0xA0) 0x258 = 600dec
// mt9d111_inf_axis_0, axi_iic_0
volatile unsigned int *mt9d111_axi_lites;
volatile unsigned int *mt9d111_i2c_axi_lites;
mt9d111_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_MT9D111_INF_AXIS_0_BASEADDR;
mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_AXI_IIC_0_BASEADDR;
mt9d111_axi_lites[0] = (volatile unsigned int)CAMERA_FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)
// CMOS Camera initialize, MT9D111
cam_i2c_init(mt9d111_i2c_axi_lites);
cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0xf0, 0x1); // Changed regster map to IFP page 1
cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0x97, 0x20); // RGB Mode, RGB565
mt9d111_axi_lites[1] = 0; // One_shot_mode is disabled
// bitmap_disp_cntrler_axi_master_0 : VGA port Display
volatile unsigned int *bmdc0_axi_lites;
bmdc0_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
//bmdc0_axi_lites[0] = (volatile unsigned int)CAMERA_FRAME_BUFFER_ADDRESS; // Bitmap Display Controller 0 start, Camera Image
bmdc0_axi_lites[0] = (volatile unsigned int)(DVI_INPUT_FRAME_BUFFER_ADDRESS + 0xc); // Bitmap Display Controller 0 start, HDMI Image
return(0);
}
sudo insmod udmabuf.ko udmabuf0=5760000
sudo chmod 666 /dev/udmabuf0
(追記:”Linuxでユーザー空間で動作するプログラムとハードウェアがメモリを共有するためのデバイスドライバ”にロード時にパーミッションを変更する方法が追加されています。/etc/udev/rules.d/99-udmabuf.rules というファイルにパーミションを 666 にする記述を書いておくそうです)
//
// udmabuf_test.c
// 2016/01/23 by marsee
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
int main()
{
int fd, fd1;
volatile unsigned *udmabuf_test;
unsigned char attr[1024];
unsigned long phys_addr;
int i;
fd = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled.
if (fd == -1){
fprintf(stderr, "/dev/udmabuf0 open error\n");
exit(-1);
}
udmabuf_test = (volatile unsigned *)mmap(NULL, 5760000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (!udmabuf_test){
fprintf(stderr, "udmabuf_test mmap error\n");
exit(-1);
}
// phys_addr of udmabuf0
fd1 = open("/sys/devices/virtual/udmabuf/udmabuf0/phys_addr", O_RDONLY);
if (fd1 == -1){
fprintf(stderr, "/sys/devices/virtual/udmabuf/udmabuf0/phys_addr open error\n");
exit(-1);
}
read(fd1, attr, 1024);
sscanf(attr, "%lx", &phys_addr);
close(fd1);
printf("phys_addr = %x\n", (int)phys_addr);
for (i=0; i<100; i++){
udmabuf_test[i] = i;
if (udmabuf_test[i] != i){
printf("Error: i = %d, udmabuf_test[i] = %d\n", i, udmabuf_test[i]);
} else {
printf("i = %d, udamabuf_test[i] = %d\n", i, udmabuf_test[i]);
}
}
munmap((void *)udmabuf_test, 576000);
close(fd);
return(0);
}
//
// cam_disp_vdma.c
// Created on: 2015/12/03
// Author: marsee
// 2016/01/23 : udmabuf version
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#define CMA_START_ADDRESS 0x17800000
#define VIDEO_BUFFER_START_ADDRESS 0x18000000 // Limit 0x18800000, 800*600*4 = 2MBytes * 2
#define NUMBER_OF_WRITE_FRAMES 3 // Note: If not at least 3 or more, the image is not displayed in succession.
#define HORIZONTAL_PIXEL 800
#define ALL_CHAR_OF_1LINE (HORIZONTAL_PIXEL/8)
#define VERTICAL_PIXEL 600
#define ALL_CHAR_OF_ROW (VERTICAL_PIXEL/8)
#define ALL_DISP_ADDRESS (HORIZONTAL_PIXEL*VERTICAL_PIXEL*4)
#define ALL_DISP_CHARACTOR HORIZONTAL_PIXEL*VERTICAL_PIXEL
void cam_i2c_init(volatile unsigned *mt9d111_axi_iic) {
mt9d111_axi_iic[64] = 0x2; // reset tx fifo ,address is 0x100, i2c_control_reg
mt9d111_axi_iic[64] = 0x1; // enable i2c
}
void cam_i2x_write_sync(void) {
// unsigned c;
// c = *cam_i2c_rx_fifo;
// while ((c & 0x84) != 0x80)
// c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
usleep(1000);
}
void cam_i2c_write(volatile unsigned *mt9d111_axi_iic, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
mt9d111_axi_iic[66] = 0x100 | (device_addr & 0xfe); // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
mt9d111_axi_iic[66] = write_addr;
mt9d111_axi_iic[66] = (write_data >> 8)|0xff; // first data
mt9d111_axi_iic[66] = 0x200 | (write_data & 0xff); // second data
cam_i2x_write_sync();
}
int main()
{
int fd0, fd1, fd2, fd3, fd4, fd5, fd6, fd7, fd8, fd9, fd10;
volatile unsigned *bmdc_axi_lites0, *bmdc_axi_lites1;
volatile unsigned *axi_vdma_0;
volatile unsigned *axis_switch_0, *axis_switch_1;
volatile unsigned *mt9d111_inf_axis_0;
volatile unsigned *mt9d111_axi_iic;
volatile unsigned *axi_gpio_0;
volatile unsigned *frame_buffer_bmdc;
unsigned char attr[1024];
unsigned long phys_addr;
// Bitmap Display Controller 0 AXI4 Lite Slave (UIO6)
fd6 = open("/dev/uio6", O_RDWR); // bitmap_display_controller 0 axi4 lite
if (fd6 < 1){
fprintf(stderr, "/dev/uio6 (bitmap_disp_cntrler_axi_master_0) open error\n");
exit(-1);
}
bmdc_axi_lites0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd6, 0);
if (!bmdc_axi_lites0){
fprintf(stderr, "bmdc_axi_lites0 mmap error\n");
exit(-1);
}
bmdc_axi_lites0[0] = VIDEO_BUFFER_START_ADDRESS; // Bitmap Display 1 Controller start
// Bitmap Display Controller 1 AXI4 Lite Slave (UIO7)
fd7 = open("/dev/uio7", O_RDWR); // bitmap_display_controller axi4 lite
if (fd7 < 1){
fprintf(stderr, "/dev/uio7 (bitmap_disp_cntrler_axi_master_0) open error\n");
exit(-1);
}
bmdc_axi_lites1 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd7, 0);
if (!bmdc_axi_lites1){
fprintf(stderr, "bmdc_axi_lites1 mmap error\n");
exit(-1);
}
bmdc_axi_lites1[0] = VIDEO_BUFFER_START_ADDRESS; // Bitmap Display Controller start
// axi_vdma_0 (UIO1)
fd1 = open("/dev/uio1", O_RDWR); // axi_vdma_0 interface AXI4 Lite Slave
if (fd1 < 1){
fprintf(stderr, "/dev/uio1 (axi_vdma_0) open error\n");
exit(-1);
}
axi_vdma_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
if (!axi_vdma_0){
fprintf(stderr, "axi_vdma_0 mmap error\n");
exit(-1);
}
// mt9d111 i2c AXI4 Lite Slave (UIO0)
fd0 = open("/dev/uio0", O_RDWR); // mt9d111 i2c AXI4 Lite Slave
if (fd0 < 1){
fprintf(stderr, "/dev/uio0 (mt9d111_axi_iic) open error\n");
exit(-1);
}
mt9d111_axi_iic = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd0, 0);
if (!mt9d111_axi_iic){
fprintf(stderr, "mt9d111_axi_iic mmap error\n");
exit(-1);
}
// mt9d111 inf axis AXI4 Lite Slave (UIO5)
fd5 = open("/dev/uio5", O_RDWR); // mt9d111 inf axis AXI4 Lite Slave
if (fd5 < 1){
fprintf(stderr, "/dev/uio5 (mt9d111_inf_axis_0) open error\n");
exit(-1);
}
mt9d111_inf_axis_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd5, 0);
if (!mt9d111_inf_axis_0){
fprintf(stderr, "mt9d111_inf_axis_0 mmap error\n");
exit(-1);
}
// axis_switch_0 (UIO2)
fd2 = open("/dev/uio2", O_RDWR); // axis_switch_0 interface AXI4 Lite Slave
if (fd2 < 1){
fprintf(stderr, "/dev/uio2 (axis_switch_0) open error\n");
exit(-1);
}
axis_switch_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
if (!axis_switch_0){
fprintf(stderr, "axis_switch_0 mmap error\n");
exit(-1);
}
// axis_switch_1 (UIO3)
fd3 = open("/dev/uio3", O_RDWR); // axis_switch_1 interface AXI4 Lite Slave
if (fd3 < 1){
fprintf(stderr, "/dev/uio3 (axis_switch_1) open error\n");
exit(-1);
}
axis_switch_1 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
if (!axis_switch_1){
fprintf(stderr, "axis_switch_1 mmap error\n");
exit(-1);
}
// axi_gpio_0 (UIO8)
fd8 = open("/dev/uio8", O_RDWR); // axi_gpio_0 interface AXI4 Lite Slave
if (fd8 < 1){
fprintf(stderr, "/dev/uio8 (axi_gpio_0) open error\n");
exit(-1);
}
axi_gpio_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd8, 0);
if (!axi_gpio_0){
fprintf(stderr, "axi_gpio_8 mmap error\n");
exit(-1);
}
// 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);
}
frame_buffer_bmdc = (volatile unsigned *)mmap(NULL, 5760000, PROT_READ|PROT_WRITE, MAP_SHARED, fd9, 0);
if (!frame_buffer_bmdc){
fprintf(stderr, "frame_buffer_bmdc mmap error\n");
exit(-1);
}
// axis_switch_1, 1to2 ,Select M00_AXIS
// Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
axis_switch_1[16] = 0x0; // 0x40 = 0
axis_switch_1[17] = 0x80000000; // 0x44 = 0x80000000, disable
axis_switch_1[0] = 0x2; // Comit registers
// axis_switch_0, 2to1, Select S00_AXIS
// Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
axis_switch_0[16] = 0x0; // 0x40 = 0;
axis_switch_0[0] = 0x2; // Comit registers
// phys_addr of udmabuf0
fd10 = open("/sys/devices/virtual/udmabuf/udmabuf0/phys_addr", O_RDONLY);
if (fd10 == -1){
fprintf(stderr, "/sys/devices/virtual/udmabuf/udmabuf0/phys_addr open error\n");
exit(-1);
}
read(fd10, attr, 1024);
sscanf(attr, "%lx", &phys_addr);
close(fd10);
printf("phys_addr = %x\n", (int)phys_addr);
// AXI VDMA Initialization sequence
axi_vdma_0[12] = 0x4; // S2MM_VDMACR (S2MM VDMA Control Register Offset 30h) is 0x4
while ((axi_vdma_0[12] & 0x4) == 0x4) ; // Reset is progress
axi_vdma_0[12] = 0x4; // S2MM_VDMACR (S2MM VDMA Control Register Offset 30h) is 0x4
while ((axi_vdma_0[12] & 0x4) == 0x4) ; // Reset is progress
axi_vdma_0[18] = 0x3; // S2MM_FRMSTORE (0x48) register
axi_vdma_0[12] = 0x00010002; // S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1)
axi_vdma_0[41] = 0xc80; // S2MM Horizontal Size Register(S2MM_HSIZE)0xc80 = 3200dec = 800 x 4
axi_vdma_0[42] = 0xc80; // S2MM Frame Delay and Stride Register(S2MM_FRMDLY_STRIDE)0xc80 = 3200dec = 800 x 4
axi_vdma_0[43] = (int)phys_addr; // S2MM Start Address (1 to 16) Start Address 1
axi_vdma_0[44] = (int)phys_addr+ALL_DISP_ADDRESS; // S2MM Start Address (1 to 16) Start Address 2
axi_vdma_0[45] = (int)phys_addr+2*ALL_DISP_ADDRESS; // S2MM Start Address (1 to 16) Start Address 3
axi_vdma_0[12] = 0x00010003; // S2MM_VDMACR(IRQFrameCount = 0x1, Circular_Park = 1, Run/stop = 1)
while((axi_vdma_0[13] & 0x1) == 0x1) ; // Halt? (S2MM_VDMASR 0x34)
axi_vdma_0[40] = 0x258; // S2MM Vertical Size (S2MM_VSIZE Offset 0xA0) 0x258 = 600dec
// bitmap display controller settings
bmdc_axi_lites0[0] = (int)phys_addr; // Bitmap Display Controller 0 start
bmdc_axi_lites1[0] = (int)phys_addr; // Bitmap Display Controller 1 start
mt9d111_inf_axis_0[0] = (int)phys_addr; // Camera Interface start (Address is dummy)
// CMOS Camera initialize, MT9D111
cam_i2c_init(mt9d111_axi_iic);
cam_i2c_write(mt9d111_axi_iic, 0xba, 0xf0, 0x1); // Changed regster map to IFP page 1
cam_i2c_write(mt9d111_axi_iic, 0xba, 0x97, 0x20); // RGB Mode, RGB565
mt9d111_inf_axis_0[1] = 0;
munmap((void *)bmdc_axi_lites0, 0x10000);
munmap((void *)bmdc_axi_lites1, 0x10000);
munmap((void *)axi_vdma_0, 0x10000);
munmap((void *)mt9d111_inf_axis_0, 0x10000);
munmap((void *)mt9d111_axi_iic, 0x10000);
munmap((void *)axis_switch_0, 0x10000);
munmap((void *)axis_switch_1, 0x10000);
munmap((void *)axi_gpio_0, 0x10000);
munmap((void *)frame_buffer_bmdc, 576000);
close(fd0);
close(fd1);
close(fd2);
close(fd3);
close(fd4);
close(fd5);
close(fd6);
close(fd7);
close(fd8);
close(fd9);
return(0);
}
obj-m := udmabuf.o
all:
make -C ../Linux-Digilent-Dev/ M=$(PWD) modules
clean:
make -C ../Linux-Digilent-Dev/ M=$(PWD) clean
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat phys_addr
0x18900000
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat size
5760000
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat dev
244:0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_direction
0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_for_cpu
0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_for_device
0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_mode
1
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_offset
0x0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_owner
0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat sync_size
5760000
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat uevent
MAJOR=244
MINOR=0
DEVNAME=udmabuf0
linaro@linaro-ubuntu-desktop:/sys/devices/virtual/udmabuf/udmabuf0$ cat debug_vma
0
制約が追加された。set_clock_groups -name clk_fpga_0_pixel_clk -asynchronous -group [get_clocks clk_fpga_0] -group [get_clocks [list [get_clocks -of_objects [get_pins StereoCamTest_i/bitmap_disp_cntrler_axi_master_0/inst/dvi_disp_i/BUFR_pixel_clk_io/O]]]]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[0]}]
set_property PACKAGE_PIN J18 [get_ports {vga_blue[3]}]
set_property PACKAGE_PIN K19 [get_ports {vga_blue[2]}]
set_property PACKAGE_PIN M20 [get_ports {vga_blue[1]}]
set_property PACKAGE_PIN P20 [get_ports {vga_blue[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[4]}]
set_property PACKAGE_PIN G19 [get_ports {vga_blue[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[0]}]
set_property PACKAGE_PIN F20 [get_ports {vga_green[5]}]
set_property PACKAGE_PIN H20 [get_ports {vga_green[4]}]
set_property PACKAGE_PIN J19 [get_ports {vga_green[3]}]
set_property PACKAGE_PIN L19 [get_ports {vga_green[2]}]
set_property PACKAGE_PIN N20 [get_ports {vga_green[1]}]
set_property PACKAGE_PIN H18 [get_ports {vga_green[0]}]
set_property PACKAGE_PIN F19 [get_ports {vga_red[4]}]
set_property PACKAGE_PIN G20 [get_ports {vga_red[3]}]
set_property PACKAGE_PIN J20 [get_ports {vga_red[2]}]
set_property PACKAGE_PIN L20 [get_ports {vga_red[1]}]
set_property PACKAGE_PIN M19 [get_ports {vga_red[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports vga_hsync]
set_property IOSTANDARD LVCMOS33 [get_ports vga_vsync]
set_property PACKAGE_PIN P19 [get_ports vga_hsync]
set_property PACKAGE_PIN R19 [get_ports vga_vsync]
set_property PACKAGE_PIN H16 [get_ports TMDS_Clk_p]
set_property PACKAGE_PIN D19 [get_ports {TMDS_Data_p[0]}]
set_property PACKAGE_PIN C20 [get_ports {TMDS_Data_p[1]}]
set_property PACKAGE_PIN B19 [get_ports {TMDS_Data_p[2]}]
#set_property IOSTANDARD TMDS_33 [get_ports TMDS_Clk_p]
#set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[0]}]
#set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[1]}]
#set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[2]}]
set_property PACKAGE_PIN G18 [get_ports ddc_sda_io]
set_property PACKAGE_PIN G17 [get_ports ddc_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports ddc_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports ddc_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_hpd[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_out_en[0]}]
set_property PACKAGE_PIN E18 [get_ports {hdmi_hpd[0]}]
set_property PACKAGE_PIN F17 [get_ports {hdmi_out_en[0]}]
set_property PACKAGE_PIN L16 [get_ports clk125]
set_property IOSTANDARD LVCMOS33 [get_ports clk125]
set_property PACKAGE_PIN T14 [get_ports {cam_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[0]}]
set_property PACKAGE_PIN U14 [get_ports {cam_data[6]}]
set_property PACKAGE_PIN T15 [get_ports {cam_data[5]}]
set_property PACKAGE_PIN U15 [get_ports {cam_data[4]}]
set_property PACKAGE_PIN P14 [get_ports {cam_data[3]}]
set_property PACKAGE_PIN V17 [get_ports {cam_data[2]}]
set_property PACKAGE_PIN R14 [get_ports {cam_data[1]}]
set_property PACKAGE_PIN V18 [get_ports {cam_data[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports mt9d111_iic_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports mt9d111_iic_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports href]
set_property IOSTANDARD LVCMOS33 [get_ports pclk]
set_property IOSTANDARD LVCMOS33 [get_ports standby]
set_property IOSTANDARD LVCMOS33 [get_ports vsync]
set_property IOSTANDARD LVCMOS33 [get_ports xck]
set_property PACKAGE_PIN V15 [get_ports mt9d111_iic_scl_io]
set_property PACKAGE_PIN W14 [get_ports mt9d111_iic_sda_io]
set_property PACKAGE_PIN W15 [get_ports vsync]
set_property PACKAGE_PIN Y14 [get_ports href]
set_property PACKAGE_PIN T11 [get_ports standby]
set_property PACKAGE_PIN T10 [get_ports pclk]
set_property PACKAGE_PIN U12 [get_ports xck]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF]
set_clock_groups -name clk_fpga_0_pixel_clk -asynchronous -group [get_clocks clk_fpga_0] -group [get_clocks [list [get_clocks -of_objects [get_pins StereoCamTest_i/bitmap_disp_cntrler_axi_master_0/inst/dvi_disp_i/BUFR_pixel_clk_io/O]]]]
で design_name を StereoCamTest に設定した。set design_name StereoCamTest
camera_interface 階層を生成するブロックデザインを選択する必要があるだろうから。。。current_bd_design $design_name
を記述した。create_hier_cell_camera_interface [current_bd_instance .] camera_interface
コマンドを起動して、camera_interface 階層を生成する。source CreateCameraInterface.tcl
# CreateCameraInterface.tcl
#
################################################################
# Check if script is running in correct Vivado version.
################################################################
set scripts_vivado_version 2015.4
set current_vivado_version [version -short]
# CHANGE DESIGN NAME HERE
set design_name StereoCamTest
# If you do not already have an existing IP Integrator design open,
# you can create a design using the following command:
# create_bd_design $design_name
# Creating design if needed
set errMsg ""
set nRet 0
set cur_design [current_bd_design -quiet]
set list_cells [get_bd_cells -quiet]
puts "INFO: Making design <$design_name> as current_bd_design."
current_bd_design $design_name
# Hierarchical cell: camera_interface
proc create_hier_cell_camera_interface { parentCell nameHier } {
if { $parentCell eq "" || $nameHier eq "" } {
puts "ERROR: create_hier_cell_camera_interface() - Empty argument(s)!"
return
}
# Get object for parentCell
set parentObj [get_bd_cells $parentCell]
if { $parentObj == "" } {
puts "ERROR: Unable to find parent cell <$parentCell>!"
return
}
# Make sure parentObj is hier blk
set parentType [get_property TYPE $parentObj]
if { $parentType ne "hier" } {
puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be <hier>."
return
}
# Save current instance; Restore later
set oldCurInst [current_bd_instance .]
# Set parent object as current
current_bd_instance $parentObj
# Create cell and set as current instance
set hier_obj [create_bd_cell -type hier $nameHier]
current_bd_instance $hier_obj
# Create interface pins
create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:iic_rtl:1.0 IIC
create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_S2MM
create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S_AXI
create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S_AXI_CTRL
create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S_AXI_CTRL1
create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S_AXI_LITE
create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 s_axi_AXILiteS
create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 s_axi_lite1
# Create pins
create_bd_pin -dir I -from 0 -to 0 -type rst aresetn
create_bd_pin -dir I -from 7 -to 0 cam_data
create_bd_pin -dir I href
create_bd_pin -dir I pclk
create_bd_pin -dir I pclk_from_pll
create_bd_pin -dir I -type clk s_axi_aclk
create_bd_pin -dir I -from 0 -to 0 -type rst s_axi_aresetn
create_bd_pin -dir O standby
create_bd_pin -dir I vsync
create_bd_pin -dir O xck
# Create instance: axi_iic_0, and set properties
set axi_iic_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_iic:2.0 axi_iic_0 ]
# Create instance: axi_vdma_0, and set properties
set axi_vdma_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_vdma:6.2 axi_vdma_0 ]
set_property -dict [ list \
CONFIG.c_include_mm2s {0} \
CONFIG.c_m_axi_mm2s_data_width {64} \
CONFIG.c_mm2s_genlock_mode {0} \
CONFIG.c_mm2s_max_burst_length {8} \
] $axi_vdma_0
# Create instance: axis_switch_0, and set properties
set axis_switch_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_switch:1.1 axis_switch_0 ]
set_property -dict [ list \
CONFIG.DECODER_REG {0} \
CONFIG.NUM_MI {1} \
CONFIG.NUM_SI {2} \
CONFIG.ROUTING_MODE {1} \
] $axis_switch_0
# Create instance: axis_switch_1, and set properties
set axis_switch_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_switch:1.1 axis_switch_1 ]
set_property -dict [ list \
CONFIG.DECODER_REG {1} \
CONFIG.NUM_MI {2} \
CONFIG.NUM_SI {1} \
CONFIG.ROUTING_MODE {1} \
] $axis_switch_1
# Create instance: lap_filter_axis_0, and set properties
set lap_filter_axis_0 [ create_bd_cell -type ip -vlnv xilinx.com:hls:lap_filter_axis:1.0 lap_filter_axis_0 ]
# Create instance: mt9d111_inf_axis_0, and set properties
set mt9d111_inf_axis_0 [ create_bd_cell -type ip -vlnv marsee:user:mt9d111_inf_axis:1.0 mt9d111_inf_axis_0 ]
# Create interface connections
connect_bd_intf_net -intf_net axi_iic_0_IIC [get_bd_intf_pins IIC] [get_bd_intf_pins axi_iic_0/IIC]
connect_bd_intf_net -intf_net axi_vdma_0_M_AXI_S2MM [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins axi_vdma_0/M_AXI_S2MM]
connect_bd_intf_net -intf_net axis_switch_0_M00_AXIS [get_bd_intf_pins axi_vdma_0/S_AXIS_S2MM] [get_bd_intf_pins axis_switch_0/M00_AXIS]
connect_bd_intf_net -intf_net axis_switch_1_M00_AXIS [get_bd_intf_pins axis_switch_0/S00_AXIS] [get_bd_intf_pins axis_switch_1/M00_AXIS]
connect_bd_intf_net -intf_net axis_switch_1_M01_AXIS [get_bd_intf_pins axis_switch_1/M01_AXIS] [get_bd_intf_pins lap_filter_axis_0/ins]
connect_bd_intf_net -intf_net lap_filter_axis_0_outs [get_bd_intf_pins axis_switch_0/S01_AXIS] [get_bd_intf_pins lap_filter_axis_0/outs]
connect_bd_intf_net -intf_net mt9d111_inf_axis_0_m_axis [get_bd_intf_pins axis_switch_1/S00_AXIS] [get_bd_intf_pins mt9d111_inf_axis_0/m_axis]
connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M00_AXI [get_bd_intf_pins s_axi_lite1] [get_bd_intf_pins mt9d111_inf_axis_0/s_axi_lite]
connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M01_AXI [get_bd_intf_pins S_AXI] [get_bd_intf_pins axi_iic_0/S_AXI]
connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M02_AXI [get_bd_intf_pins s_axi_AXILiteS] [get_bd_intf_pins lap_filter_axis_0/s_axi_AXILiteS]
connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M04_AXI [get_bd_intf_pins S_AXI_LITE] [get_bd_intf_pins axi_vdma_0/S_AXI_LITE]
connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M05_AXI [get_bd_intf_pins S_AXI_CTRL] [get_bd_intf_pins axis_switch_0/S_AXI_CTRL]
connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M06_AXI [get_bd_intf_pins S_AXI_CTRL1] [get_bd_intf_pins axis_switch_1/S_AXI_CTRL]
# Create port connections
connect_bd_net -net cam_data_1 [get_bd_pins cam_data] [get_bd_pins mt9d111_inf_axis_0/cam_data]
connect_bd_net -net href_1 [get_bd_pins href] [get_bd_pins mt9d111_inf_axis_0/href]
connect_bd_net -net mt9d111_inf_axis_0_standby [get_bd_pins standby] [get_bd_pins mt9d111_inf_axis_0/standby]
connect_bd_net -net mt9d111_inf_axis_0_xck [get_bd_pins xck] [get_bd_pins mt9d111_inf_axis_0/xck]
connect_bd_net -net pclk_1 [get_bd_pins pclk] [get_bd_pins mt9d111_inf_axis_0/pclk]
connect_bd_net -net processing_system7_0_FCLK_CLK0 [get_bd_pins s_axi_aclk] [get_bd_pins axi_iic_0/s_axi_aclk] [get_bd_pins axi_vdma_0/m_axi_s2mm_aclk] [get_bd_pins axi_vdma_0/s_axi_lite_aclk] [get_bd_pins axi_vdma_0/s_axis_s2mm_aclk] [get_bd_pins axis_switch_0/aclk] [get_bd_pins axis_switch_0/s_axi_ctrl_aclk] [get_bd_pins axis_switch_1/aclk] [get_bd_pins axis_switch_1/s_axi_ctrl_aclk] [get_bd_pins lap_filter_axis_0/ap_clk] [get_bd_pins mt9d111_inf_axis_0/m_axis_aclk] [get_bd_pins mt9d111_inf_axis_0/s_axi_lite_aclk]
connect_bd_net -net processing_system7_0_FCLK_CLK2 [get_bd_pins pclk_from_pll] [get_bd_pins mt9d111_inf_axis_0/pclk_from_pll]
connect_bd_net -net rst_processing_system7_0_100M_interconnect_aresetn [get_bd_pins aresetn] [get_bd_pins axis_switch_0/aresetn] [get_bd_pins axis_switch_1/aresetn]
connect_bd_net -net rst_processing_system7_0_100M_peripheral_aresetn [get_bd_pins s_axi_aresetn] [get_bd_pins axi_iic_0/s_axi_aresetn] [get_bd_pins axi_vdma_0/axi_resetn] [get_bd_pins axis_switch_0/s_axi_ctrl_aresetn] [get_bd_pins axis_switch_1/s_axi_ctrl_aresetn] [get_bd_pins lap_filter_axis_0/ap_rst_n] [get_bd_pins mt9d111_inf_axis_0/axi_resetn]
connect_bd_net -net vsync_1 [get_bd_pins vsync] [get_bd_pins mt9d111_inf_axis_0/vsync]
# Restore current instance
current_bd_instance $oldCurInst
}
# Create instance: camera_interface
create_hier_cell_camera_interface [current_bd_instance .] camera_interface
コマンドを入力し、リターンキーで実行させた。cd z:/test/StereoCamTest_154/
source StereoCamTest.tcl
// bmp_header.h
// 2015/07/17 by Masaaki Ono
//
// BMP ファイルフォーマットから引用
// http://www.kk.iij4u.or.jp/~kondo/bmp/
//
#pragma once
#include <stdio.h>
#include <tchar.h>
// TODO: プログラムに必要な追加ヘッダーをここで参照してください。
// BITMAPFILEHEADER 14bytes
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} BITMAPFILEHEADER;
// BITMAPINFOHEADER 40bytes
typedef struct tagBITMAPINFOHEADER{
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPixPerMeter;
long biYPixPerMeter;
unsigned long biClrUsed;
unsigned long biClrImporant;
} BITMAPINFOHEADER;
typedef struct BMP24bitsFORMAT {
unsigned char blue;
unsigned char green;
unsigned char red;
} BMP24FORMAT;
// lap_filter_axis.h
// 2015/05/01
//#define HORIZONTAL_PIXEL_WIDTH 800
//#define VERTICAL_PIXEL_WIDTH 600
#define HORIZONTAL_PIXEL_WIDTH 64
#define VERTICAL_PIXEL_WIDTH 48
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
//
// lap_filter_axis.cpp
// 2015/05/01
// 2015/06/25 : 修正、ラプラシアンフィルタの値が青だけ担っていたので、RGBに拡張した
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include "lap_filter_axis.h"
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
int lap_filter_axis(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE axis port=ins
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE s_axilite port=return
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> lap;
unsigned int line_buf[2][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=2 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P
int pix_mat[3][3];
#pragma HLS array_partition variable=pix_mat complete
int lap_fil_val;
do { // user が 1になった時にフレームがスタートする
ins >> pix;
} while(pix.user == 0);
for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
for (int k=0; k<3; k++){
for (int m=0; m<2; m++){
#pragma HLS UNROLL
pix_mat[k][m] = pix_mat[k][m+1];
}
}
pix_mat[0][2] = line_buf[0][x];
pix_mat[1][2] = line_buf[1][x];
int y_val = conv_rgb2y(pix.data);
pix_mat[2][2] = y_val;
line_buf[0][x] = line_buf[1][x]; // 行の入れ替え
line_buf[1][x] = y_val;
lap_fil_val = laplacian_fil( pix_mat[0][0], pix_mat[0][1], pix_mat[0][2],
pix_mat[1][0], pix_mat[1][1], pix_mat[1][2],
pix_mat[2][0], pix_mat[2][1], pix_mat[2][2]);
lap.data = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
if (x<2 || y<2) // 最初の2行とその他の行の最初の2列は無効データなので0とする
lap.data = 0;
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
lap.user = 1;
else
lap.user = 0;
if (x == (HORIZONTAL_PIXEL_WIDTH-1)) // 行の最後で TLAST をアサートする
lap.last = 1;
else
lap.last = 0;
outs << lap; // AXI4-Stream へ出力
}
}
return 0;
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
// lap_filter_axis_tb.cpp
// 2015/05/01
// 2015/08/17 : BMPファイルを読み書きするように変更した
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <ap_axi_sdata.h>
#include "lap_filter_axis.h"
#include "bmp_header.h"
int lap_filter_axis(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y_soft(int rgb);
int lap_filter_axis_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height);
#define CLOCK_PERIOD 10
int main()
{
using namespace std;
hls::stream<ap_axis<32,1,1,1> > ins;
hls::stream<ap_axis<32,1,1,1> > ins_soft;
hls::stream<ap_axis<32,1,1,1> > outs;
hls::stream<ap_axis<32,1,1,1> > outs_soft;
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> vals;
ap_axis<32,1,1,1> vals_soft;
int m_seq = 1; // M系列の値
int i;
int xor_shift;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw;
int *rd_bmp, *hw_lapd;
int blue, green, red;
if ((fbmpr = fopen("test.bmp", "rb")) == NULL){ // test.bmp をオープン
fprintf(stderr, "Can't open test.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(char), 2, fbmpr);
fread(&bmpfhr.bfSize, sizeof(long), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_lapd =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_lapd memory\n");
exit(1);
}
// 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);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
ins << pix;
}
for(int j=0; j < bmpihr.biHeight; j++){
for(i=0; i < bmpihr.biWidth; i++){
pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == bmpihr.biWidth-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
ins << pix;
ins_soft << pix;
}
}
lap_filter_axis(ins, outs);
lap_filter_axis_soft(ins_soft, outs_soft, bmpihr.biWidth, bmpihr.biHeight);
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
cout << endl;
cout << "outs" << endl;
for(int j=0; j < bmpihr.biHeight; j++){
for(i=0; i < bmpihr.biWidth; i++){
outs >> vals;
outs_soft >> vals_soft;
ap_int<32> val = vals.data;
ap_int<32> val_soft = vals_soft.data;
hw_lapd[(j*bmpihr.biWidth)+i] = (int)val;
if (val != val_soft){
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %d, SW = %d\n", i, j, (int)val, (int)val_soft);
return(1);
}
if (vals.last)
cout << "AXI-Stream is end" << endl;
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
// ハードウェアのラプラシアンフィルタの結果を temp_lap.bmp へ出力する
if ((fbmpw=fopen("temp_lap.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open temp_lap.bmp by binary write mode\n");
exit(1);
}
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(long), 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++){
blue = hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
green = (hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
red = (hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;
fputc(blue, fbmpw);
fputc(green, fbmpw);
fputc(red, fbmpw);
}
}
fclose(fbmpw);
free(rd_bmp);
free(hw_lapd);
return 0;
}
int lap_filter_axis_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height){
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> lap;
unsigned int **line_buf;
int pix_mat[3][3];
int lap_fil_val;
int i;
// line_buf の1次元目の配列をアロケートする
if ((line_buf =(unsigned int **)malloc(sizeof(unsigned int *) * 2)) == NULL){
fprintf(stderr, "Can't allocate line_buf[3][]\n");
exit(1);
}
// メモリをアロケートする
for (i=0; i<2; i++){
if ((line_buf[i]=(unsigned int *)malloc(sizeof(unsigned int) * width)) == NULL){
fprintf(stderr, "Can't allocate line_buf[%d]\n", i);
exit(1);
}
}
do { // user が 1になった時にフレームがスタートする
ins >> pix;
} while(pix.user == 0);
for (int y=0; y<height; y++){
for (int x=0; x<width; x++){
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
for (int k=0; k<3; k++){
for (int m=0; m<2; m++){
pix_mat[k][m] = pix_mat[k][m+1];
}
}
pix_mat[0][2] = line_buf[0][x];
pix_mat[1][2] = line_buf[1][x];
int y_val = conv_rgb2y_soft(pix.data);
pix_mat[2][2] = y_val;
line_buf[0][x] = line_buf[1][x]; // 行の入れ替え
line_buf[1][x] = y_val;
lap_fil_val = laplacian_fil_soft( pix_mat[0][0], pix_mat[0][1], pix_mat[0][2],
pix_mat[1][0], pix_mat[1][1], pix_mat[1][2],
pix_mat[2][0], pix_mat[2][1], pix_mat[2][2]);
lap.data = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
if (x<2 || y<2) // 最初の2行とその他の行の最初の2列は無効データなので0とする
lap.data = 0;
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
lap.user = 1;
else
lap.user = 0;
if (x == (HORIZONTAL_PIXEL_WIDTH-1)) // 行の最後で TLAST をアサートする
lap.last = 1;
else
lap.last = 0;
outs << lap; // AXI4-Stream へ出力
}
}
for (i=0; i<2; i++)
free(line_buf[i]);
free(line_buf);
return 0;
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y_soft(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[0]}]
set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[1]}]
set_property IOSTANDARD TMDS_33 [get_ports {TMDS_Data_p[2]}]
set_property IOSTANDARD TMDS_33 [get_ports TMDS_Clk_p]
set_property PACKAGE_PIN D19 [get_ports {TMDS_Data_p[0]}]
set_property PACKAGE_PIN C20 [get_ports {TMDS_Data_p[1]}]
set_property PACKAGE_PIN B19 [get_ports {TMDS_Data_p[2]}]
set_property PACKAGE_PIN H16 [get_ports TMDS_Clk_p]
制約が追加された。set_clock_groups -name FCLK_CLK0_FCLK_CLK3 -asynchronous -group [get_clocks clk_fpga_0] -group [get_clocks clk_fpga_3]
// bmp_header.h
// 2015/07/17 by Masaaki Ono
//
// BMP ファイルフォーマットから引用
// http://www.kk.iij4u.or.jp/~kondo/bmp/
//
#pragma once
#include <stdio.h>
#include <tchar.h>
// TODO: プログラムに必要な追加ヘッダーをここで参照してください。
// BITMAPFILEHEADER 14bytes
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} BITMAPFILEHEADER;
// BITMAPINFOHEADER 40bytes
typedef struct tagBITMAPINFOHEADER{
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPixPerMeter;
long biYPixPerMeter;
unsigned long biClrUsed;
unsigned long biClrImporant;
} BITMAPINFOHEADER;
typedef struct BMP24bitsFORMAT {
unsigned char blue;
unsigned char green;
unsigned char red;
} BMP24FORMAT;
// laplacian_filter_soft.c
// m_axi offset=slave Version
// lap_filter_axim()
// 2015/08/26 by marsee
//
#include <stdio.h>
#include <string.h>
#define HORIZONTAL_PIXEL_WIDTH 64
#define VERTICAL_PIXEL_WIDTH 48
//#define HORIZONTAL_PIXEL_WIDTH 800
//#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb
int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int a, b;
int fl, sl, tl;
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (y == 1 && x == 1){ // 最初のラインの最初のピクセルでは2ライン分の画素を読み出す
for (a=0; a<2; a++){ // 2ライン分
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[a][b] = cam_fb[(a*HORIZONTAL_PIXEL_WIDTH)+b];
line_buf[a][b] = conv_rgb2y(line_buf[a][b]);
}
}
}
if (x == 1) { // ラインの最初なので、2つのピクセルを読み込む
for (b=0; b<2; b++){ // ライン
line_buf[(y+1)%3][b] = cam_fb[((y+1)*HORIZONTAL_PIXEL_WIDTH)+b];
// (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]);
}
}
// 1つのピクセルを読み込みながらラプラシアン・フィルタを実行する
line_buf[(y+1)%3][x+1] = cam_fb[((y+1)*HORIZONTAL_PIXEL_WIDTH)+(x+1)];
// (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
line_buf[(y+1)%3][x+1] = conv_rgb2y(line_buf[(y+1)%3][x+1]);
fl = (y-1)%3; // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
sl = y%3; // 2番めのライン
tl = (y+1)%3; // 3番目のライン
lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
// ラプラシアンフィルタ・データの書き込み
lap_fb[(y*HORIZONTAL_PIXEL_WIDTH)+x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val ;
// printf("x = %d y = %d", x, y);
}
}
return(1);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
// Testbench of laplacian_filter.c
// lap_filter_tb.c
// BMPデータをハードウェアとソフトウェアで、ラプラシアン・フィルタを掛けて、それを比較する
// m_axi offset=slave version
// 2015/08/26 by marsee
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bmp_header.h"
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y_soft(int rgb);
int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb); // hardware
void laplacian_filter_soft(int *cam_fb, int *lap_fb, long width, long height); // software
int main()
{
int *s, *h;
long x, y;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw;
int *rd_bmp, *hw_lapd, *sw_lapd;
int blue, green, red;
char blue_c, green_c, red_c;
if ((fbmpr = fopen("test.bmp", "rb")) == NULL){ // test.bmp をオープン
fprintf(stderr, "Can't open test.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(char), 2, fbmpr);
fread(&bmpfhr.bfSize, sizeof(long), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_lapd =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_lapd memory\n");
exit(1);
}
if ((sw_lapd =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate sw_lapd memory\n");
exit(1);
}
// 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);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
lap_filter_axim((int *)rd_bmp, (int *)hw_lapd); // ハードウェアのラプラシアン・フィルタ
laplacian_filter_soft(rd_bmp, sw_lapd, bmpihr.biWidth, bmpihr.biHeight); // ソフトウェアのラプラシアン・フィルタ
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
for (y=0, h=hw_lapd, s=sw_lapd; y<bmpihr.biHeight; y++){
for (x=0; x<bmpihr.biWidth; x++){
if (*h != *s){
printf("ERROR HW and SW results mismatch x = %ld, y = %ld, HW = %d, SW = %d\n", x, y, *h, *s);
return(1);
} else {
h++;
s++;
}
}
}
printf("Success HW and SW results match\n");
// ハードウェアのラプラシアンフィルタの結果を temp_lap.bmp へ出力する
if ((fbmpw=fopen("temp_lap.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open temp_lap.bmp by binary write mode\n");
exit(1);
}
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (y=0; y<bmpihr.biHeight; y++){
for (x=0; x<bmpihr.biWidth; x++){
blue = hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
green = (hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
red = (hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;
fputc(blue, fbmpw);
fputc(green, fbmpw);
fputc(red, fbmpw);
}
}
fclose(fbmpw);
free(rd_bmp);
free(hw_lapd);
free(sw_lapd);
return(0);
}
void laplacian_filter_soft(int *cam_fb, int *lap_fb, long width, long height)
{
int **line_buf;
int *lap_buf;
int x, y, i;
int lap_fil_val;
int a, b;
int fl, sl, tl;
// line_buf の1次元目の配列をアロケートする
if ((line_buf =(int **)malloc(sizeof(int *) * 3)) == NULL){
fprintf(stderr, "Can't allocate line_buf[3][]\n");
exit(1);
}
// メモリをアロケートする
for (i=0; i<3; i++){
if ((line_buf[i]=(int *)malloc(sizeof(int) * width)) == NULL){
fprintf(stderr, "Can't allocate line_buf[%d]\n", i);
exit(1);
}
}
if ((lap_buf=(int *)malloc(sizeof(int) * (width))) == NULL){
fprintf(stderr, "Can't allocate lap_buf memory\n");
exit(1);
}
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0; y<height; y++){
for (x=0; x<width; x++){
if (y==0 || y==height-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==width-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (y == 1 && x == 1){ // 最初のラインの最初のピクセルでは2ライン分の画素を読み出す
for (a=0; a<2; a++){ // 2ライン分
for (b=0; b<width; b++){ // ライン
line_buf[a][b] = cam_fb[(a*width)+b];
line_buf[a][b] = conv_rgb2y_soft(line_buf[a][b]);
}
}
}
if (x == 1) { // ラインの最初なので、2つのピクセルを読み込む
for (b=0; b<2; b++){ // ライン
line_buf[(y+1)%3][b] = cam_fb[((y+1)*width)+b];
// (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
line_buf[(y+1)%3][b] = conv_rgb2y_soft(line_buf[(y+1)%3][b]);
}
}
// 1つのピクセルを読み込みながらラプラシアン・フィルタを実行する
line_buf[(y+1)%3][x+1] = cam_fb[((y+1)*width)+(x+1)];
// (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
line_buf[(y+1)%3][x+1] = conv_rgb2y_soft(line_buf[(y+1)%3][x+1]);
fl = (y-1)%3; // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
sl = y%3; // 2番めのライン
tl = (y+1)%3; // 3番目のライン
lap_fil_val = laplacian_fil_soft(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
// ラプラシアンフィルタ・データの書き込み
lap_fb[(y*width)+x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val ;
}
}
free(lap_buf);
for (i=0; i<3; i++)
free(line_buf[i]);
free(line_buf);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y_soft(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
// laplacian_filter2.c
// lap_filter_axim()
// m_axi offset=slave version
// 2015/08/26 by marsee
//
#include <stdio.h>
#include <string.h>
#define HORIZONTAL_PIXEL_WIDTH 64
#define VERTICAL_PIXEL_WIDTH 48
//#define HORIZONTAL_PIXEL_WIDTH 800
//#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb
int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int a, b;
int fl, sl, tl;
int line_sel;
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0, line_sel=0; y<VERTICAL_PIXEL_WIDTH; y++){
// 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
switch(line_sel){
case 1 :
fl = 0; sl = 1; tl = 2;
break;
case 2 :
fl = 1; sl = 2; tl = 0;
break;
case 3 :
fl = 2; sl = 0; tl = 1;
break;
default :
fl = 0; sl = 1; tl = 2;
}
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (x == 1){ // ラインの最初でラインの画素を読み出す
if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
for (a=0; a<3; a++){ // 3ライン分
memcpy(&line_buf[a][0], (const int*)&cam_fb[a*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){
#pragma HLS PIPELINE
// ライン
line_buf[a][b] = conv_rgb2y(line_buf[a][b]); // カラーから白黒へ
}
}
} else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
memcpy(line_buf[tl], (const int*)&cam_fb[(y+1)*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){
#pragma HLS PIPELINE
// ライン
line_buf[tl][b] = conv_rgb2y(line_buf[tl][b]); // カラーから白黒へ
}
}
}
lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
}
memcpy(&((int *)lap_fb)[y*(HORIZONTAL_PIXEL_WIDTH)], (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
line_sel++;
if (line_sel > 3){
line_sel = 1;
}
}
return(1);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
// laplacian_filter3.c
// m_axi offset=slave version
// 2015/08/26
//
#include <stdio.h>
#include <string.h>
#define HORIZONTAL_PIXEL_WIDTH 64
#define VERTICAL_PIXEL_WIDTH 48
//#define HORIZONTAL_PIXEL_WIDTH 800
//#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb
int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=3 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P
int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int a, b;
int fl, sl, tl;
int line_sel;
int prev[3],current[3],next[3]; // 0->1ライン目, 1->2ライン目, 2->3ライン目, prev->1pixel前, current->現在, next->次pixel
#pragma HLS array_partition variable=prev complete dim=0
#pragma HLS array_partition variable=current complete dim=0
#pragma HLS array_partition variable=next complete dim=0
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0, line_sel=0; y<VERTICAL_PIXEL_WIDTH-1; y++){
// 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
switch(line_sel){
case 1 :
fl = 0; sl = 1; tl = 2;
break;
case 2 :
fl = 1; sl = 2; tl = 0;
break;
case 3 :
fl = 2; sl = 0; tl = 1;
break;
default :
fl = 0; sl = 1; tl = 2;
}
if (y == 1){
#ifndef __SYNTHESIS__
printf("copy 3 lines\n");
#endif
for (a=0; a<3; a++){
// 3ライン分
memcpy(line_buf[a], (const int*)&cam_fb[a*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
}
}else{ // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
memcpy(line_buf[tl], (const int*)&cam_fb[(y+1)*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
}
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){
for(b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){
lap_buf[b] = 0;
}
} else {
next[0] = conv_rgb2y(line_buf[fl][0]);
next[1] = conv_rgb2y(line_buf[sl][0]);
next[2] = conv_rgb2y(line_buf[tl][0]);
for (x = 0; x < HORIZONTAL_PIXEL_WIDTH; x++){
if (x == 0 || x == HORIZONTAL_PIXEL_WIDTH-1){
lap_fil_val = 0;
current[0] = next[0];
next[0] = conv_rgb2y(line_buf[fl][1]);
current[1] = next[1];
next[1] = conv_rgb2y(line_buf[sl][1]);
current[2] = next[2];
next[2] = conv_rgb2y(line_buf[tl][1]);
}else{
prev[0] = current[0];
current[0] = next[0];
next[0] = conv_rgb2y(line_buf[fl][x+1]);
prev[1] = current[1];
current[1] = next[1];
next[1] = conv_rgb2y(line_buf[sl][x+1]);
prev[2] = current[2];
current[2] = next[2];
next[2] = conv_rgb2y(line_buf[tl][x+1]);
#pragma HLS pipeline
lap_fil_val = laplacian_fil(prev[0], current[0], next[0],
prev[1], current[1], next[1],
prev[2], current[2], next[2]);
}
lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
}
}
#ifndef __SYNTHESIS__
printf("write back:%d\n", y);
#endif
memcpy((int*)&lap_fb[y*(HORIZONTAL_PIXEL_WIDTH)], (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
line_sel++;
if (line_sel > 3){
line_sel = 1;
}
}
return(0);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : line[sl]oat を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |