《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​
  95kVyaJuybju 2023年11月12日 22 0

双目OV5640摄像头LCD显示实验​

双目摄像头是在一个模组上集成了两个摄像头,实现了双通道的图像采集。双目摄像头一般应用于安防监控、立体视觉测距、三维重建等领域。本章我们将使用ZYNQ MPSoC开发板实现对双目OV5640摄像头的图像采集并通过LCD屏幕实时显示。

本章包括以下几个部分:

  1. 简介
  2. 实验任务
  3. 硬件设计
  4. 软件设计
  5. 下载验证

简介

摄像头在日常生活中非常常见,一般分为单目摄像头、双目摄像头和多目摄像头。单目摄像头凭借着成本低和易用的特点,目前使用最为广泛;双目摄像头主要应用于单目摄像头无法胜任的场合,如三维坐标定位等;当然针对一些特殊的应用,目前市场上也出现了多目摄像头,以应对更加复杂的场景。

我们在前面的例程中实现了单目OV5640摄像头LCD屏的实时显示,本章我们在此基础上实现双目OV5640摄像头的实时显示,即两路摄像头的图像视频显示在LCD屏上,并叠加两个标记层的显示。Xilinx官方提供了专门用于视频混合显示和图层叠加的视频处理模块,即OSDOn Screen Display)IP核和Video Mixer IP核,由于新版本的开发环境已经不支持OSD IP核,所以我们使用Video Mixer IP核。

Video Mixer IP核为alpha混合和合成多个视频或图形层提供了灵活的视频处理方法,支持多达17层(一个主层和16个覆盖层),带有可选的logo层,使用来自内存或AXI-Stream流的视频输入组合。Video Mixer IP核可通过综合寄存器接口进行编程,以控制帧大小、背景颜色、层位置和AXI4 Lite接口。该IP核也支持中断操作。

Video Mixer IP核的特性和优势如下所示:

(1):支持(每像素)8 个视频/图形和标识层的 α 混合;

(2):可选标识(块 RAM (BRAM))层支持色彩透明;

(3):各层既可以是内存映射的 AXI4 接口,也可以是 AXI4-Stream;

(4):提供可编程背景色彩;

(5):提供可编程层位置及尺寸;

(6):可按 1 倍、2 倍或 4 倍提供层缩放;

(7):可选内建色彩空间转换;

(8):支持 RGB、YUV 444、YUV 422、 YUV 420;

(9):支持流媒体 8 位、10 位、12 位和 16 位每个色彩组件的输入输出;

(10):接口,内存接口上 8 位和 10 位每个色彩组件;

(11):支持的空间分辨率: 64 × 64 至 4,096 × 2,160;

(12):在所有支持的器件系列中,支持 4K 60 fps;

Video Mixer IP核寄存器包括顶层寄存器、CSC系数寄存器、图层寄存器和Logo层寄存器,这里我们介绍实验里用到的顶层寄存器和图层寄存器。

顶层寄存器包括下面这些:

“Control”寄存器:bit[7]~bit[0]共8bit控制位,包括控制传输开始、传输完成标志、空闲标志、ready标志、刷新事件挂起、刷新状态、自动重启模式。

Global Interrupt Enable”:IP核中断使能寄存器,用来使能IP核内所有中断。

IP Interrupt Enable”:该寄存器允许选择性的启动中断。

IP Interrupt Status Register”:双重用途寄存器。当中断发生时,相应的中断源位被设置在此寄存器中。在读回模式下,可以确定中断源。在写回模式下,请求的中断源位被清除。

Width”:该寄存器用来设置每一行的有效像素个数。

Height”:该寄存器用来设置每一帧有多少行。

Layer enable”:图层使能寄存器,bit[0]用来使能Master层,也就是最底层,其它图层在这一层上叠加,bit[1]~bit[16]用来使能Layer1~Layer16,bit[23]用来使能Logo层,也就是最顶层。

图层寄存器包括下面这些寄存器:

Alpha”:设置透明度寄存器。

Start X”:图层左上角的X位置。

Start Y”:图层左上角的Y位置。

Width”:图层的有效宽度(单位:像素)。

Stride”:当图层视频数据为Memory类型时,该寄存器有效,表示一行当中像素的总字节数。

Height”:图层的有效高度(单位:行)。

Scale Factor”:图层缩放因子。

Plane 1 Buffer”:对于Memory类型图层,用于指定平面1的缓冲地址。

Plane 2 Buffer”:在半平面模式下有效,用于指定平面2缓冲地址。

实验任务

本章的实验任务是通过调用Video Mixer IP核,在ZYNQ MPSoC开发板实现双目OV5640摄像头LCD屏幕实时显示,并在LCD屏幕上显示标记层。

硬件设计

我们的ZYNQ开发板上有J1、J19两个扩展接口,本次实验使用的是J19扩展口(纽扣电池座附近),该接口可以用来连接双目OV5640摄像头、高速ADDA等模块,扩展接口原理图如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_寄存器


31.3.1扩展接口原理图

ATK-Dual-OV5640是正点原子推出的一款双目OV5640摄像头,该模块通过2*20排母(2.54mm间距)同外部连接,连接时将双目摄像头的排母直接插在开发板上的扩展口即可,模块外观如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_ide_02


31.3.2双目OV5640模块

由于双目OV5640的引脚较多,这里不再给出引脚分配列表,在硬件设计的最后给出了本次实验管脚分配的约束代码,大家在搭建工程时可以直接拷贝。

我们在前面的例程中实现了单目OV5640摄像头LCD接口的实时显示,本章我们在此基础上,增加了一路摄像头的图像采集与显示,然后使用视频混合IP核将这两路视频拼接到一起显示。Xilinx官方提供的Video Mixer IP核最大支17层外部视频的输入,本实验使用4路视频输入,包括两路摄像头采集的视频和两路标记层输入,标记层用来区分OV5640 1摄像头和OV5640 2摄像头。打开第二十七章OV5640摄像头LCD显示实验的工程,点击File->Project->Save as,将工程另存为dual_ov5640_lcd工程,然后将原ov5640_lcd工程下ip_repo文件夹复制到当前工程路径下,并将这个文件夹下的ip核添加到工程中,添加之前先将原来添加的ip核删除,具体方法参考《自定义IP核-呼吸灯实验》中6.3.44所示的步骤,这样我们的双目OV5640 LCD显示的工程初步搭建起来了。

在导航栏中点击“Open Block Design”,打开设计框图,将“Processor System Reset”、“AXI Interconnect”、“AXI SmartConnect”三个IP核删除,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_IP_03


31.3.3删除IP核

删除AXI4-Stream to Video Out核中video_in端口和axi_vdma_0核的连接。

然后分别添加“ov5640_capture_data”、“video in to AXI4-Stream”、“vdma”IP核。添加完成后,先将“ov5640_capture_data_1”IP核相应端口引出,并将后缀改为“_2,”,修改完成后如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_寄存器_04


《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_ide_05


31.3.4引出端口并重命名

重新配置vdma_1 IP核的数据位宽为24。

配置v_vid_in_axi4s_1 IP核的Clock Mode为“Independent”模式。

接下来添加Video Mixer IP核。这里需要注意的是,直接添加完该IP核后,在后面的“Generate Output Product”步骤中会报“找不到Video Mixer IP”的错误,这是软件Bug导致的时间溢出问题。解决方法是,读者到“正点原子ZYNQ售后群”(QQ群)中下载《HLS时间溢出》文档,按照里面的步骤打上补丁即可。

Video Mixer IP核添加后,双击该IP核进入配置页面,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_ide_06


31.3.5 Video Mixer IP核配置页面

这里介绍几个需要配置的选项:

“Number of Overlay Layers”:覆盖层,用来叠加混合的视频层,这里设置为3;

“Maximum Number of Columns”:最大显示的列数,由于我们支持的屏幕的分辨率,列数目最大1280,所以这里设置为“1280”。

“Maximum Number of Rows”:最大显示行数,这里设置为“800”。

“Enable Global Alpha”:表格中这个选项用来设置Alpha值,即透明度,这里Layer1~Layer3全部使能。

“Enable Scaling”:表示使能缩放,这里全部勾选。

“Interface Type”:表格中这个选项用来设置某一图层视频的接口类型,由于Layer 1层视频源为摄像头2输出的Stream流,所以接口类型要设置为“Stream”。Layer 2和Layer 3视频源是从DDR3输出的,所以接口类型保持默认的“Memory”就行。

“Video Format”设置视频数据的格式,这里我们将Layer2和Layer3层的视频数据格式设置为“RGB8”,设置完成后如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_寄存器_07


然后我们将“Zynq UltraScale+ MPSoC”IP 核emio位宽设置为“4”。

接下来点击“Run Connection Automation”进行自动连线。完成后,发现还需要对“ov5640_capture_data_1”、“v_vid_in_axi4s_1”、axi_vdma_1axi_vdma_0”、 “v_mix_0”、 “v_axis_vid_out_0核进行手动连线。连线完成后的整体框图如下所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_IP_08


31.3.6整体框图

然后保存并运行“Generate Output Product”。

添加引脚约束文件。由于lcd引脚约束和前面的实验相同,这里只列出双目摄像头的引脚约束:

#----------------------摄像头接口的时钟---------------------------

#72M​
create_clock -period 13.888 -name cam_pclk [get_ports cam_pclk]​
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets cam_pclk_IBUF]​

create_clock -period 13.888 -name cam_pclk_2 [get_ports cam_pclk_2]​
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets cam_pclk_2_IBUF]​

set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS33} [get_ports cam_pclk]​
set_property -dict {PACKAGE_PIN F13 IOSTANDARD LVCMOS33} [get_ports cam_rst_n]​
set_property -dict {PACKAGE_PIN B15 IOSTANDARD LVCMOS33} [get_ports cam_pwdn]​
set_property -dict {PACKAGE_PIN E15 IOSTANDARD LVCMOS33} [get_ports {cam_data[0]}]​
set_property -dict {PACKAGE_PIN D15 IOSTANDARD LVCMOS33} [get_ports {cam_data[1]}]​
set_property -dict {PACKAGE_PIN E14 IOSTANDARD LVCMOS33} [get_ports {cam_data[2]}]​
set_property -dict {PACKAGE_PIN D14 IOSTANDARD LVCMOS33} [get_ports {cam_data[3]}]​
set_property -dict {PACKAGE_PIN E13 IOSTANDARD LVCMOS33} [get_ports {cam_data[4]}]​
set_property -dict {PACKAGE_PIN B13 IOSTANDARD LVCMOS33} [get_ports {cam_data[5]}]​
set_property -dict {PACKAGE_PIN C14 IOSTANDARD LVCMOS33} [get_ports {cam_data[6]}]​
set_property -dict {PACKAGE_PIN A13 IOSTANDARD LVCMOS33} [get_ports {cam_data[7]}]​
set_property -dict {PACKAGE_PIN G14 IOSTANDARD LVCMOS33} [get_ports cam_vsync]​
set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports cam_href]​
set_property -dict {PACKAGE_PIN H13 IOSTANDARD LVCMOS33} [get_ports {emio_sccb_tri_io[0]}]​
set_property -dict {PACKAGE_PIN F15 IOSTANDARD LVCMOS33} [get_ports {emio_sccb_tri_io[1]}]​
set_property PULLUP true [get_ports {emio_sccb_tri_io[0]}]​
set_property PULLUP true [get_ports {emio_sccb_tri_io[1]}]​

set_property -dict {PACKAGE_PIN D11 IOSTANDARD LVCMOS33} [get_ports cam_pclk_2]​
set_property -dict {PACKAGE_PIN A11 IOSTANDARD LVCMOS33} [get_ports cam_rst_n_2]​
set_property -dict {PACKAGE_PIN B14 IOSTANDARD LVCMOS33} [get_ports cam_pwdn_2]​
set_property -dict {PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports {cam_data_2[0]}]​
set_property -dict {PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports {cam_data_2[1]}]​
set_property -dict {PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports {cam_data_2[2]}]​
set_property -dict {PACKAGE_PIN B10 IOSTANDARD LVCMOS33 } [get_ports {cam_data_2[3]}]​
set_property -dict {PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports {cam_data_2[4]}]​
set_property -dict {PACKAGE_PIN E10 IOSTANDARD LVCMOS33 } [get_ports {cam_data_2[5]}]​
set_property -dict {PACKAGE_PIN E12 IOSTANDARD LVCMOS33 } [get_ports {cam_data_2[6]}]​
set_property -dict {PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports {cam_data_2[7]}]​
set_property -dict {PACKAGE_PIN A15 IOSTANDARD LVCMOS33} [get_ports cam_vsync_2]​
set_property -dict {PACKAGE_PIN A12 IOSTANDARD LVCMOS33} [get_ports cam_href_2]​
set_property -dict {PACKAGE_PIN A14 IOSTANDARD LVCMOS33} [get_ports {emio_sccb_tri_io[2]}]​
set_property -dict {PACKAGE_PIN D12 IOSTANDARD LVCMOS33} [get_ports {emio_sccb_tri_io[3]}]​
set_property PULLUP true [get_ports {emio_sccb_tri_io[2]}]​
set_property PULLUP true [get_ports {emio_sccb_tri_io[3]}]

接下来生成bitstream,新建vitis文件夹,并导出xsa文件到vitis文件夹中。

到这里,硬件设计就完成了。

软件设计

打开vitis软件后,将路径指定到上一小节创建的vitis文件夹,然后按照《第一章Hello World实验》创建应用工程。创建完成后,添加如下图所示的文件,读者可以直接从例程中复制这些文件到自己的工程中。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_寄存器_09


31.4.1添加工程文件

下面我们来分析一下这些文件。首先看一下main.c文件,如下所示:

……


17 //宏定义​
18 #define CLK_WIZ_ID XPAR_CLK_WIZ_0_DEVICE_ID //时钟IP核器件ID​
19 #define DISP_VTC_ID XPAR_VTC_0_DEVICE_ID //VTC器件ID​
20 #define AXI_GPIO_0_ID XPAR_AXI_GPIO_0_DEVICE_ID //PL端 AXI GPIO 0(lcd_id)器件ID​
21 #define AXI_GPIO_0_CHANEL 1 //使用AXI GPIO(lcd_id)通道1​
22 ​
23 unsigned int vdma_id[DISPLAY_VDMA_NUM] = {XPAR_AXIVDMA_0_DEVICE_ID,​
24 XPAR_AXIVDMA_1_DEVICE_ID};​
25 ​
26 XAxiVdma vdma[DISPLAY_VDMA_NUM];​
27 ​
28 //全局变量​
29 DisplayCtrl dispCtrl;​
30 XGpio axi_gpio_inst; //PL端 AXI GPIO 驱动实例​
31 VideoMode vd_mode;​
32 ​
33 unsigned int frame_buffer_addr[DISPLAY_VDMA_NUM]; //frame buffer的起始地址​
34 unsigned int lcd_id=0; //LCD ID​
35 ​
36 XV_Mix_l2 mix;​
37 XVidC_VideoStream VidStream;​
38 ​
39 extern const unsigned char gImage_ov5640_1[88560];​
40 extern const unsigned char gImage_ov5640_2[88560];​
41 extern const unsigned char gImage_ov5640_1_4342[27000];​
42 extern const unsigned char gImage_ov5640_2_4342[27000];​
43 ​
44 int main(void)​
45 {​
46 u8 *ov56401_point;​
47 u8 *ov56402_point;​
48 u32 status0,status1;​
49 u16 cmos_h_pixel; //ov5640 DVP 输出水平像素点数​
50 u16 cmos_v_pixel; //ov5640 DVP 输出垂直像素点数​
51 u16 total_h_pixel; //ov5640 水平总像素大小​
52 u16 total_v_pixel; //ov5640 垂直总像素大小​
54 ​
55 XGpio_Initialize(&axi_gpio_inst,AXI_GPIO_0_ID); //GPIO初始化​
56 XGpio_SetDataDirection(&axi_gpio_inst,AXI_GPIO_0_CHANEL,0x07); //设置AXI GPIO为输入​
57 lcd_id = LTDC_PanelID_Read(&axi_gpio_inst,AXI_GPIO_0_CHANEL); //获取LCD的ID​
58 XGpio_SetDataDirection(&axi_gpio_inst,AXI_GPIO_0_CHANEL,0x00); //设置AXI GPIO为输出​
59 xil_printf("LCD ID: %x\r\n",lcd_id);​
60 ​

……​

102 status0 = ov5640_init(CMOS_CH0,cmos_h_pixel,//初始化ov5640 0​
103 cmos_v_pixel,​
104 total_h_pixel,​
105 total_v_pixel);​
106 status1 = ov5640_init(CMOS_CH1,cmos_h_pixel,//初始化ov5640 1​
107 cmos_v_pixel,​
108 total_h_pixel,​
109 total_v_pixel);​
110 if(status0 == 0 && status1 == 0)​
111 xil_printf("Dual OV5640 detected successful!\r\n");​
112 else​
113 xil_printf("Dual OV5640 detected failed!\r\n");​
114 ​
115 //根据获取的LCD的ID号来进行video参数的选择​
116 switch(lcd_id){​
117 case 0x4342 : vd_mode = VMODE_480x272; break; //4.3寸屏,480*272分辨率​
118 case 0x4384 : vd_mode = VMODE_800x480; break; //4.3寸屏,800*480分辨率​
119 case 0x7084 : vd_mode = VMODE_800x480; break; //7寸屏,800*480分辨率​
120 case 0x7016 : vd_mode = VMODE_1024x600; break; //7寸屏,1024*600分辨率​
121 case 0x1018 : vd_mode = VMODE_1280x800; break; //10.1寸屏,1280*800分辨率​
122 default : vd_mode = VMODE_800x480; break;​
123 }​
124 ​
125 xil_printf("vd_mode.width is %d\r\n",vd_mode.width);​
126 xil_printf("vd_mode.height is %d\r\n",vd_mode.height);​
127 ​
128 //配置VDMA​
129 for(u8 i=0;i<DISPLAY_VDMA_NUM;i++){​
130 frame_buffer_addr[i] = XPAR_PSU_DDR_0_S_AXI_BASEADDR+0x1000000*i+0x05000000;​
131 //配置VDMA​
132 run_vdma_frame_buffer(&vdma[i], vdma_id[i], vd_mode.width, vd_mode.height,​
133 frame_buffer_addr[i],0,0,BOTH);​
134 }​
135 ​
136 xil_printf("VDMA Config succesfull\r\n");​
137 ​
138 //设置clk_wiz时钟IP核输出的时钟频率​
139 clk_wiz_cfg(CLK_WIZ_ID,vd_mode.freq);​
140 ​
141 //初始化Display controller​
142 DisplayInitialize(&dispCtrl, DISP_VTC_ID);​
143 //设置VideoMode​
144 DisplaySetMode(&dispCtrl, &vd_mode);​
145 DisplayStart(&dispCtrl);​
146 ​
147 XV_mix xv_mix;​
148 XV_mix_Config *xv_config;​
149 ​
150 xv_config = XV_mix_LookupConfig(XPAR_XV_MIX_0_DEVICE_ID);​
151 XV_mix_CfgInitialize(&xv_mix,xv_config,xv_config->BaseAddress);​
152 ​
153 XV_mix_Set_HwReg_layerEnable(&xv_mix,(u32)0x0f);​
154 XV_mix_Set_HwReg_width(&xv_mix, vd_mode.width);​
155 XV_mix_Set_HwReg_height(&xv_mix, vd_mode.height);​
156 ​
157 XV_mix_Set_HwReg_layerAlpha_1(&xv_mix, 255);​
158 XV_mix_Set_HwReg_layerStartX_1(&xv_mix,((vd_mode.width)/2));​
159 XV_mix_Set_HwReg_layerStartY_1(&xv_mix,(u32)0);​
160 XV_mix_Set_HwReg_layerWidth_1(&xv_mix,((vd_mode.width)/2));​
161 XV_mix_Set_HwReg_layerHeight_1(&xv_mix,vd_mode.height);​
162 ​
163 if(lcd_id == 0x4342){​
164 ov56401_point =gImage_ov5640_1_4342;​
165 ov56402_point =gImage_ov5640_2_4342;​
166 ​
167 XV_mix_Set_HwReg_layerAlpha_2(&xv_mix, 125);​
168 XV_mix_Set_HwReg_layerStartX_2(&xv_mix,(u32)((vd_mode.width)/2 + 20));​
169 XV_mix_Set_HwReg_layerStartY_2(&xv_mix,(u32)20);​
170 XV_mix_Set_HwReg_layerWidth_2(&xv_mix,(u32)200);​
171 XV_mix_Set_HwReg_layerHeight_2(&xv_mix,(u32)45);​
172 XV_mix_Set_HwReg_layerStride_2(&xv_mix, 200*3);​
173 XV_mix_Set_HwReg_layer2_buf1_V(&xv_mix, ov56401_point);​
174 ​
175 XV_mix_Set_HwReg_layerAlpha_3(&xv_mix, 125);​
176 XV_mix_Set_HwReg_layerStartX_3(&xv_mix,(u32)20);​
177 XV_mix_Set_HwReg_layerStartY_3(&xv_mix,(u32)20);​
178 XV_mix_Set_HwReg_layerWidth_3(&xv_mix,(u32)200);​
179 XV_mix_Set_HwReg_layerHeight_3(&xv_mix,(u32)45);​
180 XV_mix_Set_HwReg_layerStride_3(&xv_mix, 200*3);​
181 XV_mix_Set_HwReg_layer3_buf1_V(&xv_mix, ov56402_point);​
182 }​
183 else{​
184 ov56401_point =gImage_ov5640_1;​
185 ov56402_point =gImage_ov5640_2;​
186 ​
187 XV_mix_Set_HwReg_layerAlpha_2(&xv_mix, 125);​
188 XV_mix_Set_HwReg_layerStartX_2(&xv_mix,(u32)((vd_mode.width)/2 + 50));​
189 XV_mix_Set_HwReg_layerStartY_2(&xv_mix,(u32)50);​
190 XV_mix_Set_HwReg_layerWidth_2(&xv_mix,(u32)328);​
191 XV_mix_Set_HwReg_layerHeight_2(&xv_mix,(u32)90);​
192 XV_mix_Set_HwReg_layerStride_2(&xv_mix, 328*3);​
193 XV_mix_Set_HwReg_layer2_buf1_V(&xv_mix, ov56401_point);​
194 ​
195 XV_mix_Set_HwReg_layerAlpha_3(&xv_mix, 125);​
196 XV_mix_Set_HwReg_layerStartX_3(&xv_mix,(u32)50);​
197 XV_mix_Set_HwReg_layerStartY_3(&xv_mix,(u32)50);​
198 XV_mix_Set_HwReg_layerWidth_3(&xv_mix,(u32)328);​
199 XV_mix_Set_HwReg_layerHeight_3(&xv_mix,(u32)90);​
200 XV_mix_Set_HwReg_layerStride_3(&xv_mix, 328*3);​
201 XV_mix_Set_HwReg_layer3_buf1_V(&xv_mix, ov56402_point);​
202 }​
203 ​
204 XV_mix_EnableAutoRestart(&xv_mix);​
205 XV_mix_Start(&xv_mix);​
206 ​
207 return 0;​
208 }

第39到第42行,定义了四个字符型数组,其中gImage_ov5640_1gImage_ov5640_2两个数组用来存储标记层图像所对应的字符,标记层图像如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_寄存器_10


31.4.2标记层图像

上面的图像是笔者先在PPT中分别输入两行“OV5640 1”和“OV5640 2”文字,然后使用截图工具(QQ截图)截取328*250像素大小的图片,保存在windows自带的画图工具中,然后使用画图工具自带的裁剪功能,分别将“OV5640 1”、“OV5640 2”裁剪出来,两个图片裁剪的大小都是328*90像素,然后分别另存为名为“ov5640_1.bmp”、“ov5640_2.bmp”的图片。注意,图片格式必须为bmp格式的,否则将不能调节透明度。

接下来,我们使用正点原子提供的“资料盘/软件/ Image2Lcd”路径下的“Ima2Lcd.exe”工具,将前面生成的两个图片转换成C语言数组,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_寄存器_11


31.4.3 Ima2Lcd工具

打开软件如下图所示,点击下图中序号1处,将前面生成“ov5640_1.bmp”导入进来,序号2处显示图片的大小,接下来在序号3处设置将图片输出到c语言数组后的宽度和高度,这里设置为328*90像素,然后点击序号4处的“保存”按钮,点击后弹出一个窗口,我们在里面将数组命名为“ov5640_1.c”,生成的文件如31.4.5所示,注意数组名为“gImage_ ov5640_1”。同样的方法生成“gImage_ ov5640_2”数组。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_IP_12


31.4.4将图像导出到数组

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_寄存器_13


31.4.5 ov5640_1数组文件

第102行到第109行,调用ov5640_init()函数初始化双目OV5640摄像头,ov5640_init()函数通过调用sccb_write_reg16()函数实现IIC协议,从而配置OV5640摄像头寄存器。sccb_write_reg16()函数调用Xilinx的XGpioPs_WritePin()函数对EMIO进行读写,从而实现IIC接口时序。

第129行到第134行对vdma进行配置,注意第130行frame_buffer_addr的地址加0x05000000,是为了避免frame_buffer_addr地址和程序中变量存储地址冲突。

第150和第151行,根据video mixer器件id查找配置信息并对video mixe初始化。

第153行,调用XV_mix_Set_HwReg_layerEnable()函数设置Layer enable寄存器,参数“0x0f表示”将Master layer、Overlay Layer1、Overlay Layer2、Overlay Layer3四个图层的使能开关打开。第154行和第155行用来设置背景层的有效宽度和有效高度。

第157行到第161行用来设置Overlay Layer1图层的相关参数,也就是显示摄像头1拍摄的画面。其中XV_mix_Set_HwReg_layerStartX_1()和XV_mix_Set_HwReg_layerStartY_1()两个函数用来设置图层在屏幕上的X轴和Y轴起点,其中X轴参数为“(vd_mode.width)/2”表示X轴方向从屏幕中间开始,Y轴参数“0”表示Y轴方向起点0处开始,从上往下显示。XV_mix_Set_HwReg_layerAlpha_1()函数用来设置透明度的值,“255”表示完全不透明,“0”表示完全透明。

第163行到第202行用来设置Layer2层和Layer3层,由于分辨率为480*272的4.3寸屏幕太小,用在其它分辨率屏幕上的标记层图像不能用在分辨率为480*272的屏幕上,所以第163行根据480*272屏幕id单独设置显示在该屏幕上的标记层图像。不同分辨率屏幕上Layer2和Layer3图层的配置方法都是一样的,这里我们以480*272分辨率屏幕为例讲解。

前面讲解使用Ima2Lcd工具将两个328*90像素大小的图片生成两个字符数组,而第164行和第165行gImage_ov5640_1_4342gImage_ov5640_2_4342两个数组是使用200*45像素大小的图片生成的,方法同前面讲解的一样。第167行将Layer2图层的透明度设置为125,第168行和第169行设置Layer2层的起点,即水平方向在屏幕的中间位置再右移20个像素,垂直方向从屏幕显示区域最上方往下移20个像素。第170行和第171行设置Layer图层的大小,即200*45个像素。第172行XV_mix_Set_HwReg_layerStride_2函数用来设置一行像素数据的总个数,由于Layer2层一行有200个像素,每个像素3个字节数据,所以总共有200*3个字节数据。173行调用XV_mix_Set_HwReg_layer2_buf1_V()函数将显示图像数据的数组写入Layer2图层的帧buffer中。第175行到第181行用来配置Layer3图层,方法和配置Layer2图层一样,不同在于Layer3图层的起始位置不同,Layer3图层在水平方向上,从左到右从第20个像素开始,在垂直方向上,从上到下从第20个像素开始。

第204行和第205行的XV_mix_EnableAutoRestart()函数和XV_mix_Start()函数用来配置Video Mixer IP核的“Control”寄存器,从而让Video Mixer IP核开始传输视频。

下载验证

首先我将下载器与开发板上的JTAG接口连接,下载器另外一端与电脑连接然后使用USB连接线将USB UART接口(PS_PORT)与电脑连接,用于口通信。接下来使用FPC排线一端与RGB LCD液晶屏上的接口连接,另一端连接开发板上的RGB LCD接口。

接下来将双目OV5640摄像头模块插在MPSOC开发板的J19扩展口,注意在连接时,摄像头镜头方向朝外,如下图所示,然后开发板上的启动模式设置为JTAG模式,最后连接开发板的电源。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_寄存器_14


31.5.1开发板连接摄像头

打开vitis软件,连接串口并下载程序。程序下载完成后,可以看到LCD屏幕显示如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第三十一章 双目OV5640摄像头LCD显示实验​_IP_15


31.5.2实验结果


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月12日 0

暂无评论

推荐阅读
  Vn37uiKQIsdv   2023年12月06日   13   0   0 网络层链路IP
  tprTMCWDkFAR   2023年12月06日   23   0   0 用户名APIIP
95kVyaJuybju
最新推荐 更多