搜索
bottom↓
回复: 0

【正点原子FPGA连载】第九章基于OV5640的字符叠加实验--摘自【正点原子】领航者ZYNQ之HLS 开发指南

[复制链接]

出0入234汤圆

发表于 2020-9-27 10:31:00 | 显示全部楼层 |阅读模式
1)实验平台:正点原子领航者ZYNQ开发板
2)购买链接:https://item.taobao.com/item.htm?id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html
4) 正点原子官方B站:https://space.bilibili.com/394620890
5)对正点原子FPGA感兴趣的同学可以加群讨论:876744900 点击加入:
QQ群头像.png                                                                                                                   
6)关注正点原子公众号,获取最新资料

100846rel79a9p4uelap24.jpg

100846f1ce1fg14zbg0va4.png

第九章基于OV5640的字符叠加实验



在基于OV5640的视频图像叠加实验中,我们成功的在液晶屏上显示了摄像头采集图像和彩条数据图像叠加后的图像。本章节我们将在此实验的基础上生成一个字符叠加的IP核,来进行基于OV5640的字符叠加实验。
本章包括以下几个部分:
99.1简介
9.2实验任务
9.3HLS设计
9.4IP验证
9.5下载验证


9.1简介
视频字符叠加,是指在显示屏幕的指定区域以一定的透明度显示指定的图像符号或字符。字符叠加在多媒体、监控系统、电视等领域有着广泛需求。以视频监控为例,监控端需要接收外部数据并实时的显示在监控屏幕上,如时间、记号、地点等信息。许多工业应用的人机界面和视频播放场合也需要叠加各种图文信息,视频字符叠加的应用可以显著提高操控终端的操控性能和人机功效。
字符(包括汉字、字母和符号等)的本质都是点阵,在屏幕上体现为字符显示区域内像素点的集合。我们想要实现视频字符叠加的功能,就需要在显示模块中指定字符显示区域各个像素点颜色值。字符的大小决定了字符显示区域内像素点的数目,而字符的样式(字体、颜色等)则决定了各像素点的颜色值。因此,在显示字符之前,我们需要先指定字符的大小、样式,然后获取该字符的点阵,这个过程我们称之为“提取字模”,或简称“取模”。
我们一般使用0和1的组合来描述字符的点阵排列:点阵中每个像素点用一位(1 bit)数据来表示,其中用于表征字符的像素点用数字1来表示,其他的像素点作为背景用数字0来表示,如图所示:
阿莫论坛发帖领航者专用1619.png

图 9.1.1 汉字“正”及其点阵描述

图中用于表征字符的像素点用数字1来表示,其他的像素点作为背景用数字0来表示。采用这种方式描述的字符是不含有颜色特征的,只能区分点阵中的字符和背景。
字模的提取可以使用取模软件“PCtoLCD2002”来获取汉字“正点原子”的字模。首先在开发板所随附的资料盘(A盘)中“6_软件资料/1_软件/PCtoLCD2002 完美版”目录下找到“PCtoLCD2002” 并双击打开,如下图所示:
阿莫论坛发帖领航者专用1878.png

图 9.1.2 取模软件PCtoLCD2002

打开之后会发现软件中的字体、字宽和字高都是无法设置的,这个时候点击菜单栏的“模式”,选择“字符模式”,如下图所示。
阿莫论坛发帖领航者专用11005.png

图 9.1.3 切换到字符模式

切换到字符模式后,就可以设置字体、字宽和字高了。字宽和字高的值越高,显示在 LCD 屏上的字符就越大,但是代码也需要做相应的修改。这里将字体选择默认的“宋体”,字宽和字高设置成“32”,然后在下方文本框中输入汉字“正点原子”,如下图所示:
阿莫论坛发帖领航者专用11186.png

图 9.1.4 字符设置

由于PCtoLCD2002会给每个字符生成一个独立的字模,如果此时点击文本框右侧的“生成字模”按钮,我们将会得到四个 32*32 的字模。然而为了方便在 LCD 上显示,我们将四个汉字看作一个整体,从而获得一个字宽为 128, 字高为 32 的“大字模”。为了达到这个目的,我们首先将图中四个汉字的点阵保存为.BMP 格式的图片。在菜单栏中点击“文件”并选择“另存为”,在保存界面中指定文件存储路径,并选择保存类型为“BMP 图像文件”,然后输入文件名“正点原子_bmp”,最后点击“保存”。本次我们在工程路径下新建一个“doc”文件夹,将生成的 BMP 图片保存在 doc 文件夹下。如下图所示。
阿莫论坛发帖领航者专用11544.png

图 9.1.5 点击“文件”并另存为图像

阿莫论坛发帖领航者专用11610.png

图 9.1.6 BMP格式图片保存界面

我们在“画图”中打开刚刚保存的 BMP 格式的图片如下所示:
阿莫论坛发帖领航者专用11706.png

图 9.1.7 保存的BMP格式图片

接下来我们将取模软件 PCtoLCD2002 切换至图形模式, 在菜单栏中点击“模式”,选择“图形模式”。
阿莫论坛发帖领航者专用11824.png

图 9.1.8 切换至图形模式

然后在菜单栏中点击“文件”并选择“打开”, 指定图1.3.9中存放BMP格式图片的路径并打开图片“正点原子_bmp”, 图片打开后如下所示。
阿莫论坛发帖领航者专用11956.png

图 9.1.9 PCtoLCD2002 图形模式

在上图中,四个汉字“正点原子”被看作一个整体,而不再是四个独立的字符。实际上,这四个汉字也确实是作为一个整体以BMP图片的形式导入到取模软件中的。
    在生成字模之前,我们需要先设置字模的格式。在菜单栏中点击“选项”,并在弹出的配置界面中按照下图进行配置,配置完成后点击确定。
阿莫论坛发帖领航者专用12167.png

图 9.1.10 字符格式配置界面

在配置界面中,当鼠标悬浮在各配置选项上时,软件会自动提示当前配置的含义。需要注意的是图1.3.12左下角“每行显示数据”是以字节(Byte) 为单位的,而一个字节的数据为8个bit,即可以表示一行点阵中的8个像素点。由于图1.3.9中的点阵每行为128个像素点,所以需要16个Byte的数据来表示一行,因此将“每行显示数据—点阵”处设置为16。
配置字模选项完成后,点击“生成字模”,即可得到汉字“正点原子”所对应的点阵数据,如下图所示:
阿莫论坛发帖领航者专用12450.png

图 9.1.11 生成字模

最后点击保存字模,可将生成的点阵数据保存在txt格式的文本文档中,如下图所示:
阿莫论坛发帖领航者专用12549.png

图 9.1.12 正点原子字模

如图所示,数据以十六进制显示,每行有16个Byte,对应每行四个汉字共128个像素点;共有32行,对应每个汉字的高度为32。
字符叠加的效果如下图所示:
阿莫论坛发帖领航者专用12687.png

图 9.1.13 字符叠加

上图中左边的“lena”图是没有叠加字符的图像,右边的“lena_text”图是叠加完字符之后的图像。
9.2实验任务
本节的实验任务是使用Vivado HLS设计字符叠加的IP核,并在Vivado中对设计出来的IP核进行验证。
9.3HLS设计
我们在电脑中的“F:\ZYNQ\High_Level_Synthesis”目录下新建一个名为text_overlay的文件夹,作为本次实验的工程目录。然后打开Vivado HLS工具,创建一个新的工程。设置工程名为“text_overlay”,选择工程路径为刚刚创建的文件夹。需要注意的是,工程名以及路径只能由英文字母、数字和下划线组成,不能包含中文、空格以及其他特殊字符。如下图所示:
阿莫论坛发帖领航者专用13058.png

图 9.3.1 工程配置界面

设置好工程名及路径之后,点击“Next”,进入如下界面设置顶层函数:
阿莫论坛发帖领航者专用13153.png

图 9.3.2 设置顶层函数

工程创建完成后,在工程面板中的“source”目录上点击右键,然后在打开的列表中选择“New File”新建源文件,在弹出的对话框中输入源文件的名称“text_overlay.cpp”,如图1.3.3所示。源文件默认的保存路径为HLS工程目录,为方便源文件的管理,我们在工程目录下新建一个名为“src”的文件下,将源文件保存在src目录下。
阿莫论坛发帖领航者专用13384.png

图 9.3.3 输入源文件名

我们在这里使用Vivado HLS提供的视频库“hls_video.h”,由于这个视频库是用C++语言编写的,那么后缀名需要设置为“.cpp”。设置好文件名和路径之后,点击“保存”。
“text_overlay.cpp”文件源代码如下:
  1. 1  #include "text_overlay.h"
  2. 2  #include "text.h"
  3. 3  
  4. 4  //字符数据叠加
  5. 5  void text_overlay(RGB_IMAGE& src, RGB_IMAGE& dst, int rows, int cols)
  6. 6  {
  7. 7      //定义输入和输出图像像素数据
  8. 8      RGB_PIXEL src_data;
  9. 9      RGB_PIXEL dst_data;
  10. 10
  11. 11     //字符叠加位置
  12. 12     int x_pos_edge = 128;
  13. 13     int y_pos_edge = 32;
  14. 14
  15. 15     //获取图像数据
  16. 16     for(int y_pos = 0; y_pos < rows; y_pos++){
  17. 17         for(int x_pos = 0; x_pos < cols; x_pos++){
  18. 18             if((y_pos < rows) && (x_pos < cols)){
  19. 19                 src >> src_data;
  20. 20             }
  21. 21
  22. 22             //获取输入图像像素RGB通道数据
  23. 23             unsigned char src_B = src_data.val[0];
  24. 24             unsigned char src_G = src_data.val[1];
  25. 25             unsigned char src_R = src_data.val[2];
  26. 26
  27. 27             //定义输出图像像素RGB通道数据
  28. 28             unsigned char dst_B;
  29. 29             unsigned char dst_G;
  30. 30             unsigned char dst_R;
  31. 31
  32. 32             //字符数据叠加
  33. 33             if((x_pos < x_pos_edge) && (y_pos < y_pos_edge)){
  34. 34                 dst_B = (1-((text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1))*src_B;
  35. 35                 dst_G = (1-((text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1))*src_G;
  36. 36                 dst_R = (1-((text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1))*src_R
  37. 37                          + ((text_my[y_pos][x_pos/8] >> (x_pos%8)) & 1)*0xFF;
  38. 38             }else{
  39. 39                 dst_B = src_B;
  40. 40                 dst_G = src_G;
  41. 41                 dst_R = src_R;
  42. 42             }
  43. 43
  44. 44             //输出图像数据
  45. 45             dst_data.val[0] = dst_B;
  46. 46             dst_data.val[1] = dst_G;
  47. 47             dst_data.val[2] = dst_R;
  48. 48             dst << dst_data;
  49. 49         }
  50. 50     }
  51. 51 }
  52. 52
  53. 53 //顶层函数
  54. 54 void text_overlay_top(AXI_STREAM& input_axi,
  55. 55                       AXI_STREAM& output_axi,
  56. 56                       int rows,
  57. 57                       int cols)
  58. 58 {
  59. 59 #pragma HLS INTERFACE ap_ctrl_none port=return
  60. 60 #pragma HLS INTERFACE s_axilite port=cols
  61. 61 #pragma HLS INTERFACE s_axilite port=rows
  62. 62 #pragma HLS INTERFACE axis register both port=output_axi
  63. 63 #pragma HLS INTERFACE axis register both port=input_axi
  64. 64
  65. 65     RGB_IMAGE img_0(rows,cols);
  66. 66     RGB_IMAGE img_1(rows,cols);
  67. 67
  68. 68 #pragma HLS dataflow
  69. 69
  70. 70     hls::AXIvideo2Mat(input_axi, img_0);
  71. 71     text_overlay(img_0, img_1, rows, cols);
  72. 72     hls::Mat2AXIvideo(img_1, output_axi);
  73. 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. 1  #ifndef _TEXT_H_
  2. 2  #define _TEXT_H_
  3. 3  
  4. 5  unsigned char text[32][16] = {
  5. 6          {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
  6. 7          {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
  7. 8          {0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00},
  8. 9          {0x00,0x00,0x00,0x08,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x02},
  9. 10         {0x00,0x00,0x00,0x1C,0x00,0x80,0x01,0x00,0xC0,0xFF,0xFF,0x1F,0xC0,0xFF,0xFF,0x07},
  10. 11         {0xF0,0xFF,0xFF,0x1F,0x00,0x80,0x01,0x00,0xC0,0x00,0x02,0x00,0x00,0x00,0x80,0x0F},
  11. 12         {0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x06,0xC0,0x00,0x06,0x00,0x00,0x00,0xC0,0x01},
  12. 13         {0x00,0x00,0x03,0x00,0x00,0x80,0xFF,0x0F,0xC0,0x00,0x02,0x00,0x00,0x00,0x60,0x00},
  13. 14         {0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x00,0xC0,0x00,0x01,0x02,0x00,0x00,0x30,0x00},
  14. 15         {0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x00,0xC0,0xF8,0xFF,0x07,0x00,0x00,0x0C,0x00},
  15. 16         {0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x00,0xC0,0x18,0x00,0x02,0x00,0x80,0x06,0x00},
  16. 17         {0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x00,0xC0,0x18,0x00,0x02,0x00,0x80,0x03,0x00},
  17. 18         {0x00,0x01,0x03,0x00,0x80,0x80,0x01,0x01,0xC0,0x18,0x00,0x02,0x00,0x80,0x03,0x00},
  18. 19         {0x00,0x07,0x03,0x00,0x80,0xFF,0xFF,0x03,0xC0,0xF8,0xFF,0x03,0x00,0x80,0x01,0x08},
  19. 20         {0x00,0x03,0x03,0x06,0x80,0x01,0x80,0x01,0xC0,0x18,0x00,0x02,0x00,0x80,0x01,0x1C},
  20. 21         {0x00,0x03,0xFF,0x0F,0x80,0x01,0x80,0x01,0xC0,0x18,0x00,0x02,0xFC,0xFF,0xFF,0x3F},
  21. 22         {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x01,0xC0,0x18,0x00,0x02,0x00,0x80,0x01,0x00},
  22. 23         {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x01,0xC0,0x18,0x00,0x02,0x00,0x80,0x01,0x00},
  23. 24         {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x01,0x40,0xF8,0xFF,0x03,0x00,0x80,0x01,0x00},
  24. 25         {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x01,0x40,0x18,0x0C,0x02,0x00,0x80,0x01,0x00},
  25. 26         {0x00,0x03,0x03,0x00,0x80,0xFF,0xFF,0x01,0x40,0x00,0x0C,0x00,0x00,0x80,0x01,0x00},
  26. 27         {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x01,0x40,0x00,0x0C,0x00,0x00,0x80,0x01,0x00},
  27. 28         {0x00,0x03,0x03,0x00,0x80,0x01,0x80,0x00,0x60,0x60,0x2C,0x00,0x00,0x80,0x01,0x00},
  28. 29         {0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x60,0xF0,0xCC,0x01,0x00,0x80,0x01,0x00},
  29. 30         {0x00,0x03,0x03,0x00,0x00,0x08,0x04,0x02,0x60,0x30,0x0C,0x07,0x00,0x80,0x01,0x00},
  30. 31         {0x00,0x03,0x03,0x00,0x40,0x10,0x0C,0x06,0x20,0x18,0x0C,0x1E,0x00,0x80,0x01,0x00},
  31. 32         {0x00,0x03,0x03,0x08,0x40,0x30,0x18,0x0C,0x30,0x04,0x0C,0x1C,0x00,0x80,0x01,0x00},
  32. 33         {0x00,0x03,0x03,0x1C,0x60,0x30,0x18,0x1C,0x10,0x03,0x0C,0x18,0x00,0x84,0x01,0x00},
  33. 34         {0xFC,0xFF,0xFF,0x3F,0x30,0x60,0x18,0x18,0x88,0xC1,0x0F,0x10,0x00,0xF8,0x01,0x00},
  34. 35         {0x00,0x00,0x00,0x00,0x38,0x20,0x10,0x18,0x08,0x00,0x07,0x00,0x00,0xE0,0x00,0x00},
  35. 36         {0x00,0x00,0x00,0x00,0x18,0x20,0x00,0x08,0x04,0x00,0x02,0x00,0x00,0x40,0x00,0x00},
  36. 37         {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
  37. 38 };
  38. 39
  39. 40 #endif  
复制代码

在这个头文件中我们定义了一个32行16列的二维数组“text[32][16]”,这个二维数组中的数据就是我们在简介中使用取模软件得到的数据。其中数组一共有32行代表了每个汉字的高度是32;数组一共有16列,每列的数据是一个字节,代表了每行四个汉字共128个像素点。
工程创建完成后,点击工具栏中向右的绿色三角形对C代码进行综合,如下图所示:
阿莫论坛发帖领航者专用19973.png

图 9.3.14 运行C综合

综合完成后,会自动打开综合结果(solution)的报告,如下图所示:
阿莫论坛发帖领航者专用110044.png

图 9.3.15 综合报告

在工具栏中点击黄色的“田”字按钮,导出RTL,如下图所示:
阿莫论坛发帖领航者专用110108.png

图 9.3.16 导出RTL

在弹出的对话框中保持默认设置,直接点击“OK”,如下图所示:
阿莫论坛发帖领航者专用110174.png

图 9.3.17 将设计导出成IP

设计导出完成后,HLS设计部分就结束了,我们在HLS工程目录下可以找到导出的IP核,如下图红色方框所示:
阿莫论坛发帖领航者专用110265.png

图 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工程目录保持一致,如下图所示:
阿莫论坛发帖领航者专用110592.png

图 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”按钮。最终完成的设计如下图所示:
阿莫论坛发帖领航者专用111102.png

图 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_lcd\ov7725_lcd.sdk\ov7725_lcd”目录下的src文件夹拷贝到新建的应用工程目录下。
在SDK中刷新src目录,然后将“main.c”的代码修改为如下所示:
  1. 1   #include <stdio.h>
  2. 2   #include <stdlib.h>
  3. 3   #include <string.h>
  4. 4   #include "xil_types.h"
  5. 5   #include "xil_cache.h"
  6. 6   #include "xparameters.h"
  7. 7   #include "xgpio.h"
  8. 8   #include "xaxivdma.h"
  9. 9   #include "xaxivdma_i.h"
  10. 10  #include "display_ctrl/display_ctrl.h"
  11. 11  #include "vdma_api/vdma_api.h"
  12. 12  #include "emio_sccb_cfg/emio_sccb_cfg.h"
  13. 13  #include "ov5640/ov5640_init.h"
  14. 14  #include "xtext_overlay_top.h"
  15. 15  
  16. 16  //宏定义
  17. 17  #define BYTES_PIXEL        3                           //像素字节数,RGB888占3个字节
  18. 18  #define FRAME_BUFFER_NUM   3                           //帧缓存个数3
  19. 19  #define DYNCLK_BASEADDR    XPAR_AXI_DYNCLK_0_BASEADDR  //动态时钟基地址
  20. 20  #define VDMA_ID            XPAR_AXIVDMA_0_DEVICE_ID    //VDMA器件ID
  21. 21  #define DISP_VTC_ID        XPAR_VTC_0_DEVICE_ID        //VTC器件ID
  22. 22  //PL端  AXI GPIO 0(lcd_id)器件 ID
  23. 23  #define AXI_GPIO_0_ID      XPAR_AXI_GPIO_0_DEVICE_ID   
  24. 24  //使用AXI GPIO(lcd_id)通道1
  25. 25  #define AXI_GPIO_0_CHANEL  1                           
  26. 26  
  27. 27  //全局变量
  28. 28  //frame buffer的起始地址
  29. 29  unsigned int const frame_buffer_addr = (XPAR_PS7_DDR_0_S_AXI_BASEADDR
  30. 30                                          + 0x1000000);
  31. 31  XAxiVdma             vdma;
  32. 32  DisplayCtrl          dispCtrl;
  33. 33  XGpio                axi_gpio_inst;        //PL端 AXI GPIO 驱动实例
  34. 34  XText_overlay_top     text_overlay_inst;   //PL端text_overlay驱动实例
  35. 35  VideoMode            vd_mode;
  36. 36  unsigned int lcd_id;
  37. 37  
  38. 38  int main(void)
  39. 39  {
  40. 40      u32 status;
  41. 41      u16 cmos_h_pixel;   //ov5640 DVP 输出水平像素点数
  42. 42      u16 cmos_v_pixel;   //ov5640 DVP 输出垂直像素点数
  43. 43      u16 total_h_pixel;  //ov5640 水平总像素大小
  44. 44      u16 total_v_pixel;  //ov5640 垂直总像素大小
  45. 45  
  46. 46      //获取LCD的ID
  47. 47      XGpio_Initialize(&axi_gpio_inst, AXI_GPIO_0_ID);
  48. 48      lcd_id = LTDC_PanelID_Read(&axi_gpio_inst,AXI_GPIO_0_CHANEL);
  49. 49      xil_printf("lcd_id = %x\n\r",lcd_id);
  50. 50  
  51. 51      //根据获取的LCD的ID号来进行ov5640显示分辨率参数的选择
  52. 52      switch(lcd_id){
  53. 53          case 0x4342 :  //4.3寸屏,480*272分辨率
  54. 54              cmos_h_pixel = 480;
  55. 55              cmos_v_pixel = 272;
  56. 56              total_h_pixel = 1800;
  57. 57              total_v_pixel = 1000;
  58. 58              break;
  59. 59          case 0x4384 :  //4.3寸屏,800*480分辨率
  60. 60              cmos_h_pixel = 800;
  61. 61              cmos_v_pixel = 480;
  62. 62              total_h_pixel = 1800;
  63. 63              total_v_pixel = 1000;
  64. 64              break;
  65. 65          case 0x7084 :  //7寸屏,800*480分辨率
  66. 66              cmos_h_pixel = 800;
  67. 67              cmos_v_pixel = 480;
  68. 68              total_h_pixel = 1800;
  69. 69              total_v_pixel = 1000;
  70. 70              break;
  71. 71          case 0x7016 :  //7寸屏,1024*600分辨率
  72. 72              cmos_h_pixel = 1024;
  73. 73              cmos_v_pixel = 600;
  74. 74              total_h_pixel = 2200;
  75. 75              total_v_pixel = 1000;
  76. 76              break;
  77. 77          case 0x1018 :  //10.1寸屏,1280*800分辨率
  78. 78              cmos_h_pixel = 1280;
  79. 79              cmos_v_pixel = 800;
  80. 80              total_h_pixel = 2570;
  81. 81              total_v_pixel = 980;
  82. 82              break;
  83. 83          default :
  84. 84              cmos_h_pixel = 480;
  85. 85              cmos_v_pixel = 272;
  86. 86              total_h_pixel = 1800;
  87. 87              total_v_pixel = 1000;
  88. 88              break;
  89. 89      }
  90. 90  
  91. 91      emio_init();                         //初始化EMIO
  92. 92      status = ov5640_init( cmos_h_pixel,  //初始化ov5640
  93. 93                            cmos_v_pixel,
  94. 94                           total_h_pixel,
  95. 95                           total_v_pixel);
  96. 96      if(status == 0)
  97. 97          xil_printf("OV5640 detected successful!\r\n");
  98. 98      else
  99. 99          xil_printf("OV5640 detected failed!\r\n");
  100. 100
  101. 101     //根据获取的LCD的ID号来进行video参数的选择
  102. 102     switch(lcd_id){
  103. 103         case 0x4342 : vd_mode = VMODE_480x272;  break;  //4.3寸屏,480*272分辨率
  104. 104         case 0x4384 : vd_mode = VMODE_800x480;  break;  //4.3寸屏,800*480分辨率
  105. 105         case 0x7084 : vd_mode = VMODE_800x480;  break;  //7寸屏,800*480分辨率
  106. 106         case 0x7016 : vd_mode = VMODE_1024x600; break;  //7寸屏,1024*600分辨率
  107. 107         case 0x1018 : vd_mode = VMODE_1280x800; break;  //10.1寸屏,1280*800分辨率
  108. 108         default : vd_mode = VMODE_800x480; break;
  109. 109     }
  110. 110
  111. 111     //初始化字符叠加IP核text_overlay
  112. 112     XText_overlay_top_Initialize(&text_overlay_inst, XPAR_TEXT_OVERLAY_TOP_0_DEVICE_ID);
  113. 113     //配置字符叠加IP核text_overlay
  114. 114     XText_overlay_top_Set_rows(&text_overlay_inst, vd_mode.height);
  115. 115     //配置字符叠加IP核text_overlay
  116. 116     XText_overlay_top_Set_cols(&text_overlay_inst, vd_mode.width);
  117. 117
  118. 118     //配置VDMA
  119. 119     run_vdma_frame_buffer(&vdma, VDMA_ID, vd_mode.width, vd_mode.height,
  120. 120                             frame_buffer_addr,0,0,BOTH);
  121. 121     //初始化Display controller
  122. 122     DisplayInitialize(&dispCtrl, DISP_VTC_ID, DYNCLK_BASEADDR);
  123. 123     //设置VideoMode
  124. 124     DisplaySetMode(&dispCtrl, &vd_mode);
  125. 125     DisplayStart(&dispCtrl);
  126. 126
  127. 127     return 0;
  128. 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上就可以看到液晶屏上显示了摄像头采集图像和字符数据叠加后的图像,如下图所示:
阿莫论坛发帖领航者专用117321.png

图 9.5.1 字符叠加效果图

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 05:12

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表