ZYNQ笔记(二十一): VDMA HDMI 彩条显示

版本:Vivado2020.2(Vitis)

任务:实现驱动 HDMI 显示彩条图像,同时支持输出给 HDMI 的图像分辨率可调。

目录

一、介绍

二、硬件设计

(1)DVI_Transmitter

[(2)Clocking Wizard](#(2)Clocking Wizard)

[(3)整体 BD 设计](#(3)整体 BD 设计)

三、软件设计

四、效果


一、介绍

这次的笔记没有之前其他的笔记写的那么详细(东拼西凑写出来的,有点潦草),其实也是主要是将前面笔记中知识加以运用。

二、硬件设计

硬件设计和之前 VGA 彩条显示几乎一样,区别在于是将最后的 RGB888_to_444 模块转为了可以产生 HDMI 视频信号时序的 DVI_Transmitter 模块、同时 Clocking Wizard 多添加了一个时钟输出用于驱动 DVI_Transmitter 模块。

之前的系统搭建和软件部分设计可参考:ZYNQ笔记(十九):VDMA VGA 输出分辨率可调、ZYNQ笔记(十八):VDMA VGA彩条显示

(1)DVI_Transmitter

这个是用的正点原子的模块,内容很多实在懒得写了.....,将模块封装为 IP 核之后就可以在 BD 设计中使用了,这个在前面的笔记也有提到过:ZYNQ笔记(十七):IP核封装与接口定义

(2)Clocking Wizard

要支持输出给 HDMI 的图像分辨率可调,所以输出像素时钟需要通过 PS 端进行动态配置,因为驱动 DVI_Transmitter 模块需要两个时钟,一个像素时钟和一个5倍像素时钟,所以要同时配置两时钟输出,同样在前面的笔记有做介绍:ZYNQ笔记(二十):Clocking Wizard 动态配置

(3)整体 BD 设计

最后整体 bd 设计部分如图所示:设计检查、Generate Output Products、 Create HDL Wrapper、管脚约束、Gnerate Bitstream、Export Hardware(包含比特流文件)、启动Vitis

(标橙的模块是本次例程相较于 VGA 彩条显示有改动的地方)

三、软件设计

mian.c

cs 复制代码
#include "stdio.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_cache.h"
#include "xaxivdma.h"
#include "vdma_api/vdma_api.h"
#include "display_ctrl/display_ctrl.h"
#include "xclk_wiz.h"
#include "clk_wiz/clk_wiz.h"
#include "sleep.h"

//======================宏定义======================//

#define VDMA_ID			XPAR_AXIVDMA_0_DEVICE_ID		//VDMA器件ID
#define VTC_ID     		XPAR_VTC_0_DEVICE_ID       		//VTC器件ID
#define CLK_WIZ_ID      XPAR_CLK_WIZ_0_DEVICE_ID   		//时钟IP核器件ID
#define DDR_BASE_ADDR   XPAR_PS7_DDR_0_S_AXI_BASEADDR	//DDR的基地址(在xparameters.h或lscript.ld查看)
#define MEM_BASE_ADDR	(DDR_BASE_ADDR + 0x01000000)	//DDR中存储数据缓存的基地址(确保在堆栈已使用DDR范围之后,lscript.ld查看)
#define PIXEL_BYTE		3		//一个像素数据所占字节(RGB888 3字节)

//==================函数、变量声明==================//

XAxiVdma 	Vdma;					//VDMA实例
VideoMode   vd_mode;				//lcd_modes.h中定义的结构体,包含视频分辨率格式的各个参数
DisplayCtrl dispCtrl;				//display_ctrl.h中定义的结构体,包含视频分辨率格式的各个参数

static void Set_Mode(int mode);//调整输出分辨率
static void Write_Colorbar();    	//向DDR数据缓存区域写数据

//======================主函数======================//
int main()
{
	xil_printf("VDMA HDMI Colorbar Test\r\n");

	//设置输出分辨率
	Set_Mode(3);//VMODE_1280x720;
	xil_printf("Width: %u, Height: %u\r\n", vd_mode.width, vd_mode.height);

	//配置时钟IP输出频率(单位MHz)(第二个5倍像素时钟给DVI转换模块)
	clk_wiz_cfg(CLK_WIZ_ID, vd_mode.freq , (vd_mode.freq)*5);

	//配置并启动VDMA:(本例未使用中断)
	//(VDMA实例指针,器件ID,图像宽度,图像高度,帧缓存起始地址,中断帧计数(传输多少帧产生中断),中断使能,读写模式)
	run_vdma_frame_buffer(&Vdma, VDMA_ID,  vd_mode.width, vd_mode.height, (int)MEM_BASE_ADDR, 0, 0, ONLY_READ);

	//初始化dispCtrl结构体(vd_mode默认1280x720@60)、初始化VTC
	DisplayInitialize(&dispCtrl, VTC_ID);
	//设置VTC时序参数
	DisplaySetMode(&dispCtrl, &vd_mode);
	//启动VTC时序生成
	DisplayStart(&dispCtrl);

	//向DDR数据缓存区域写数据(写彩条图像)
	Write_Colorbar((u8*)MEM_BASE_ADDR , vd_mode.width, vd_mode.height);

	return 0;
}

//=============向DDR数据缓存区域写数据==============//
/*
 * IMG_Buffer	指针,指向图像缓存的起始地址
 * IMG_WIDTH	图像宽度
 * IMG_HIGHT	图像高度
 */
void Write_Colorbar(u8 *IMG_Buffer, u32 IMG_WIDTH, u32 IMG_HIGHT)
{
    u8 RGB_r, RGB_g, RGB_b;
    int x, y, addr;
    int segment_width = IMG_WIDTH / 7;  // 每种颜色占1/7宽度
    // 向DDR缓存区域写像素数据(RGB888)
    for(y = 0; y < IMG_HIGHT; y++) {
        for(x = 0; x < IMG_WIDTH; x++) {
            // 根据x坐标确定颜色
            if(x < segment_width * 1) {        // 红色
                RGB_r = 0xFF; RGB_g = 0x00; RGB_b = 0x00;
            }
            else if(x < segment_width * 2) {   // 橙色
                RGB_r = 0xFF; RGB_g = 0x4F; RGB_b = 0x00;
            }
            else if(x < segment_width * 3) {   // 黄色
                RGB_r = 0xFF; RGB_g = 0xBF; RGB_b = 0x00;
            }
            else if(x < segment_width * 4) {   // 绿色
                RGB_r = 0x00; RGB_g = 0xFF; RGB_b = 0x00;
            }
            else if(x < segment_width * 5) {   // 青色
                RGB_r = 0x00; RGB_g = 0xFF; RGB_b = 0xFF;
            }
            else if(x < segment_width * 6) {   // 蓝色
                RGB_r = 0x00; RGB_g = 0x00; RGB_b = 0xFF;
            }
            else {                             // 紫色
                RGB_r = 0x7F; RGB_g = 0x00; RGB_b = 0xFF;
            }
            addr = y * (IMG_WIDTH * PIXEL_BYTE) + x * PIXEL_BYTE;
            IMG_Buffer[addr + 0] = RGB_b;  // B
            IMG_Buffer[addr + 1] = RGB_g;  // G
            IMG_Buffer[addr + 2] = RGB_r;  // R
        }
    }
    // 刷新Cache,数据更新至内存
    Xil_DCacheFlush();
    xil_printf("Colorbar data ready\r\n");
}

//==================调整输出分辨率==================//
void Set_Mode(int mode)
{
	switch(mode){
		case 1 : vd_mode = VMODE_640x480; 	break;
		case 2 : vd_mode = VMODE_800x600;	break;
		case 3 : vd_mode = VMODE_1280x720; 	break;
		default: vd_mode = VMODE_1280x720; 	break;
	}
	xil_printf("Width: %u, Height: %u\r\n", vd_mode.width, vd_mode.height);
}

四、效果

彩条都是一样的,只是分辨率不一样,不过我的显示器上调出当前参数,只有频率对不上,都是相较于我的输出格式提高了,可能是因为显示器(我的显示器支持 2K 240Hz)对于低分辨率的输入做了帧率优化。不过分辨率肯定是没问题的:

640*480分辨率:

800*600分辨率:

1280*720分辨率:

相关推荐
起个网名真难~30 分钟前
STM32F103_Bootloader_从零到UART升级成功_博客原稿
stm32·单片机·嵌入式硬件
揣一尾游鱼yu1 小时前
Spring上(IOC)笔记
java·笔记·spring·ioc
小李不想当小白3 小时前
BKP备份寄存器与RTC实时时钟(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
瑞码空间5 小时前
JSP与Servlet核心开发与CRUD实战笔记
java·笔记·servlet·jsp
La Pulga5 小时前
【FreeRTOS源码学习笔记】链表的实现
数据结构·笔记·stm32·mcu·链表·嵌入式·freertos
wuyoutrans8 小时前
以色列专利OA答复翻译,重点要避开哪些坑?
笔记
宝绿特塑业再生科技8 小时前
HDPE再生颗粒户外家具表面粉化机理与改性技术全解析
笔记·户外家具·再生塑料·塑木桌椅
铅笔小新z8 小时前
【stm32】WWDG(窗口看门狗)
stm32·单片机·嵌入式硬件
凉、介8 小时前
深入理解 ARMv7-A | Generic Timer
笔记·学习·嵌入式·arm
n 55!w !1089 小时前
MySQL笔记整理2
数据库·笔记·mysql