OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7258|回复: 3

[XILINX] 【正点原子FPGA连载】第十九章 SD卡读BMP图片HDMI显示实验--摘自【正点原子】领航者ZYNQ之嵌入式开发指南_V1.2

[复制链接]

1107

主题

1118

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4615
金钱
4615
注册时间
2019-5-8
在线时间
1218 小时
发表于 2020-9-8 11:18:38 | 显示全部楼层 |阅读模式
本帖最后由 正点原子01 于 2020-9-8 11:18 编辑

1)实验平台:正点原子领航者ZYNQ开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-301505-1-1.html
4)对正点原子FPGA感兴趣的同学可以加群讨论:905624739 点击加入群聊
5)关注正点原子公众号,获取最新资料更新
1.jpg
1120.png

第十九章 SD卡读BMP图片HDMI显示实验

我们在“SD卡读BMP图片LCD显示实验”中,成功地将SD卡中的BMP图片读出,并将其显示在了LCD屏上。本章我们将学习如何SD卡中的BMP图片显示在HDMI显示器上。
本章包括以下几个部分:
1         
1.1        简介
1.2        实验任务
1.3        硬件设计
1.4        软件设计
1.5        下载验证
简介
在“SD卡读BMP图片LCD显示实验”的简介部分,我们详细介绍了BMP图片的数据格式;另外在《领航者FPGA开发指南》中的“HDMI彩条显示实验”一章,我们介绍了HDMI接口。如果大家对这两部分的内容不熟悉的话,可以参考相应的章节,此处就不再赘述了。
实验任务
本章的实验任务是使用领航者ZYNQ开发板读取SD卡中存放的BMP格式图片,分辨率为1920*1080,并将其显示在HDMI显示器上。
硬件设计
根据实验任务我们可以画出本次实验的系统框图,如下图所示:
image002.png

图 0.1 系统框图
图5.3.1与“SD卡读BMP图片LCD显示实验”中的系统框图基本相同,只是将驱动LCD显示的rgb2lcd模块替换成了本次实验中的DVI Transmitter,用于驱动HDMI接口;另外还删除了用于读取LCD ID信息的AXI GPIO模块。因此本次实验的硬件设计部分在“SD卡读BMP图片LCD显示实验”的基础上稍作修改即可。
首先要删除《SD卡读BMP图片LCD显示实验》工程中的rgbto lcd和AXI GPIO两个模块,以及LCD相关的接口。如图 20.3.2所示,我们要删除图中橙色高亮的两个模块和3个接口:
image004.png

图 0.2 删除LCD相关模块
接下来添加DVI TransmitterIP核。该IP核位于工程目录下的ip_repo文件夹中,名为“DVI_TX”。我们需要将其添加到工程的IP库中,添加IP核的方法请大家参考“自定义IP核-呼吸灯实验”。添加完成后,我们要在Block Design中连接DVI Transmitter模块的接口信号,并引出外部端口,具体的连接方式如图 20.3.3所示:
image006.png

图 0.3 添加并连接DVI_Transmitter IP核
至此本次实验的硬件框图已经搭建好了。需要说明的是,本次实验的硬件框图是基于《SD卡读BMP图片LCD显示实验》搭建的,VDMA的AXI Stream格式数据流和Memory Map格式数据流的时钟频率设置的较低,为100Mhz,因此VDMA和DDR3的数据交互速率会受到限制,即支持的HDMI显示分辨率无法达到很高,实测最大能达到的分辨率为1280x800。
对于LCD屏的显示实验来说,达到1280x800的分辨率已经够用了,但是考虑到目前大多数的HDMI显示器支持1080P(1920x1080)的分辨率,我们需要对底层搭建的硬件环境做修改,才能支持1080P分辨率。考虑到本手册HDMI显示相关的例程不需要1080P分辨率,且大多数HDMI显示例程是基于LCD例程修改而来,如果每次都为了兼容1080P分辨率而修改底层硬件环境比较麻烦,因此本手册仅本章实验的底层硬件环境支持1080P分辨率,其它HDMI实验大家如果有1080P分辨率的显示需求,可以按照本章实验进行修改。
底层硬件修改的方法是将VDMA的AXI Stream格式数据流和Memory Map格式数据流的时钟频率改为150Mhz,而VDMA的配置端口不需要太高的频率,可以仍然保持100Mhz。
首先双击打开“ZYNQ7Processing System”框图,点击“Clock Configuration”,在“PL Fabric Clocks”一栏下勾选FCLK_CLK1,时钟频率设置为150Mhz。设置完成后,点击“OK”按钮,如下图所示:
image008.jpg

0.4 添加“FCLK_CLK1”时钟
修改完成后,可以发现“ZYNQ7Processing System”框图多了一个FCLK_CLK1端口。接下来删除FCLK_CLK0连线,首先选中FCLK_CLK0的连线使其高亮,然后按下键盘的“Delete”进行删除,如图 20.3.5和图 20.3.6所示:
image010.jpg

0.5 选中FCLK_CLK0连线
image012.jpg

0.6 删除FCLK_CLK0连线
然后删除框图中的AXIInterconnect IP核(ps7_0_axi_periph)、AXI SmartConnect IP核(axi_smc)和Processor System Reset IP核(rst_ps7_0_100M),框图删除后,如下图所示。
image014.jpg

0.7 删除IP
接下来连接FCLK_CLK1的时钟,如下图所示。
image016.jpg

然后点击“Run Connnection Automation”,下面列出了会自动连接的模块及其接口,勾选“All Automation”,然后点击“OK”按钮。
此时系统会自动生成 AXI Interconnect 和 AXISmartconnect。AXI Interconnect(ps7_0_axi_periph)用于桥接ZYNQ处理器M_AXI_GP0总线和外部低速外设的AXI_LITE总线;AXISmartconnect(axi_smc)用于连接ZYNQ处理器的HP0接口和VDMA的M_AXI_MM2S总线。另外系统也自动生成了两个 reset模块(rst_ps7_0_100M和rst_ps7_0_150M),用于复位总线上的外设。
整体系统架构图如下:
image018.jpg

0.8 整体系统架构连接图
block design修改完成后保存,然后重新Generate Output Products和“Create HDL Wrapper”。接下来我们还要修改约束文件,为HDMI接口分配引脚。打开工程中名为“system_wrapper.xdc”的约束文件,并将原先LCD相关的约束语句删除,替换成以下内容:
  1. set_property-dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports tmds_oen_0]
  2. set_propertyPACKAGE_PIN L16 [get_ports {TMDS_0_tmds_data_p[2]}]
  3. set_propertyPACKAGE_PIN M14 [get_ports {TMDS_0_tmds_data_p[1]}]
  4. set_propertyPACKAGE_PIN K19 [get_ports {TMDS_0_tmds_data_p[0]}]
  5. set_propertyPACKAGE_PIN L14 [get_ports TMDS_0_tmds_clk_p]
复制代码
保存约束文件,然后选择“GenerateBitstream”重新生成BIT文件。
软件设计
本次实验的软件工程与“SD卡读BMP图片LCD显示实验”略有不同,如下图所示:
image020.png

图 0.1 软件工程
图 20.4.1左侧红色方框中的文件夹名为“display_ctrl_hdmi”,它在前面实验中“display_ctrl”的基础上删除了GPIO相关的函数及变量。在本次实验中删除了AXI GPIO模块,因此要删除这些函数和变量,否则会报错。
本次实验的代码如下所示:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "xil_types.h"
  5. #include "xil_cache.h"
  6. #include "xparameters.h"
  7. #include "xaxivdma.h"
  8. #include "xaxivdma_i.h"
  9. #include "display_ctrl_hdmi/display_ctrl.h"
  10. #include "vdma_api/vdma_api.h"
  11. #include "ff.h"

  12. //宏定义
  13. #define BYTES_PIXEL        3                          //像素字节数,RGB888占3个字节
  14. #define DYNCLK_BASEADDR    XPAR_AXI_DYNCLK_0_BASEADDR //动态时钟基地址
  15. #define VDMA_ID            XPAR_AXIVDMA_0_DEVICE_ID   //VDMA器件ID
  16. #define DISP_VTC_ID        XPAR_VTC_0_DEVICE_ID       //VTC器件ID

  17. //函数声明
  18. void load_sd_bmp(u8 *frame);

  19. //全局变量
  20. XAxiVdma     vdma;
  21. DisplayCtrl  dispCtrl;
  22. VideoMode    vd_mode;
  23. //frame buffer的起始地址
  24. unsigned int const frame_buffer_addr = (XPAR_PS7_DDR_0_S_AXI_BASEADDR+ 0x1000000);
  25. unsigned int lcd_id=0;        //LCD ID

  26. int main(void)
  27. {
  28. xil_printf("HDMI Display 1920*1080 \r\n");

  29. //设置video参数,分辨率:1920*1080
  30. vd_mode = VMODE_1920x1080;

  31. //配置VDMA
  32. run_vdma_frame_buffer(&vdma, VDMA_ID, vd_mode.width, vd_mode.height,
  33.                           frame_buffer_addr,0, 0,ONLY_READ);

  34. //初始化Display controller
  35. DisplayInitialize(&dispCtrl, DISP_VTC_ID, DYNCLK_BASEADDR);
  36. //设置VideoMode
  37. DisplaySetMode(&dispCtrl, &vd_mode);
  38. DisplayStart(&dispCtrl);

  39. //读取SD卡图片并显示
  40. load_sd_bmp((u8*)frame_buffer_addr);

  41. return 0;
  42. }

  43. //从SD卡中读取BMP图片
  44. void load_sd_bmp(u8 *frame)
  45. {
  46. static  FATFS fatfs;
  47. FIL     fil;
  48. u8      bmp_head[54];
  49. UINT    *bmp_width,*bmp_height,*bmp_size;
  50. UINT    br;
  51. int     i;

  52. //挂载文件系统
  53. f_mount(&fatfs,"",1);

  54. //打开文件
  55. f_open(&fil,"fengjing.bmp",FA_READ);

  56. //移动文件读写指针到文件开头
  57. f_lseek(&fil,0);

  58. //读取BMP文件头
  59. f_read(&fil,bmp_head,54,&br);
  60. xil_printf("fengjing.bmp head: \n\r");
  61. for(i=0;i<54;i++)
  62.       xil_printf("%x",bmp_head[i]);

  63. //打印BMP图片分辨率和大小
  64. bmp_width  = (UINT *)(bmp_head +0x12);
  65. bmp_height = (UINT *)(bmp_head + 0x16);
  66. bmp_size   = (UINT *)(bmp_head +0x22);
  67. xil_printf("\n width = %d, height = %d, size = %d bytes\n\r",
  68.           *bmp_width,*bmp_height,*bmp_size);

  69. //读出图片,写入DDR
  70. for(i=*bmp_height-1;i>=0;i--){
  71.       f_read(&fil,frame+i*(*bmp_width)*3,(*bmp_width)*3,&br);
  72. }

  73. //关闭文件
  74. f_close(&fil);

  75. Xil_DCacheFlush();     //刷新Cache,数据更新至DDR3中
  76. xil_printf("show bmp\n\r");
  77. }
复制代码
可以看出,本次实验的程序与“SD卡读BMP图片LCD显示实验”非常相似,只是删除了读取LCD ID相关的内容。有关这部分代码的详细介绍请大家参考“SD卡读BMP图片LCD显示实验”,此处不再赘述。需要注意的是,本次实验在SD卡中放置的图片分辨率为1920*1080,因此在程序的第35行,视频参数设置成VMODE_1920x1080。
下载验证
首先我们将下载器与领航者底板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用Mini USB连接线将开发板左侧的USB_UART接口与电脑连接,用于串口通信。
我们在工程目录下新建了一个名为“风景图片”的文件夹,把其中名为“fengjing.bmp”的图片拷贝到SD卡的根目录下,然后将SD卡插入领航者底板背面的卡槽中。另外还需要使用HDMI连接线将HDMI显示器连接到领航者底板上的HDMI接口。最后连接开发板的电源,并打开电源开关。
在SDK软件下方的SDK Terminal窗口中点击右上角的加号来设置并连接串口。然后下载本次实验硬件设计过程中所生成的BIT文件,来对PL进行配置。最后下载软件程序,下载完成后,在下方的SDK Terminal中可以看到应用程序打印的信息,如下图所示:
image022.jpg

图 0.1 串口打印信息
图 20.5.1中打印出了BMP文件的文件头和信息头等信息,同时从数据中计算出BMP图片的宽度为1920,高度为1080,与我们存入SD卡中的BMP图片一致。
同时HDMI显示器上显示存入SD卡中的示例图片,如图 20.5.2所示,说明本次实验在领航者ZYNQ开发板上面下载验证成功。
image024.jpg

图 0.2 下载验证



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

2

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2022-10-24
在线时间
1 小时
发表于 2022-10-28 16:17:35 | 显示全部楼层
为什么我的显示器都不亮
回复 支持 反对

使用道具 举报

3

主题

1979

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5520
金钱
5520
注册时间
2018-10-21
在线时间
1561 小时
发表于 2022-10-29 14:10:04 | 显示全部楼层
别出bug 发表于 2022-10-28 16:17
为什么我的显示器都不亮

可以单独下载HDMI彩条的实验看亮不亮
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
6
金钱
6
注册时间
2023-9-4
在线时间
2 小时
发表于 2023-9-12 10:42:54 | 显示全部楼层
有大佬们知道改了分辨率后显示不出来是怎么回事吗
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-10-4 08:15

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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