source insight3.5显示中文_【正点原子FPGA连载】第五章彩条显示实验--领航者ZYNQ之HLS 开发指南...

1)摘自【正点原子】领航者ZYNQ之HLS 开发指南

2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761

3)全套实验源码+手册+视频下载:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html

4)对正点原子FPGA感兴趣的同学可以加群讨论:876744900

5)正点原子资料更新和新品发布,请加正点原子公众号:正点原子 关注方法:微信→添加好友→公众号→输入:正点原子

第五章彩条显示实验


AXI4-Stream总线协议由ARM公司提出,该协议专门针对视频、音频、数组等数据在片内通信设计。在本章我们将彩条显示实验,来学习如何使用Vivado HLS工具生成一个带有AXI4-Stream总线接口的IP核,以及在Vivado中对综合结果进行验证的流程。
本章包括以下几个部分:
55.1简介
5.2实验任务
5.3HLS设计
5.4IP验证
5.5下载验证
5.1简介
AXI4-Stream协议一般被翻译为AXI流协议,是AXI总线的一种演化版本。AXI4流协议作为一个标准接口,用于连接进行数据交换的组件。接口可以用来连接一个单一的主机,主机向接收数据的单一从机发送数据,也可用于连接若干个主机和从机的组件。协议支持共用一组信号线的多个数据流,允许构建一个通用互联。相比于AHB/APB,AXI流协议提出了数据包、数据帧以及传输操作等概念,这也是其被称为流(Stream)的原因。
关于AXI Stream的基本概念解释如下:
传输(Transfer):通过 AXI4 流接口进行的一个单一数据传输。一个单一数据传输由TVALID和TREADY握手信号定义。
包(Packet):通过 AXI4 流接口被一起传输的一组字节,包类似于 AXI4 的突发。
帧(Frame):一个 AXI4 流中最高级别的字节编组。一帧可以包含很大数量的字节数,例如,一个完整的视频帧缓存。
数据流(Data Stream):从一个源设备到一个目标设备传输的数据。
两个模块之间进行数据传输,需要事先约定好这两个模块之间的传输协议,这是两个信号握手的概念。TVALID和TREADY信号的握手包含三种情况:TVALID先于 TREADY 的握手、TREADY先于 TVALID 的握手、TVALID 和 TREADY 同时发生的握手。
下图中,主机发出了数据和控制信息并将TVALID 信号置为高。一旦主机驱动了 TVALID ,主机发出的数据或控制信息必须保持不变,直到从机驱动 TREADY 信号为高表示可以接收数据和控制信息。在这种情况下,一旦从机设置 TREADY 为高,传输就会发生。箭头标示出了传输发生的位置。

8ec1c2347ba22112e19bb4837a72d083.png

图 5.1.1 TVALID先于TREADY的握手


下图中,从机在数据和控制信息有效之前驱动TREADY为高。这表示目标设备可以在一个ACLK周期内接收数据和控制信息。在这种情况下,一旦主机驱动 TVALID 为高,则传输就会发生。箭头标示出了传输发生的位置。

71c7337f4abfb83a1dad0dcc5d480c46.png

图 5.1.2 TREADY先于 TVALID 的握手


下图中,主机驱动TVALID为高,从机在同一时钟(ACLK)周期内也驱动TREADY为高。在这种情况下,如图中箭头标注,传输在同一周期内发生。

ecac8734f92a293f6f716deabd6c334b.png

图 5.1.3 TVALID 和 TREADY 同时发生的握手


本次实验我们需要使用Vivado HLS工具生成带有AXI4-Stream接口的IP核,并将此IP核的AXI4-Stream接口连接到“AXI4-Stream to Video Out”模块中的AXI4-Stream接口,如下图所示:

29dd03dc9c8aff0f9be35da0d3d97966.png

图 5.1.4 AXI4-Stream to Video Out模块接口


我们重点关注图中的“s_axis_video_tlast”和“s_axis_video_tuser”信号,其中“s_axis_video_tlast”是AXI4-Stream协议中“TLAST”信号,这个信号设置为高表示一行像素传输结束,“s_axis_video_tuser”是AXI4-Stream协议中的“TUSER”信号,这个信号设置为高表示一帧图像传输开始。时序图如下图所示:

ed030896e81dd8b43e699ffc5c8e8c4b.png

图 5.1.5 行结束和帧开始信号


图中的“EOL”表示“End of line”是行传输结束信号,它在一行图像像素传输结束的时候拉高一个时钟周期;图中的“SOF”表示“Start of frame”是帧传输开始信号。它在一帧图像像素传输开始的时候拉高一个时钟周期。
5.2实验任务
本节的实验任务是使用Vivado HLS设计彩条显示的IP核,并在Vivado中对设计出来的IP核进行验证。
5.3HLS设计
我们在电脑中的“F:ZYNQHigh_Level_Synthesis”目录下新建一个名为lcd_rgb_colorbar的文件夹,作为本次实验的工程目录。然后打开Vivado HLS工具,创建一个新的工程。设置工程名为“lcd_rgb_colorbar”,选择工程路径为刚刚创建的文件夹。需要注意的是,工程名以及路径只能由英文字母、数字和下划线组成,不能包含中文、空格以及其他特殊字符。如下图所示:

b9059ecc16f79a55668e95afe6767bd1.png

图 5.3.1 工程配置界面


设置好工程名及路径之后,点击“Next”,进入如下界面设置顶层函数:

2ca0b4bf886d9a9592d73b7d5a31583b.png

图 5.3.2 设置顶层函数


工程创建完成后,在工程面板中的“source”目录上点击右键,然后在打开的列表中选择“New File”新建源文件,在弹出的对话框中输入源文件的名称“lcd_rgb_colorbar.c”,如图 5.3.3所示。源文件默认的保存路径为HLS工程目录,为方便源文件的管理,我们在工程目录下新建一个名为“src”的文件下,将源文件保存在src目录下。

361df9a8e3a0b272ebe263ccb41143d2.png

图 5.3.3 输入源文件名


我们在图 5.3.3中输入的源文件的后缀名为“.c”,即使用C语言进行设计。如果使用C++语言进行设计,那么后缀名需要设置为“.cpp”。设置好文件名和路径之后,点击“保存”。
“lcd_rgb_colorbar.c”文件源代码如下:

  1. 1 //引入数据类型头文件
  2. 2 #include "ap_cint.h"
  3. 3
  4. 4 //定义axi4-stream类型的结构体
  5. 5 typedef struct ap_axi_stream{
  6. 6 uint24 data;
  7. 7 uint1 user; //帧传输开始信号
  8. 8 uint1 last; //行传输结束信号
  9. 9 }axi_stream;
  10. 10
  11. 11 //彩条显示顶层函数
  12. 12 void lcd_rgb_colorbar(axi_stream* color,int rows,int cols)
  13. 13 {
  14. 14 //Vivado HLS接口定义
  15. 15 #pragma HLS INTERFACE s_axilite port=cols
  16. 16 #pragma HLS INTERFACE s_axilite port=rows
  17. 17 #pragma HLS INTERFACE axis port=color
  18. 18 #pragma HLS INTERFACE ap_ctrl_none port=return
  19. 19
  20. 20 int x_pos,y_pos;
  21. 21 int color_edge = cols/7; //显示7个彩条数据
  22. 22
  23. 23 for(y_pos=0; y_pos<rows; y_pos++){
  24. 24 for(x_pos=0; x_pos<cols; x_pos++){
  25. 25 //帧传输开始拉高一个时钟周期
  26. 26 if((x_pos==0) && (y_pos==0)){
  27. 27 (*color).user = 1;
  28. 28 }else{
  29. 29 (*color).user = 0;
  30. 30 }
  31. 31 //行传输结束拉高一个时钟周期
  32. 32 if(x_pos == (cols-1)){
  33. 33 (*color).last = 1;
  34. 34 }else{
  35. 35 (*color).last = 0;
  36. 36 }
  37. 37 //像素点彩条数据赋值
  38. 38 if(x_pos < color_edge){
  39. 39 (*color).data = 0xff0000; //红色
  40. 40 }else if(x_pos >= color_edge && x_pos < color_edge*2){
  41. 41 (*color).data = 0xff7f00; //橙色
  42. 42 }else if(x_pos >= color_edge*2 && x_pos < color_edge*3){
  43. 43 (*color).data = 0xffff00; //黄色
  44. 44 }else if(x_pos >= color_edge*3 && x_pos < color_edge*4){
  45. 45 (*color).data = 0x00ff00; //绿色
  46. 46 }else if(x_pos >= color_edge*4 && x_pos < color_edge*5){
  47. 47 (*color).data = 0x00ffff; //青色
  48. 48 }else if(x_pos >= color_edge*5 && x_pos < color_edge*6){
  49. 49 (*color).data = 0x0000ff; //蓝色
  50. 50 }else if(x_pos >= color_edge*6 && x_pos < cols){
  51. 51 (*color).data = 0x8b00ff; //紫色
  52. 52 }
  53. 53 }
  54. 54 }
  55. 55 }


在代码的第1行,包含了一个名为“ap_cint.h”的头文件,这个是xilinx提供的库文件,里面包含了本章节所需要用到的数据类型。在代码的第5行到第9行定义了“axi_stream”类型的结构体,结构体中包含了3个成员变量,分别是data、user和last。其中“data”信号是像素传输的数据,“last”信号是行像素传输结束标志信号,“user”信号是帧像素传输开始标志信号。我们这里将data置为24位,是因为采用RGB888格式的数据进行传输,数据位宽为24。
在代码的第12行,定义了顶层函数“lcd_color_bar”,这里我们传入axi_stream结构体类型的指针是因为vivodo HLS规定如果用户想要生成带有AXI4-Stream接口的IP核,只能传入指针或者数组的类型作为输出接口。“rows”表示图像行数,“cols”表示图像列数。这里我们可以通过ZYNQ的PS端来配置这些参数,从而兼容不同分辨率的LCD屏幕。
在代码的第15行到第17行,“axis”指定了颜色数据传输采用AXI4-Stream总线协议,“s_axilite”指定了行和列控制信号传输采用AXI4-Lite总线协议。在代码的第18行“ap_ctrl_none”表明没有添加包级别的协议,而是完全在端口接口级别用端口级别协议来做控制。在代码的第21行,定义了一个变量“color_edge”,
通过对比像素点位置“x_pos”值与“color_edge”值大小来显示7个彩条数据。
代码的第26行到第30行是一个条件判断语句,通过判断像素点的位置来设置“user”和“last”信号的值。(“x_pos==0”&&“y_pos==0”)表示一帧图像数据开始传输,此时将user信号置高一个时钟周期,在其它情况下将user信号置低。代码的第32行到第36行,“x_pos == (cols – 1)”表示一行像素传输到最后一个位置,这里我们将cols减一是因为cols是从零开始计数。当一行数据传输结束的时候将last信号置高一个时钟周期,在其它情况下将last信号置低。
在代码的第38行到第51行,通过比较“x_pos”和“color_edge”的大小,来对像素点的颜色数据进行赋值。其中“0xff0000”表示RGB888格式的数据高8位为1,从而像素点显示红色。
代码输入完成后,按快捷键Ctrl+S保存。然后点击工具栏中向右的绿色三角形对C代码进行综合,如下图所示:

7a669a3711562f60978ae9e9dff53b39.png

图 5.3.4 运行C综合


综合完成后,会自动打开综合结果(solution)的报告,如下图所示:

074ec8544b837f86ed2169b2954587e5.png

图 5.3.5 综合报告


图中所示的综合报告中,给出了设计的性能评估、资源评估以及接口等信息。本次实验中,我们重点关注综合工具为我们生成的接口信息,如下图所示:

58efd586fbb4cf31ccb5ade0efb76d6f.png

图 5.3.6 接口信息


图中Protocol一栏,“s_axi”和“axis”分别表示Vivado HLS生成了一个带有“AXI4-Lite”从接口和“AXI4-Stream”总线接口的IP核。其中“AX4-Lite”总线接口用于控制彩条显示的分辨率,“AXI4-Stream”总线接口用于传输彩条数据。
在工具栏中点击黄色的“田”字按钮,导出RTL,如下图所示:

46018772f684d6e9279e55a2ad283d4b.png


图 5.3.7 导出RTL
在弹出的对话框中保持默认设置,直接点击“OK”,如下图所示:

a7c401dae8154cc09e26cf192068537a.png

图 5.3.8 将设计导出成IP


设计导出完成后,HLS设计部分就结束了,我们在HLS工程目录下可以找到导出的IP核,如下图红色方框所示:

543cfbeb01cfe3d68787f0a341aea8a1.png

图 5.3.9 导出得到的IP


我们到计算机工程目录所指向的文件夹中同样可以看到以ZIP压缩文件形式存在的IP核,如下图所示:

b77720b3f2e17e8cf09c01f2b180dbf0.png

图 5.3.10 文件夹中的IP核


HLS设计结束之后,我们将在Vivado中对导出的IP核进行验证。
5.4IP验证
在IP验证环节,我们会使用Vivado工具的IP集成器将生成的IP核添加到Block Design中,然后完成设计后将程序下载到领航者开发板上进行验证。
我们在《领航者ZYNQ之嵌入式开发指南》第十八章“PS通过VDMA驱动LCD显示实验”中已经实现了彩条数据的显示。本次实验可以在这个实验的基础上进行,将《领航者ZYNQ之嵌入式开发指南》中的第18个实验“_vdma_lcd”的Vivado工程重新另存为“lcd_rgb_colorbar_ip_test”的Vivado工程。为了方便工程管理,我们将Vivado工程的目录与HLS工程目录保持一致,如下图所示:

f299274984e92e283a9120fee3269ea1.png

图 5.4.1 创建Vivado工程


Vivado工程创建完成之后,本次实验的工程目录如下图所示:

d9fba1e494bb339f614e2af7a56e7c4e.png

图 5.4.2 按键控制LED实验工程目录


工程创建完成后,需要先将HLS设计过程中导出的IP核和本次工程所需要的IP核拷贝到Vivado工程目录下。我们在Vivado工程目录下新建一个名为“ip_repo”的文件夹,然后将图1.3.18中的压缩包拷贝到该文件夹中并解压,解压完成后如下图所示:

25686cdcc5c492b8120f93e5a9046569.png

图 5.4.3 拷贝并解压IP


由于本次实验不需要用到VDMA,所以删除下图所示的IP核。

b02b027e8ebe618d007ce3290bda7615.png

图 5.4.4 VDMA IP核


将Vivado HLS生成的彩条显示IP核添加到原理图设计中并连线,如下图所示:

103badba69d67c8190e625f5277ffbd9.png

图 5.4.5 连线图


然后点击“Run Connnection Automation”,下面列出了会自动连接的模块及其接口,勾选“AllAutomation”, 然后点击“OK”按钮。最终完成的设计如下图所示:

73e25804c56bb408bb28f7d0a4638132.png

图 5.4.6 完成后的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 软件。
将“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 "display_ctrl/display_ctrl.h"
  9. 9 #include "xlcd_rgb_colorbar.h"
  10. 10
  11. 11 //宏定义
  12. 12 #define DYNCLK_BASEADDR XPAR_AXI_DYNCLK_0_BASEADDR //动态时钟基地址
  13. 13 #define DISP_VTC_ID XPAR_VTC_0_DEVICE_ID //VTC器件ID
  14. 14 #define AXI_GPIO_0_ID XPAR_AXI_GPIO_0_DEVICE_ID //PL端 AXI GPIO 0(lcd_id)器件ID
  15. 15 #define AXI_GPIO_0_CHANEL 1 //PL按键使用AXI GPIO(lcd_id)通道1
  16. 16
  17. 17 //全局变量
  18. 18 DisplayCtrl dispCtrl;
  19. 19 XGpio axi_gpio_inst; //PL端 AXI GPIO 驱动实例
  20. 20 VideoMode vd_mode;
  21. 21 unsigned int lcd_id=0; //LCD ID
  22. 22
  23. 23 int main(void)
  24. 24 {
  25. 25 XLcd_rgb_colorbar colorbarInstance;
  26. 26 //获取LCD的ID
  27. 27 XGpio_Initialize(&axi_gpio_inst,AXI_GPIO_0_ID);
  28. 28 lcd_id = LTDC_PanelID_Read(&axi_gpio_inst,AXI_GPIO_0_CHANEL);
  29. 29 xil_printf("LCD ID: %xrn",lcd_id);
  30. 30
  31. 31 //根据获取的LCD的ID号来进行video参数的选择
  32. 32 switch(lcd_id){
  33. 33 case 0x4342 : vd_mode = VMODE_480x272; break; //4.3寸屏,480*272分辨率
  34. 34 case 0x4384 : vd_mode = VMODE_800x480; break; //4.3寸屏,800*480分辨率
  35. 35 case 0x7084 : vd_mode = VMODE_800x480; break; //7寸屏,800*480分辨率
  36. 36 case 0x7016 : vd_mode = VMODE_1024x600; break; //7寸屏,1024*600分辨率
  37. 37 case 0x1018 : vd_mode = VMODE_1280x800; break; //10.1寸屏,1280*800分辨率
  38. 38 default : vd_mode = VMODE_800x480; break;
  39. 39 }
  40. 40
  41. 41 XLcd_rgb_colorbar_Initialize(&colorbarInstance, XPAR_LCD_RGB_COLORBAR_0_DEVICE_ID);
  42. 42
  43. 43 //初始化Display controller
  44. 44 DisplayInitialize(&dispCtrl, DISP_VTC_ID, DYNCLK_BASEADDR);
  45. 45 //设置VideoMode
  46. 46 DisplaySetMode(&dispCtrl, &vd_mode);
  47. 47 DisplayStart(&dispCtrl);
  48. 48
  49. 49 while(1)
  50. 50 {
  51. 51 XLcd_rgb_colorbar_Set_cols(&colorbarInstance, vd_mode.width);
  52. 52 XLcd_rgb_colorbar_Set_rows(&colorbarInstance, vd_mode.height);
  53. 53 sleep(20);
  54. 54 }
  55. 55 return 0;
  56. 56 }


在代码的第9行引入了“xlcd_rgb_color.h”头文件,这个头文件是Vivado HLS工具生成的,里面声明了彩条显示IP核的驱动函数。其路径如下图所示:

3d478d30867b4ec4265c5f0b5fa4e4e2.png


在代码的第41行通过“XLcd_rgb_colorbar_Initialize”函数来初始化Vivado HLS生成的IP核,这个函数在“xlcd_rgb_color.h”头文件中声明。在代码的第51行通过传入“vd_mode.width”形参来设置彩条显示的列数,在代码的第52行通过传入“vd_mode.height”形参来设置彩条显示的列数。
5.5下载验证
首先我们将下载器与领航者底板上的 JTAG 接口连接,下载器另外一端与电脑连接。接下来使用 FPC 排线一端与 RGB LCD 液晶屏上的 接口连接,另一端连接领航者底板上的 RGB LCD 接口,如下图所示。连接时,先掀开 FPC 连接器上的黑色翻盖,将 FPC 排线蓝色面朝上插入连接器,最后将黑色盖压下以固定 FPC 排线。

f95c696309695c137e31055e1640ef5a.png

图 5.5.1 RGB LCD液晶屏

bc44548d4b0eba3dfe5963c247c61899.png

图 5.5.2 开发板连接图


在 SDK 软件下方的 SDK Terminal 窗口中点击右上角的加号设置并连接串口。然后下载本次实验硬件 设计过程中所生成的 BIT 文件,来对 PL 进行配置。最后下载软件程序,下载完成后,下载完成后,在下方 的 SDK Terminal 中可以看到应用程序打印的信息,如下图所示:

8f64f0a03dda101ee15be94d2e9851d4.png

图 5.5.3 Terimnal 打印的信息


由于本次实验连接的是 7 寸液晶屏(分辨率:800*480),因此串口打印的 LCD ID 为 7084。接下来观察RGB LCD液晶屏,可以看到,LCD 上显示出彩条,彩条颜色从左到右依次为红橙黄绿青蓝紫,与写入的彩虹色数据相同,如下图所示。

31e0833c22642affbe1f1db82d6af402.png

图 5.5.4 RGB LCD液晶屏显示彩条

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值