1)实验平台:正点原子领航者ZYNQ开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/FPGA/zdyz_linhanz.html
4)对正点原子FPGA感兴趣的同学可以加群讨论:876744900
5)关注正点原子公众号,获取最新资料
第九章基于OV5640的字符叠加实验
在基于OV5640的视频图像叠加实验中,我们成功的在液晶屏上显示了摄像头采集图像和彩条数据图像叠加后的图像。本章节我们将在此实验的基础上生成一个字符叠加的IP核,来进行基于OV5640的字符叠加实验。
本章包括以下几个部分:99.1简介9.2实验任务9.3HLS设计9.4IP验证9.5下载验证9.1简介视频字符叠加,是指在显示屏幕的指定区域以一定的透明度显示指定的图像符号或字符。字符叠加在多媒体、监控系统、电视等领域有着广泛需求。以视频监控为例,监控端需要接收外部数据并实时的显示在监控屏幕上,如时间、记号、地点等信息。许多工业应用的人机界面和视频播放场合也需要叠加各种图文信息,视频字符叠加的应用可以显著提高操控终端的操控性能和人机功效。字符(包括汉字、字母和符号等)的本质都是点阵,在屏幕上体现为字符显示区域内像素点的集合。我们想要实现视频字符叠加的功能,就需要在显示模块中指定字符显示区域各个像素点颜色值。字符的大小决定了字符显示区域内像素点的数目,而字符的样式(字体、颜色等)则决定了各像素点的颜色值。因此,在显示字符之前,我们需要先指定字符的大小、样式,然后获取该字符的点阵,这个过程我们称之为“提取字模”,或简称“取模”。我们一般使用0和1的组合来描述字符的点阵排列:点阵中每个像素点用一位(1 bit)数据来表示,其中用于表征字符的像素点用数字1来表示,其他的像素点作为背景用数字0来表示,如图所示:
图 9.1.1 汉字“正”及其点阵描述
图中用于表征字符的像素点用数字1来表示,其他的像素点作为背景用数字0来表示。采用这种方式描述的字符是不含有颜色特征的,只能区分点阵中的字符和背景。字模的提取可以使用取模软件“PCtoLCD2002”来获取汉字“正点原子”的字模。首先在开发板所随附的资料盘(A盘)中“6_软件资料/1_软件/PCtoLCD2002 完美版”目录下找到“PCtoLCD2002” 并双击打开,如下图所示:
图 9.1.2 取模软件PCtoLCD2002
打开之后会发现软件中的字体、字宽和字高都是无法设置的,这个时候点击菜单栏的“模式”,选择“字符模式”,如下图所示。
图 9.1.3 切换到字符模式
切换到字符模式后,就可以设置字体、字宽和字高了。字宽和字高的值越高,显示在 LCD 屏上的字符就越大,但是代码也需要做相应的修改。这里将字体选择默认的“宋体”,字宽和字高设置成“32”,然后在下方文本框中输入汉字“正点原子”,如下图所示:
图 9.1.4 字符设置
由于PCtoLCD2002会给每个字符生成一个独立的字模,如果此时点击文本框右侧的“生成字模”按钮,我们将会得到四个 32*32 的字模。然而为了方便在 LCD 上显示,我们将四个汉字看作一个整体,从而获得一个字宽为 128, 字高为 32 的“大字模”。为了达到这个目的,我们首先将图中四个汉字的点阵保存为.BMP 格式的图片。在菜单栏中点击“文件”并选择“另存为”,在保存界面中指定文件存储路径,并选择保存类型为“BMP 图像文件”,然后输入文件名“正点原子_bmp”,最后点击“保存”。本次我们在工程路径下新建一个“doc”文件夹,将生成的 BMP 图片保存在 doc 文件夹下。如下图所示。
图 9.1.5 点击“文件”并另存为图像
图 9.1.6 BMP格式图片保存界面
我们在“画图”中打开刚刚保存的 BMP 格式的图片如下所示:
图 9.1.7 保存的BMP格式图片
接下来我们将取模软件 PCtoLCD2002 切换至图形模式, 在菜单栏中点击“模式”,选择“图形模式”。
图 9.1.8 切换至图形模式
然后在菜单栏中点击“文件”并选择“打开”, 指定图1.3.9中存放BMP格式图片的路径并打开图片“正点原子_bmp”, 图片打开后如下所示。
图 9.1.9 PCtoLCD2002 图形模式
在上图中,四个汉字“正点原子”被看作一个整体,而不再是四个独立的字符。实际上,这四个汉字也确实是作为一个整体以BMP图片的形式导入到取模软件中的。 在生成字模之前,我们需要先设置字模的格式。在菜单栏中点击“选项”,并在弹出的配置界面中按照下图进行配置,配置完成后点击确定。
图 9.1.10 字符格式配置界面
在配置界面中,当鼠标悬浮在各配置选项上时,软件会自动提示当前配置的含义。需要注意的是图1.3.12左下角“每行显示数据”是以字节(Byte) 为单位的,而一个字节的数据为8个bit,即可以表示一行点阵中的8个像素点。由于图1.3.9中的点阵每行为128个像素点,所以需要16个Byte的数据来表示一行,因此将“每行显示数据—点阵”处设置为16。配置字模选项完成后,点击“生成字模”,即可得到汉字“正点原子”所对应的点阵数据,如下图所示:
图 9.1.11 生成字模
最后点击保存字模,可将生成的点阵数据保存在txt格式的文本文档中,如下图所示:
图 9.1.12 正点原子字模
如图所示,数据以十六进制显示,每行有16个Byte,对应每行四个汉字共128个像素点;共有32行,对应每个汉字的高度为32。字符叠加的效果如下图所示:
图 9.1.13 字符叠加
上图中左边的“lena”图是没有叠加字符的图像,右边的“lena_text”图是叠加完字符之后的图像。9.2实验任务本节的实验任务是使用Vivado HLS设计字符叠加的IP核,并在Vivado中对设计出来的IP核进行验证。9.3HLS设计我们在电脑中的“F:ZYNQHigh_Level_Synthesis”目录下新建一个名为text_overlay的文件夹,作为本次实验的工程目录。然后打开Vivado HLS工具,创建一个新的工程。设置工程名为“text_overlay”,选择工程路径为刚刚创建的文件夹。需要注意的是,工程名以及路径只能由英文字母、数字和下划线组成,不能包含中文、空格以及其他特殊字符。如下图所示:
图 9.3.1 工程配置界面
设置好工程名及路径之后,点击“Next”,进入如下界面设置顶层函数:
图 9.3.2 设置顶层函数
工程创建完成后,在工程面板中的“source”目录上点击右键,然后在打开的列表中选择“New File”新建源文件,在弹出的对话框中输入源文件的名称“text_overlay.cpp”,如图1.3.3所示。源文件默认的保存路径为HLS工程目录,为方便源文件的管理,我们在工程目录下新建一个名为“src”的文件下,将源文件保存在src目录下。
图 9.3.3 输入源文件名
我们在这里使用Vivado HLS提供的视频库“hls_video.h”,由于这个视频库是用C++语言编写的,那么后缀名需要设置为“.cpp”。设置好文件名和路径之后,点击“保存”。“text_overlay.cpp”文件源代码如下:
- 1 #include "text_overlay.h"
- 2 #include "text.h"
- 3
- 4 //字符数据叠加
- 5 void text_overlay(RGB_IMAGE& src, RGB_IMAGE& dst, int rows, int cols)
- 6 {
- 7 //定义输入和输出图像像素数据
- 8 RGB_PIXEL src_data;
- 9 RGB_PIXEL dst_data;
- 10
- 11 //字符叠加位置
- 12 int x_pos_edge = 128;
- 13 int y_pos_edge = 32;
- 14
- 15 //获取图像数据
- 16 for(int y_pos = 0; y_pos < rows; y_pos++){
- 17 for(int x_pos = 0; x_pos < cols; x_pos++){
- 18 if((y_pos < rows) && (x_pos < cols)){
- 19 src >> src_data;
- 20 }
- 21
- 22 //获取输入图像像素RGB通道数据
- 23 unsigned char src_B = src_data.val[0];
- 24 unsigned char src_G = src_data.val[1];
- 25 unsigned char src_R = src_data.val[2];
- 26
- 27 //定义输出图像像素RGB通道数据
- 28 unsigned char dst_B;
- 29 unsigned char dst_G;
- 30 unsigned char dst_R;
- 31
- 32 //字符数据叠加
- 33 if((x_pos < x_pos_edge) && (y_pos < y_pos_edge)){
- 34 dst_B = (1-((text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1))*src_B;
- 35 dst_G = (1-((text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1))*src_G;
- 36 dst_R = (1-((text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1))*src_R
- 37 + ((text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1)*0xFF;
- 38 }else{
- 39 dst_B = src_B;
- 40 dst_G = src_G;
- 41 dst_R = src_R;
- 42 }
- 43
- 44 //输出图像数据
- 45 dst_data.val[0] = dst_B;
- 46 dst_data.val[1] = dst_G;
- 47 dst_data.val[2] = dst_R;
- 48 dst << dst_data;
- 49 }
- 50 }
- 51 }
- 52
- 53 //顶层函数
- 54 void text_overlay_top(AXI_STREAM& input_axi,
- 55 AXI_STREAM& output_axi,
- 56 int rows,
- 57 int cols)
- 58 {
- 59 #pragma HLS INTERFACE ap_ctrl_none port=return
- 60 #pragma HLS INTERFACE s_axilite port=cols
- 61 #pragma HLS INTERFACE s_axilite port=rows
- 62 #pragma HLS INTERFACE axis register both port=output_axi
- 63 #pragma HLS INTERFACE axis register both port=input_axi
- 64
- 65 RGB_IMAGE img_0(rows,cols);
- 66 RGB_IMAGE img_1(rows,cols);
- 67
- 68 #pragma HLS dataflow
- 69
- 70 hls::AXIvideo2Mat(input_axi, img_0);
- 71 text_overlay(img_0, img_1, rows, cols);
- 72 hls::Mat2AXIvideo(img_1, output_axi);
- 73 }
本章实验的C++源代码与上一章节的基于OV5640的视频图像叠加实验基本相同。下面讲解一下不同之处:在代码的第一行引入了“text_overlay.h”,这是我们定义的头文件。这个头文件里面对Vivado HLS提供的部分数据类型做了重新定义。在代码的第33行“if((x_pos < x_pos_edge) && (y_pos < y_pos_edge))”,通过if条件判断语句判断像素点显示的位置,当像素点显示到字符数据的位置时,对像素点数据的RGB三个通道赋值。在代码的第34行到第37行“((text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1)*0xFF;”,“/”是取模运算符,“>>”是移位运算符,“%”是取余运算符,“&”是按位与。“x_pos/8”是为了确定像素点显示的位置对应着字模数据中的第几个字节,“x_pos%8”是为了确定像素点显示的位置对应着字模数据中每个字节中的第几个位。“>>”运算符是为了将提取到的字模数据移到最低位,“& 1”是为了判断当前像素点显示的位置是否为字模数据显示的位置。如果“(text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1)”得到的结果是0,表示对应像素点的数据不是字模数据,这个时候我们通过1减去我们得到的结果0再乘以原来图像RGB各个通道分量的值来直接显示原始图像;如果“(text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1)”得到的结果是1,表示对应像素点是字模数据,这个时候我们通过1减去我们得到的结果1再乘以RGB各个通道的值来将RGB各个通道赋值为0,并且将这个结果乘以0xff再赋值给输出图像的R通道,来显示红色的字符数据。
在代码的第二行引入了“text.h”,这个头文件里面包含了字库数据。“text.h”头文件代码如下:
- 1 #ifndef _TEXT_H_
- 2 #define _TEXT_H_
- 3
- 5 unsigned char text[32][16] = {
- 6 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- 7 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- 8 {0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00},
- 9 {0x00,0x00,0x00,0x08,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x02},
- 10 {0x00,0x00,0x00,0x1C,0x00,0x80,0x01,0x00,0xC0,0xFF,0xFF,0x1F,0xC0,0xFF,0xFF,0x07},
- 11 {0xF0,0xFF,0xFF,0x1F,0x00,0x80,0x01,0x00,0xC0,0x00,0x02,0x00,0x00,0x00,0x80,0x0F},
- 12 {0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x06,0xC0,0x00,0x06,0x00,0x00,0x00,0xC0,0x01},
- 13 {0x00,0x00,0x03,0x00,0x00,0x80,0xFF,0x0F,0xC0,0x00,0x02,0x00,0x00,0x00,0x60,0x00},
- 14 {0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x00,0xC0,0x00,0x01,0x02,0x00,0x00,0x30,0x00},
- 15 {0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x00,0xC0,0xF8,0xFF,0x07,0x00,0x00,0x0C,0x00},
- 16 {0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x00,0xC0,0x18,0x00,0x02,0x00,0x80,0x06,0x00},
- 17 {0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x00,0xC0,0x18,0x00,0x02,0x00,0x80,0x03,0x00},
- 18 {0x00,0x01,0x03,0x00,0x80,0x80,0x01,0x01,0xC0,0x18,0x00,0x02,0x00,0x80,0x03,0x00},
- 19 {0x00,0x07,0x03,0x00,0x80,0xFF,0xFF,0x03,0xC0,0xF8,0xFF,0x03,0x00,0x80,0x01,0x08},
- 20 {0x00,0x03,0x03,0x06,0x80,0x01,0x80,0x01,0xC0,0x18,0x00,0x02,0x00,0x80,0x01,0x1C},
- 21 {0x00,0x03,0xFF,0x0F,0x80,0x01,0x80,0x01,0xC0,0x18,0x00,0x02,0xFC,0xFF,0xFF,0x3F},
- 22 {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x01,0xC0,0x18,0x00,0x02,0x00,0x80,0x01,0x00},
- 23 {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x01,0xC0,0x18,0x00,0x02,0x00,0x80,0x01,0x00},
- 24 {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x01,0x40,0xF8,0xFF,0x03,0x00,0x80,0x01,0x00},
- 25 {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x01,0x40,0x18,0x0C,0x02,0x00,0x80,0x01,0x00},
- 26 {0x00,0x03,0x03,0x00,0x80,0xFF,0xFF,0x01,0x40,0x00,0x0C,0x00,0x00,0x80,0x01,0x00},
- 27 {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x01,0x40,0x00,0x0C,0x00,0x00,0x80,0x01,0x00},
- 28 {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x00,0x60,0x60,0x2C,0x00,0x00,0x80,0x01,0x00},
- 29 {0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x60,0xF0,0xCC,0x01,0x00,0x80,0x01,0x00},
- 30 {0x00,0x03,0x03,0x00,0x00,0x08,0x04,0x02,0x60,0x30,0x0C,0x07,0x00,0x80,0x01,0x00},
- 31 {0x00,0x03,0x03,0x00,0x40,0x10,0x0C,0x06,0x20,0x18,0x0C,0x1E,0x00,0x80,0x01,0x00},
- 32 {0x00,0x03,0x03,0x08,0x40,0x30,0x18,0x0C,0x30,0x04,0x0C,0x1C,0x00,0x80,0x01,0x00},
- 33 {0x00,0x03,0x03,0x1C,0x60,0x30,0x18,0x1C,0x10,0x03,0x0C,0x18,0x00,0x84,0x01,0x00},
- 34 {0xFC,0xFF,0xFF,0x3F,0x30,0x60,0x18,0x18,0x88,0xC1,0x0F,0x10,0x00,0xF8,0x01,0x00},
- 35 {0x00,0x00,0x00,0x00,0x38,0x20,0x10,0x18,0x08,0x00,0x07,0x00,0x00,0xE0,0x00,0x00},
- 36 {0x00,0x00,0x00,0x00,0x18,0x20,0x00,0x08,0x04,0x00,0x02,0x00,0x00,0x40,0x00,0x00},
- 37 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
- 38 };
- 39
- 40 #endif
在这个头文件中我们定义了一个32行16列的二维数组“text[32][16]”,这个二维数组中的数据就是我们在简介中使用取模软件得到的数据。其中数组一共有32行代表了每个汉字的高度是32;数组一共有16列,每列的数据是一个字节,代表了每行四个汉字共128个像素点。工程创建完成后,点击工具栏中向右的绿色三角形对C代码进行综合,如下图所示:
图 9.3.14 运行C综合
综合完成后,会自动打开综合结果(solution)的报告,如下图所示:
图 9.3.15 综合报告
在工具栏中点击黄色的“田”字按钮,导出RTL,如下图所示:
图 9.3.16 导出RTL
在弹出的对话框中保持默认设置,直接点击“OK”,如下图所示:
图 9.3.17 将设计导出成IP
设计导出完成后,HLS设计部分就结束了,我们在HLS工程目录下可以找到导出的IP核,如下图红色方框所示:
图 9.3.18导出得到的IP
HLS设计结束之后,我们将在Vivado中对导出的IP核进行验证。9.4IP验证在IP验证环节,我们会使用Vivado工具的IP集成器将生成的IP核添加到Block Design中,然后完成设计后将程序下载到领航者开发板上进行验证。用于IP验证的底层硬件可以在《领航者ZYNQ之HLS开发指南》第5章“OV5640 摄像头灰度显示”实验的基础上进行。打开该实验所对应的Vivado工程“ov5640_rgb2gray_ip_test”,将其另存为“text_overlay_ip_test”工程。为了方便工程管理,我们将Vivado工程的目录与HLS工程目录保持一致,如下图所示:
图 9.4.1 创建Vivado工程
在通过“另存为”的方式保存工程之后,还要将原来工程中的IP库(名为ip_repo的文件夹)复制到新的Vivado工程目录下, 然后将HLS设计过程中导出的IP核拷贝到“ip_repo”目录下并解压。在Vivado中重新将当前工程目录下的ip_repo文件夹添加到工程的IP库中,然后将HLS生成的IP核text_overlay添加到Block Design中,并将其STREAM接口分别连接到Video In to AXI4-Stream模块的video_out接口与VDMA模块的S_AXIS_S2MM接口上。最后点击上图中左上角的“Run Connection Automation”,让工具自动连接该IP核的其他端口,包括时钟、复位以及AXI-Lite从接口,最终完成的设计如下图所示:然后点击“Run Connnection Automation”,下面列出了会自动连接的模块及其接口,勾选“All Automation”, 然后点击“OK”按钮。最终完成的设计如下图所示:
图 9.4.2 完成后的Block Design
到这里我们的Block Design就设计完成了,在Diagram窗口空白处右击,然后选择“Validate Design”验证设计。验证完成后弹出对话框提示“Validation Successful”表明设计无误,点击“OK”确认。最后按快捷键“Ctrl + S”保存设计。接下来在Source窗口中右键点击Block Design设计文件“system.bd”,然后依次执行“Generate Output Products”和“Create HDL Wrapper”。最后在左侧Flow Navigator导航栏中找到PROGRAM AND DEBUG,点击该选项中的“Generate Bitstream”,对设计进行综合、实现、并生成Bitstream文件。在生成 Bitstream 之后,在菜单栏中选择 File > Export > Export hardware 导出硬件,并在弹出的对话框 中,勾选“Include bitstream”。然后在菜单栏选择 File > Launch SDK,启动 SDK 软件。在Vivado SDK中新建空的应用工程,工程名为“ov5640_text_overlay”。然后找到《领航者ZYNQ之嵌入式开发指南》第二十三章“OV5640 摄像头 LCD 显示”实验的Vivado工程目录,将“21_ov7725_lcdov7725_lcd.sdkov7725_lcd”目录下的src文件夹拷贝到新建的应用工程目录下。在SDK中刷新src目录,然后将“main.c”的代码修改为如下所示:
- 1 #include
- 2 #include
- 3 #include
- 4 #include "xil_types.h"
- 5 #include "xil_cache.h"
- 6 #include "xparameters.h"
- 7 #include "xgpio.h"
- 8 #include "xaxivdma.h"
- 9 #include "xaxivdma_i.h"
- 10 #include "display_ctrl/display_ctrl.h"
- 11 #include "vdma_api/vdma_api.h"
- 12 #include "emio_sccb_cfg/emio_sccb_cfg.h"
- 13 #include "ov5640/ov5640_init.h"
- 14 #include "xtext_overlay_top.h"
- 15
- 16 //宏定义
- 17 #define BYTES_PIXEL 3 //像素字节数,RGB888占3个字节
- 18 #define FRAME_BUFFER_NUM 3 //帧缓存个数3
- 19 #define DYNCLK_BASEADDR XPAR_AXI_DYNCLK_0_BASEADDR //动态时钟基地址
- 20 #define VDMA_ID XPAR_AXIVDMA_0_DEVICE_ID //VDMA器件ID
- 21 #define DISP_VTC_ID XPAR_VTC_0_DEVICE_ID //VTC器件ID
- 22 //PL端 AXI GPIO 0(lcd_id)器件 ID
- 23 #define AXI_GPIO_0_ID XPAR_AXI_GPIO_0_DEVICE_ID
- 24 //使用AXI GPIO(lcd_id)通道1
- 25 #define AXI_GPIO_0_CHANEL 1
- 26
- 27 //全局变量
- 28 //frame buffer的起始地址
- 29 unsigned int const frame_buffer_addr = (XPAR_PS7_DDR_0_S_AXI_BASEADDR
- 30 + 0x1000000);
- 31 XAxiVdma vdma;
- 32 DisplayCtrl dispCtrl;
- 33 XGpio axi_gpio_inst; //PL端 AXI GPIO 驱动实例
- 34 XText_overlay_top text_overlay_inst; //PL端text_overlay驱动实例
- 35 VideoMode vd_mode;
- 36 unsigned int lcd_id;
- 37
- 38 int main(void)
- 39 {
- 40 u32 status;
- 41 u16 cmos_h_pixel; //ov5640 DVP 输出水平像素点数
- 42 u16 cmos_v_pixel; //ov5640 DVP 输出垂直像素点数
- 43 u16 total_h_pixel; //ov5640 水平总像素大小
- 44 u16 total_v_pixel; //ov5640 垂直总像素大小
- 45
- 46 //获取LCD的ID
- 47 XGpio_Initialize(&axi_gpio_inst, AXI_GPIO_0_ID);
- 48 lcd_id = LTDC_PanelID_Read(&axi_gpio_inst,AXI_GPIO_0_CHANEL);
- 49 xil_printf("lcd_id = %xnr",lcd_id);
- 50
- 51 //根据获取的LCD的ID号来进行ov5640显示分辨率参数的选择
- 52 switch(lcd_id){
- 53 case 0x4342 : //4.3寸屏,480*272分辨率
- 54 cmos_h_pixel = 480;
- 55 cmos_v_pixel = 272;
- 56 total_h_pixel = 1800;
- 57 total_v_pixel = 1000;
- 58 break;
- 59 case 0x4384 : //4.3寸屏,800*480分辨率
- 60 cmos_h_pixel = 800;
- 61 cmos_v_pixel = 480;
- 62 total_h_pixel = 1800;
- 63 total_v_pixel = 1000;
- 64 break;
- 65 case 0x7084 : //7寸屏,800*480分辨率
- 66 cmos_h_pixel = 800;
- 67 cmos_v_pixel = 480;
- 68 total_h_pixel = 1800;
- 69 total_v_pixel = 1000;
- 70 break;
- 71 case 0x7016 : //7寸屏,1024*600分辨率
- 72 cmos_h_pixel = 1024;
- 73 cmos_v_pixel = 600;
- 74 total_h_pixel = 2200;
- 75 total_v_pixel = 1000;
- 76 break;
- 77 case 0x1018 : //10.1寸屏,1280*800分辨率
- 78 cmos_h_pixel = 1280;
- 79 cmos_v_pixel = 800;
- 80 total_h_pixel = 2570;
- 81 total_v_pixel = 980;
- 82 break;
- 83 default :
- 84 cmos_h_pixel = 480;
- 85 cmos_v_pixel = 272;
- 86 total_h_pixel = 1800;
- 87 total_v_pixel = 1000;
- 88 break;
- 89 }
- 90
- 91 emio_init(); //初始化EMIO
- 92 status = ov5640_init( cmos_h_pixel, //初始化ov5640
- 93 cmos_v_pixel,
- 94 total_h_pixel,
- 95 total_v_pixel);
- 96 if(status == 0)
- 97 xil_printf("OV5640 detected successful!rn");
- 98 else
- 99 xil_printf("OV5640 detected failed!rn");
- 100
- 101 //根据获取的LCD的ID号来进行video参数的选择
- 102 switch(lcd_id){
- 103 case 0x4342 : vd_mode = VMODE_480x272; break; //4.3寸屏,480*272分辨率
- 104 case 0x4384 : vd_mode = VMODE_800x480; break; //4.3寸屏,800*480分辨率
- 105 case 0x7084 : vd_mode = VMODE_800x480; break; //7寸屏,800*480分辨率
- 106 case 0x7016 : vd_mode = VMODE_1024x600; break; //7寸屏,1024*600分辨率
- 107 case 0x1018 : vd_mode = VMODE_1280x800; break; //10.1寸屏,1280*800分辨率
- 108 default : vd_mode = VMODE_800x480; break;
- 109 }
- 110
- 111 //初始化字符叠加IP核text_overlay
- 112 XText_overlay_top_Initialize(&text_overlay_inst, XPAR_TEXT_OVERLAY_TOP_0_DEVICE_ID);
- 113 //配置字符叠加IP核text_overlay
- 114 XText_overlay_top_Set_rows(&text_overlay_inst, vd_mode.height);
- 115 //配置字符叠加IP核text_overlay
- 116 XText_overlay_top_Set_cols(&text_overlay_inst, vd_mode.width);
- 117
- 118 //配置VDMA
- 119 run_vdma_frame_buffer(&vdma, VDMA_ID, vd_mode.width, vd_mode.height,
- 120 frame_buffer_addr,0,0,BOTH);
- 121 //初始化Display controller
- 122 DisplayInitialize(&dispCtrl, DISP_VTC_ID, DYNCLK_BASEADDR);
- 123 //设置VideoMode
- 124 DisplaySetMode(&dispCtrl, &vd_mode);
- 125 DisplayStart(&dispCtrl);
- 126
- 127 return 0;
- 128 }
在代码的第14行引入了“xtext_overlay_top.h”头文件,这个头文件是Vivado HLS工具生成的,里面声明了字符数据叠加IP核的驱动函数。首先在代码的34行定义了字符数据叠加IP核的驱动实例text_overlay_inst,该变量会在后面对IP核进行配置时用到。然后在代码的第112行通过“XText_overlay_top_Initialize ()”函数来初始化Vivado HLS生成的字符数据叠加IP核;在代码的第116行通过传入“vd_mode.height”形参来设置字符数据叠加IP核的行数,在代码的第114行通过传入“vd_mode.width”形参来设置列数。这些数据类型和函数在“xtext_overlay_top.h”头文件中均有声明。9.5下载验证编译完工程之后我们就可以开始下载程序了。将 OV5640 摄像头模块插在领航者Zynq开发板的“OLED/CAMERA”插座上,并将LCD的排线接头插入开发板上的 LCD 接线座。将下载器一端连电脑,另一端与开发板上的 JTAG 端口连接,连接电源线并打开电源开关。在SDK软件下方的SDK Terminal窗口中点击右上角的加号设置并连接串口。然后下载本次实验硬件设计过程中所生成的BIT文件,来对PL进行配置。最后下载软件程序,下载完成后在LCD上就可以看到液晶屏上显示了摄像头采集图像和字符数据叠加后的图像,如下图所示:
图 9.5.1 字符叠加效果图
|