zynq板zedboard+SDK设计(二)HDMI工程解析

0.前言

工程源自GitHub,实现了从sd卡读取图像然后通过HDMI显示的功能GJigar/HDMI-displayicon-default.png?t=N7T8https://github.com/GJigar/HDMI-display本文只是根据自己的理解做一些工程分析

1.硬件电路

先看一下zedboard的硬件电路,zedboard中因为HDMI输出接口接了一个ADV7511芯片,对向HDMI接口发送的数据进行了编码,所以无法直接自己编写时序控制每个像素位的输出,需要通过一个专用的HDMI输出IP核进行数据的输出控制

2.bd设计

整体bd框图如下,我会按照标号顺序简要介绍

1. clocking wizard

主要用于输出不同频率的时钟,在本工程中,输入了50MHz时钟,输出了一个148.5MHz的时钟。输入的时钟频率取决于板上晶振频率,通常FPGA板载晶振为50MHz,具体还请查看相应文件。输出时钟频率是通过显示图像的分辨率以及帧数计算出来的。本实验输出1080p的图像进行60帧显示,需要的时钟频率即为148.5MHz。

计算公式为:宽度像素点数x长度像素点数x帧数,如本实验为2200x1125x60=14850000=148.5MHz。其中长宽包含了消隐期的时钟数。

2. processor system reset

处理器复位用IP核,连接bd时自动生成,用于管理、生成复位信号

3. AXI smartconnect

AXI连接用的IP,用于连接zynq核和其他使用了AXI端口的IP,连接bd时自动生成

 4.zynq7 processing system

zynq处理器,没什么好说的,任何工程的唯一必需品

 5.AXI interconnect

也是用于管理zynq核和其他使用了AXI接口的IP核之间连接的,不过这个是连接zynq核master口的,前面那个是连接zynq核slave口的,连接bd时自动生成

6.AXI video direct memory access

数据搬运用IP核,相对于dma,用于数据在存储器和AXI4-Stream形式之间的转换,具有帧缓存功能,并且提供了数据对齐的功能,防止在搬运视频信息时出现撕裂现象,本次工程只启用了读通道,单缓存。

 

 advanced页面下可以选择开启数据的对其同步功能,本次实验不需要没有启用

 

7. constant

一个用于输出常量的IP,通常用于连接一些复位或是使能接口,用于保持不复位或是使能的状态

8.RGB to YCrCb color-space converter

用于将视频由RGB色域转换到YCrCb色域,主要就是设置一个分辨率

 

9.video timing controller

用于生成专用于HDMI显示的时序,在HDMI显示中,行与行,帧与帧的数据传输之间存在消隐间隔,用于传输一些控制信号或是音频信息。根据视频分辨率的不同,数据传输的时钟数和消隐阶段的时钟数是不同的,不过有着确定的关系,该IP可以生成专用的时钟时序

 先在detection/generation页面勾选enable generation,这样就可以输出时钟时序了

 在default/constant页面选择视频分辨率,有一些常用的默认选项如480p/720p/1080p等等,选择默认的分辨率后,IP核会自行配置数据时序和消隐时序之间的关系,用户也可以选择custom来自行定制需要的时序。

这里我们选择1080p,与前面RGB to YCrCb color-space converter核选择的分辨率对应。

 

 10.system_c_rsample

作者自己编写的模块,功能很简单,就是每次传输数据时,通过反转一个触发信号,来交替的传输24位数据的低16位数据或是一个高8位和低8位拼成的16位数据

代码如下

module c_rsample(
input    aclk,
input    aresetn,
//s_stream
input [23:0] s_axis_video_tdata,
input    s_axis_video_tlast,
output   s_axis_video_tready,
input    s_axis_video_tuser,
input    s_axis_video_tvalid,
//m_stream
output [15:0]  m_axis_video_tdata,
output   m_axis_video_tlast,
input    m_axis_video_tready,
output   m_axis_video_tuser,
output   m_axis_video_tvalid
);

reg toggle=0;

always @(posedge aclk)
begin
    if(s_axis_video_tvalid & s_axis_video_tready)
        toggle <= ~toggle;
end
 
assign m_axis_video_tdata = (toggle)? {s_axis_video_tdata[23:16],s_axis_video_tdata[7:0]} : s_axis_video_tdata[15:0];
assign m_axis_video_tlast = s_axis_video_tlast;
assign s_axis_video_tready = m_axis_video_tready;
assign m_axis_video_tuser = s_axis_video_tuser;
assign m_axis_video_tvalid = s_axis_video_tvalid;

endmodule

11.AXI4-stream to video out

根据video timing controller提供的时序将数据流转换为视频信息,也就是必须要和前面的video timing controller配合使用,注意视频的格式即YUV,就是前面通过RGB转换过来的YCrCb格式

 

 12.constant

又是一个用于输出常量的IP,和前面的constant相同,两个应该是可以合并成一个2位宽的constant核的,然后分别连接现在连接的端口

13.AXI IIC

i2c接口, 用于控制HDMI中的scl(串行时钟)、sda(串行数据)两个引脚,这个也可以通过将zynq核的I2C接入MIO并引出实现

14.zedboard -HDMI output

zedboard专用的HDMI输出IP核,将视频数据根据ADV7511芯片的数据类型与控制时序进行转换并输出

bd总结

bd部分的内容就是这些,整体来看就是先通过vdma从ddr内读取视频数据,然后将rgb格式转换成YCrCb格式,再结合vide timing controller产生的时序将数据流转化成视频输出格式的数据,最后通过HDMI输出IP输出数据。

3.sdk设计

打开sdk,新建工程

在bsp中启用xilffs以确保可以读取SD卡,在xilffs中,将use_lfn的值设为1以确保可以读取SD卡中的较长文件名(本人主页有SD卡读取图像比较详细的文章可供参考)

 添加main.c文件,代码如下,注意读取SD卡文件中的文件名设置,要与SD卡内文件对应。

#include "stdio.h"
#include "xparameters.h"
#include "zed_iic.h"
#include "xaxivdma.h"
#include "xscugic.h"
#include "xil_cache.h"
#include "vdma_api.h"
#include "ff.h"

#define VDMA_DEVICE_ID		XPAR_AXI_VDMA_0_DEVICE_ID
#define DDR_BASE_ADDR		XPAR_PS7_DDR_0_S_AXI_BASEADDR//DDR存储空间起始地址

#define WIDTH 1920
#define HEIGHT 1080

unsigned int const  FRAME_BUFFER_ADDR =  DDR_BASE_ADDR + 0x1000000 ;//帧缓存地址

void load_sd_bmp(u8 *frame);

int main(){
	zed_iic_t hdmi_out_iic;
	zed_iic_axi_init(&hdmi_out_iic,"IIC Controller",XPAR_AXI_IIC_0_BASEADDR);

	XAxiVdma  vdma_inst;
	//配置并启动VDMA
	run_triple_frame_buffer(
			&vdma_inst,
			VDMA_DEVICE_ID,
			WIDTH,
			HEIGHT,
			FRAME_BUFFER_ADDR,
			0,
			0);

	//读取SD卡中的图片
	load_sd_bmp((u8*)FRAME_BUFFER_ADDR);

	return 0;
}

void load_sd_bmp(u8 *frame)
{
 static FATFS fatfs;
 FIL fil;
 u8 bmp_head[54];
 UINT *bmp_width,*bmp_height,*bmp_size;
 UINT br;
 int i;
 BYTE work[FF_MAX_SS];
 FRESULT status;
 //在 FatFs 模块上注册 /注销一个工作区 (文件系统对象 )
 status = f_mount(&fatfs,"",0);
 if(status != FR_OK){
 	xil_printf("volume is not FAT format\n");
 	//格式化SD卡
 	f_mkfs("", FM_FAT32, 0, work, sizeof work);
 	f_mount(&fatfs,"",0);
 }

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

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

 //读取 BMP 文件头
 f_read(&fil,bmp_head,54,&br);
 xil_printf("1.bmp head: \n\r");
 for(i=0;i<54;i++)
 {
	 xil_printf(" %x",bmp_head[i]);
 }
 //打印 BMP 图片分辨率和大小
 bmp_width = (UINT *)(bmp_head + 0x12);
 bmp_height = (UINT *)(bmp_head + 0x16);
 bmp_size = (UINT *)(bmp_head + 0x22);
 xil_printf("\n width = %d, height = %d, size = %d bytes \n\r",
 *bmp_width,*bmp_height,*bmp_size);

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

 //关闭文件
 f_close(&fil);

 Xil_DCacheFlush(); //刷新 Cache,数据更新至 DDR3 中
 xil_printf("show bmp\n\r");
}

连接开发板数据线,HDMI并插入sd卡,加载程序后屏幕成功显示图片

 terminal内输出头文件信息。

结语

GitHub上原版的工程没有SDK部分需要自己添加,这里放上本次使用的工程以供不便去GitHub上下载的读者使用。

【免费】zedboard开发板读取sd卡内图像通过HDMI显示-嵌入式文档类资源-CSDN文库

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值