当前位置: 首页 > news >正文

14.1 - VDMA彩条显示实验之固定分辨率

文章目录

  • 1 实验任务
  • 2 系统框图
  • 3 硬件设计
  • 4 软件设计

1 实验任务

本实验任务是PS端写彩条数据至DDR3内存中,然后通过PL端的VDMA IP核将彩条数据 通过HDMI接口按照1080p@60Hz的时序 输出显示。

2 系统框图

本实验是用HDMI接口固定输出1080P的彩条图,所以:

  1. rgb2lcd模块实际是rgb2dvi模块
  2. AXI GPIO不存在,因为不需要读取LCD屏幕的ID
  3. 动态时钟配置改为PLL,输出固定频率,与AXI-Interconnect不连
  4. VTC输出固定时序,与AXI-Interconnect不连
    在这里插入图片描述

3 硬件设计

注意事项:

  1. VTC的clken引脚
    • 该引脚不连接,VTC也能正常工作
    • 该引脚高电平有效(以文档为准),不要被Block Design中VTC IP核clken引脚前边的小圆圈所迷惑(将该引脚接常量,VTC不工作)
  2. rgb2dvi模块:R、G、B三个分量所在的字节位置
    • Bit[23:16] = 红,Bit[15:8] = 蓝,Bit[7:0] = 绿,即RBG
      在这里插入图片描述

4 软件设计

注意事项:

  1. PS往DDR3写入数据后,要使用Xil_DCacheFlushRange刷新;
  2. run_triple_frame_buffer函数并非只能用于三帧缓存的情况,实际1-32帧缓存均可使用该函数(取名triple可能和VDMA模式使用三帧缓存有关);ReadSetup函数和WriteSetup函数会根据VDMA配置时选择的Frame Buffers数量设置相应数量的帧缓冲区起始地址;本实验选择Frame Buffers数量=1,PS端只往DDR3中写入一帧彩条图;
  3. XAxiVdma_DmaStop函数往VDMACR寄存器的bit0写0(Run / Stop controls the running and stopping of the VDMA channel. ),当前VDMA操作完成后停止(0 = Stop – VDMA stops when current (if any) VDMA operations are complete)
/***************************** Include Files *********************************/
#include "stdio.h"
#include "xparameters.h"
#include "xstatus.h"
#include "xaxivdma.h"
#include "vdma_api.h"
#include "xil_cache.h"
#include "xuartps.h"
#include "sleep.h"
/************************** Constant Definitions *****************************/
#define VDMA_DEVICE_ID		XPAR_AXIVDMA_0_DEVICE_ID
#define IMAGE_WIDTH			1920
#define IMAGE_HEIGHT		1080
#define MEMORY_BASEADDR		XPAR_PS7_DDR_0_S_AXI_BASEADDR

#define UART_DEVICE_ID		XPAR_XUARTPS_0_DEVICE_ID
#define UART_BASEADDR    	XPAR_XUARTPS_0_BASEADDR
/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/
s32  UartPsInit(XUartPs *UartPsInstPtr, XUartPsFormat* UartFormatPtr);

void GenPureColor(u8* DestAddr, u32 ImageWidth, u32 ImageHeight);
void GenColorBar(u8* DestAddr, u32 ImageWidth, u32 ImageHeight);
/************************** Variable Definitions *****************************/
XAxiVdma VdmaInst;
XUartPs UartInst;

int FrameBufferAddr = (MEMORY_BASEADDR + 0x02000000);

XUartPsFormat UartFormat = {
		XUARTPS_DFT_BAUDRATE,     // 115200
		XUARTPS_FORMAT_8_BITS,
		XUARTPS_FORMAT_NO_PARITY,
		XUARTPS_FORMAT_1_STOP_BIT
};
/*****************************************************************************/

int main()
{
	//
	int Status;
	u8* VdmaBufferAddr = (u8*)FrameBufferAddr;
	char cmd;

	// 串口初始化
	Status = UartPsInit(&UartInst, &UartFormat);
	if (Status != XST_SUCCESS) {
		printf("UART Initialization Failed.\n");
		return XST_FAILURE;
	}

	// 写入纯色图(用于确定RGB的字节位置)
//	GenPureColor(VdmaBufferAddr, (u32)IMAGE_WIDTH, (u32)IMAGE_HEIGHT);

	// 写入彩条图
	GenColorBar(VdmaBufferAddr, (u32)IMAGE_WIDTH, (u32)IMAGE_HEIGHT);

	//
	Status = run_triple_frame_buffer(&VdmaInst, VDMA_DEVICE_ID, IMAGE_WIDTH, IMAGE_HEIGHT, FrameBufferAddr, 0, 0);
	if (Status == XST_FAILURE) {
		printf("VDMA Run Failed.\n");
	}

	//
	printf("VDMA Control Ready (s=start, q=stop):\n");

    while (1) {
        if (XUartPs_IsReceiveData(UART_BASEADDR)) {
            cmd = XUartPs_ReadReg(UART_BASEADDR, XUARTPS_FIFO_OFFSET);

            if (cmd == 's') {  // 启动VDMA
                if (XAxiVdma_DmaStart(&VdmaInst, XAXIVDMA_READ) == XST_SUCCESS) {
                	printf("VDMA Start Succeeded.\n");
                } else {
                	printf("VDMA Start Failed.\n");
                }
            }
            else if (cmd == 'q') {  // 停止VDMA
            	XAxiVdma_DmaStop(&VdmaInst, XAXIVDMA_READ);
            	printf("VDMA Stop Succeeded.\n");
            }
        }
        usleep(10000); // 降低CPU占用
    }

	//
	return 0;
}
/*****************************************************************************/
s32 UartPsInit(XUartPs *UartInstPtr, XUartPsFormat* UartFormatPtr)
{
	//
	s32 Status;
	XUartPs_Config *UartConfigPtr;

	// 查找UART配置
	UartConfigPtr = XUartPs_LookupConfig(UART_DEVICE_ID);
	if(NULL == UartConfigPtr)
	{
		return XST_FAILURE;
	}

	// 初始化UART
	Status = XUartPs_CfgInitialize(UartInstPtr, UartConfigPtr, UartConfigPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// 设置UART数据格式
	XUartPs_SetDataFormat(UartInstPtr, UartFormatPtr);

	// 设置UART操作模式
	XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_NORMAL);

	//
	return XST_SUCCESS;
}
/*****************************************************************************/
void GenPureColor(u8* DestAddr, u32 ImageWidth, u32 ImageHeight)
{
    // 禁用缓存(如果目标内存是非缓存区域)
    Xil_DCacheDisable();

    for (u32 y = 0; y < ImageHeight; y++) {
        for (u32 x = 0; x < ImageWidth; x++) {
            // 计算当前像素的内存位置(3字节/像素)
        	u32 PixelOffset = (y * ImageWidth + x) * 3;
        	u8* PixelAddr = DestAddr + PixelOffset;

            // 写入RGB三个字节
        	PixelAddr[0] = 0x00;
        	PixelAddr[1] = 0x00;
        	PixelAddr[2] = 0xff;
        }
    }

    // 如果需要,刷新缓存
    Xil_DCacheFlushRange((INTPTR)DestAddr, ImageWidth * ImageHeight * 3);

    //
    return;
}

/*****************************************************************************/
void GenColorBar(u8* DestAddr, u32 ImageWidth, u32 ImageHeight)
{
    // 定义8种颜色(R, G, B顺序)
    const u8 color_bars[8][3] = {
        {0x00, 0x00, 0x00}, // 黑
        {0xff, 0xff, 0xff}, // 白
        {0xff, 0x00, 0x00}, // 蓝
        {0x00, 0xff, 0x00}, // 绿
        {0x00, 0x00, 0xff}, // 红
        {0xff, 0xff, 0x00}, // 青
        {0xff, 0x00, 0xff}, // 紫
        {0x00, 0xff, 0xff}  // 黄
    };

    // 计算每个色条的宽度
    u32 BarWidth = ImageWidth / 8;

    // 禁用缓存(如果目标内存是非缓存区域)
    Xil_DCacheDisable();

    for (u32 y = 0; y < ImageHeight; y++) {
        for (u32 x = 0; x < ImageWidth; x++) {
            // 计算当前色条索引
        	u32 BarIndex = x / BarWidth;

            // 计算当前像素的内存位置(3字节/像素)
        	u32 PixelOffset = (y * ImageWidth + x) * 3;
        	u8* PixelAddr = DestAddr + PixelOffset;

            // 写入RGB三个字节
        	PixelAddr[0] = color_bars[BarIndex][0];
        	PixelAddr[1] = color_bars[BarIndex][1];
        	PixelAddr[2] = color_bars[BarIndex][2];
        }
    }

    // 如果需要,刷新缓存
    Xil_DCacheFlushRange((INTPTR)DestAddr, ImageWidth * ImageHeight * 3);

    //
    return;
}

相关文章:

  • 【Javascript】在canvas中加载shader着色器的方法(开箱即用)
  • 102.二叉树的层序遍历- 力扣(LeetCode)
  • JavaScript Number 对象
  • Unity中使用FMETP STREAM传输实时画面
  • python全栈-vue框架
  • Hibernate:让对象与数据库无缝对话的全自动ORM框架
  • CesiumEarth能够本地浏览的三维倾斜模型切片(3DTiles)
  • GESP2025年3月认证C++七级( 第三部分编程题(2)等价消除)
  • 图像形态学操作对比(Opencv)
  • VSCode中选择Anaconda的Python环境
  • java数组06:Arrays类
  • 数据结构--线性表
  • 让你方便快捷实现主题色切换(useCssVar)
  • 【征程 6】工具链 VP 示例中 Cmakelists 解读
  • 创建虚拟环境无法加载到pycharm当conda环境,只能为python环境
  • C语言-字符串操作函数手册:语法、技巧与经典应用
  • FreeRTOS使任务处于挂起态的API
  • 小白学习java第11天(下):多线程详解
  • MergeX亮相GTC2025:开启全球广告流量交易新篇章
  • ​asm汇编源代码之-汉字点阵字库显示程序源代码下载​
  • 学校网站建设介绍范文/seo推广和百度推广的区别
  • 静态网站怎么更新/市场营销比较好写的论文题目
  • 网站可以增加关键词吗/培训机构网站
  • 苏州网站制作的公司/nba最新交易新闻
  • 给网站做路由/餐饮最有效的营销方案
  • 网站选项按钮/哈尔滨百度搜索排名优化