qidao123.com技术社区-IT企服评测·应用市场

标题: ZYNQ条记(十九):VDMA VGA 输出分辨率可调 [打印本页]

作者: 农民    时间: 2025-5-11 02:45
标题: ZYNQ条记(十九):VDMA VGA 输出分辨率可调
版本:Vivado2020.2(Vitis)
  使命:以 VDAM IP 为焦点实现 VGA 彩条图像显示,同时支持输出分辨率可调。
  (PS 端写入彩条数据到 DDR 通过 VDMA 读取出来输出给 VGA 进行显示)
  目录
一、介绍
二、硬件设计
(1)整体系统框架
(2)VTC 配置
(3)Clock 时钟配置
(4)RGB888_to_444 
(5)连线
三、软件设计
(1)clk_wiz
(2)display_ctrl
(3)main.c
四、效果


一、介绍

        本例基于上次例程进行优化,实现 VGA 彩条图像显示的同时,支持输出分辨率可调,以满足差别视频分辨率的需求。
        参考了正点原子的例程,但有所差别,他是通过 AXI GPIO 读取 LCD装备型号 ID 判断并配置分辨率。而我使用 VGA 进行显示且大多数 VGA 显示器都支持多种分辨率输入,对于差别型号 VGA 显示器各有差别,以是就直接通过PS端主动调节输出分辨率即可。本次只设计三种 VGA 分辨率可调:640*480@60Hz、800x600@60Hz、1280*720@60Hz。
       
二、硬件设计

(1)整体系统框架

        框架和 “条记十八”内里一致,区别在于时钟IP配置为可动态调节,PS端通过 GP 接口可对其输出时钟进行配置,别的还将 RGB888_to_444 模块进行优化并封装为带 vid_io_rtl 范例接口输入的 IP核,使BD设计视图更加简洁清晰。
        基本原理、相关 IP 介绍、系统框架搭建参考:ZYNQ条记(十八):VDMA VGA彩条显示

(2)VTC 配置

        在之前配置的基础上添加 AXI-Lite 接口,如许 PS 端可以通过 GP 接口对其进行配置

(3)Clock 时钟配置

        差别分辨率像素时钟差别,以是必要对应输出差别频率的时钟,Clock IP 启用动态配置功能,可以看到 IP 增长了一组 AXI-Lite 接口。如许 PS 端可以通过 GP 接口对其输出时钟频率进行重新配置。

(4)RGB888_to_444 

        之前的 RGB888_to_444 是作为模块添加到 bd设计中,将Video Out 输出的 RGB888 数据进行截位与拼接,输出 RGB444 格式数据。为了让 bd 设计更加简洁规范,把它封装为有关带 vid_io_rtl 范例接口输入的 IP 核,以毗连 Video Out IP 的视频信号接口。
  1. `timescale 1ns / 1ps
  2. module RGB888_to_444(
  3.     input  wire         vid_hsync,  //  输入行同步信号
  4.     input  wire         vid_vsync,  //  输入场同步信号
  5.     input  wire [23:0]  RGB888,     //  24位RGB888输入 (R[23:16], G[15:8], B[7:0])
  6.     output wire         hsync,      //  输出行同步信号
  7.     output wire         vsync,      //  输出场同步信号
  8.     output wire [11:0]  RGB444      //  12位RGB444输出 (R[11:8], G[7:4], B[3:0])
  9. );
  10.     assign vsync    =   vid_vsync;
  11.     assign hsync    =   vid_hsync;
  12.     assign RGB444   =   {RGB888[23:20], RGB888[15:12], RGB888[7:4]}; // 截取RGB888各通道的高4位,组合成RGB444  
  13. endmodule
复制代码
        IP 封装以及接口定义参考:ZYNQ条记(十七):IP核封装与接口定义

(5)连线

        完成关键信号连线,连线环境如图所示:

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

三、软件设计

(1)clk_wiz

        "xclk_wiz.h" 是Vitis提供的关于时钟IP核相关的库函数头文,"clk_wiz.h" 是自己编写的用于定义时钟相关寄存器的头文件。
clk_wiz.h  :
  1. #ifndef CLK_WIZ_H_
  2. #define CLK_WIZ_H_
  3. #include "xil_types.h"
  4. #define CLK_SR_OFFSET    0x04    //Status Register
  5. #define CLK_CFG0_OFFSET  0x200   //Clock Configuration Register 0
  6. #define CLK_CFG2_OFFSET  0x208   //Clock Configuration Register 2
  7. #define CLK_CFG23_OFFSET 0x25C   //Clock Configuration Register 23
  8. void clk_wiz_cfg(u32 clk_device_id,double freq);
  9. #endif /* CLK_WIZ_H_ */
复制代码
clk_wiz.c  :
  1. #include "xclk_wiz.h"
  2. #include "clk_wiz.h"
  3. #include "xparameters.h"
  4. #define CLK_WIZ_IN_FREQ 100  //时钟IP核输入100Mhz
  5. XClk_Wiz clk_wiz_inst;       //时钟IP核驱动实例
  6. //时钟IP核动态重配置
  7. //参数1:时钟IP核的器件ID
  8. //参数2:时钟IP核输出的时钟 单位:MHz
  9. void clk_wiz_cfg(u32 clk_device_id,double freq)
  10. {
  11.         double div_factor = 0;
  12.         u32 div_factor_int = 0,dviv_factor_frac=0;
  13.         u32 clk_divide = 0;
  14.         u32 status = 0;
  15.         //初始化XCLK_Wiz
  16.         XClk_Wiz_Config *clk_cfg_ptr;
  17.         clk_cfg_ptr = XClk_Wiz_LookupConfig(clk_device_id);
  18.         XClk_Wiz_CfgInitialize(&clk_wiz_inst,clk_cfg_ptr,clk_cfg_ptr->BaseAddr);
  19.         if(freq <= 0)
  20.                 return;
  21.         //配置时钟倍频/分频系数
  22.         XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0x00000a01);  //10倍频,1分频
  23.         //计算分频系数
  24.         div_factor = CLK_WIZ_IN_FREQ * 10 / freq;
  25.         div_factor_int = (u32)div_factor;
  26.         dviv_factor_frac = (u32)((div_factor - div_factor_int) * 1000);
  27.         clk_divide = div_factor_int | (dviv_factor_frac<<8);
  28.         //配置分频系数
  29.         XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG2_OFFSET,clk_divide);
  30.         //加载重配置的参数
  31.         XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG23_OFFSET,0x00000003);
  32.         //获取时钟IP核的状态,判断是否重配置完成
  33.         while(1){
  34.                 status = XClk_Wiz_ReadReg(clk_cfg_ptr->BaseAddr,CLK_SR_OFFSET);
  35.                 if(status&0x00000001)    //Bit0 Locked信号
  36.                         return ;
  37.         }
  38. }
复制代码
(2)display_ctrl

        这一部门使用的正点原子的代码,display_ctrl.c 和.h 是用于实现 VTC 配置的,不外做了一些微调(本例没用到GPIO)。同时还有一个 lcd_modes.h 包含差别分辨率格式的时序配置参数,同样适用于 VGA 显示器。代码如下:
display_ctrl.c
  1. /************************************************************************/
  2. /*                                                                                                                                                */
  3. /*        display_ctrl.c        --        Digilent Display Controller Driver                                */
  4. /*                                                                                                                                                */
  5. /************************************************************************/
  6. /*        Author: Sam Bobrowicz                                                                                                */
  7. /*        Copyright 2014, Digilent Inc.                                                                                */
  8. /************************************************************************/
  9. /*  Module Description:                                                                                                 */
  10. /*                                                                                                                                                */
  11. /*                This module provides an easy to use API for controlling a            */
  12. /*                Display attached to a Digilent system board via VGA or HDMI.         */
  13. /*                run-time resolution setting and seamless framebuffer-swapping         */
  14. /*                for tear-free animation.                                                                                 */
  15. /*                                                                                                                                                */
  16. /*                To use this driver, you must have a Xilinx Video Timing                 */
  17. /*                 Controller core (vtc), Xilinx axi_vdma core, a Digilent                 */
  18. /*                axi_dynclk core, a Xilinx AXI Stream to Video core, and either  */
  19. /*                a Digilent RGB2VGA or RGB2DVI core all present in your design.  */
  20. /*                See the Video in or Display out reference projects for your     */
  21. /*                system board to see how they need to be connected. Digilent     */
  22. /*                reference projects and IP cores can be found at                                 */
  23. /*                www.github.com/Digilent.                                                                                 */
  24. /*                                                                                                                                                */
  25. /*                The following steps should be followed to use this driver:                */
  26. /*                1) Create a DisplayCtrl object and pass a pointer to it to                 */
  27. /*                   DisplayInitialize.                                                                                        */
  28. /*                2) Call DisplaySetMode to set the desired mode                                        */
  29. /*                3) Call DisplayStart to begin outputting data to the display        */
  30. /*                4) To create a seamless animation, draw the next image to a                */
  31. /*                   framebuffer currently not being displayed. Then call                 */
  32. /*                   DisplayChangeFrame to begin displaying that frame.                        */
  33. /*                   Repeat as needed, only ever modifying inactive frames.                */
  34. /*                5) To change the resolution, call DisplaySetMode, followed by        */
  35. /*                   DisplayStart again.                                                                                        */
  36. /*                                                                                                                                                */
  37. /*                                                                                                                                                */
  38. /************************************************************************/
  39. /*  Revision History:                                                                                                        */
  40. /*                                                                                                                                                 */
  41. /*                2/20/2014(SamB): Created                                                                                */
  42. /*                11/25/2015(SamB): Changed from axi_dispctrl to Xilinx cores                */
  43. /*                                                  Separated Clock functions into dynclk library */
  44. /*                                                                                                                                                */
  45. /************************************************************************/
  46. /*
  47. * TODO: It would be nice to remove the need for users above this to access
  48. *       members of the DisplayCtrl struct manually. This can be done by
  49. *       implementing get/set functions for things like video mode, state,
  50. *       etc.
  51. */
  52. /* ------------------------------------------------------------ */
  53. /*                                Include File Definitions                                                */
  54. /* ------------------------------------------------------------ */
  55. /*
  56. * Uncomment for Debugging messages over UART
  57. */
  58. //#define DEBUG
  59. #include "display_ctrl.h"
  60. #include "xdebug.h"
  61. #include "xil_io.h"
  62. /* ------------------------------------------------------------ */
  63. /*                                Procedure Definitions                                                        */
  64. /* ------------------------------------------------------------ */
  65. /***        DisplayStop(DisplayCtrl *dispPtr)
  66. **
  67. **        Parameters:
  68. **                dispPtr - Pointer to the initialized DisplayCtrl struct
  69. **
  70. **        Return Value: int
  71. **                XST_SUCCESS if successful.
  72. **                XST_DMA_ERROR if an error was detected on the DMA channel. The
  73. **                        Display is still successfully stopped, and the error is
  74. **                        cleared so that subsequent DisplayStart calls will be
  75. **                        successful. This typically indicates insufficient bandwidth
  76. **                        on the AXI Memory-Map Interconnect (VDMA<->DDR)
  77. **
  78. **        Description:
  79. **                Halts output to the display
  80. **
  81. */
  82. int DisplayStop(DisplayCtrl *dispPtr)
  83. {
  84.         /*
  85.          * If already stopped, do nothing
  86.          */
  87.         if (dispPtr->state == DISPLAY_STOPPED)
  88.         {
  89.                 return XST_SUCCESS;
  90.         }
  91.         /*
  92.          * Disable the disp_ctrl core, and wait for the current frame to finish (the core cannot stop
  93.          * mid-frame)
  94.          */
  95.         XVtc_DisableGenerator(&dispPtr->vtc);
  96.         /*
  97.          * Update Struct state
  98.          */
  99.         dispPtr->state = DISPLAY_STOPPED;
  100.         //TODO: consider stopping the clock here, perhaps after a check to see if the VTC is finished
  101.         return XST_SUCCESS;
  102. }
  103. /* ------------------------------------------------------------ */
  104. /***        DisplayStart(DisplayCtrl *dispPtr)
  105. **
  106. **        Parameters:
  107. **                dispPtr - Pointer to the initialized DisplayCtrl struct
  108. **
  109. **        Return Value: int
  110. **                XST_SUCCESS if successful, XST_FAILURE otherwise
  111. **
  112. **        Errors:
  113. **
  114. **        Description:
  115. **                Starts the display.
  116. **
  117. */
  118. int DisplayStart(DisplayCtrl *dispPtr)
  119. {
  120.         XVtc_Timing vtcTiming;
  121.         XVtc_SourceSelect SourceSelect;
  122.         xdbg_printf(XDBG_DEBUG_GENERAL, "display start entered\n\r");
  123.         /*
  124.          * If already started, do nothing
  125.          */
  126.         if (dispPtr->state == DISPLAY_RUNNING)
  127.         {
  128.                 return XST_SUCCESS;
  129.         }
  130.         /*
  131.          * Configure the vtc core with the display mode timing parameters
  132.          */
  133.         vtcTiming.HActiveVideo = dispPtr->vMode.width;        /**< Horizontal Active Video Size */
  134.         vtcTiming.HFrontPorch = dispPtr->vMode.hps - dispPtr->vMode.width;        /**< Horizontal Front Porch Size */
  135.         vtcTiming.HSyncWidth = dispPtr->vMode.hpe - dispPtr->vMode.hps;                /**< Horizontal Sync Width */
  136.         vtcTiming.HBackPorch = dispPtr->vMode.hmax - dispPtr->vMode.hpe + 1;                /**< Horizontal Back Porch Size */
  137.         vtcTiming.HSyncPolarity = dispPtr->vMode.hpol;        /**< Horizontal Sync Polarity */
  138.         vtcTiming.VActiveVideo = dispPtr->vMode.height;        /**< Vertical Active Video Size */
  139.         vtcTiming.V0FrontPorch = dispPtr->vMode.vps - dispPtr->vMode.height;        /**< Vertical Front Porch Size */
  140.         vtcTiming.V0SyncWidth = dispPtr->vMode.vpe - dispPtr->vMode.vps;        /**< Vertical Sync Width */
  141.         vtcTiming.V0BackPorch = dispPtr->vMode.vmax - dispPtr->vMode.vpe + 1;;        /**< Horizontal Back Porch Size */
  142.         vtcTiming.V1FrontPorch = dispPtr->vMode.vps - dispPtr->vMode.height;        /**< Vertical Front Porch Size */
  143.         vtcTiming.V1SyncWidth = dispPtr->vMode.vpe - dispPtr->vMode.vps;        /**< Vertical Sync Width */
  144.         vtcTiming.V1BackPorch = dispPtr->vMode.vmax - dispPtr->vMode.vpe + 1;;        /**< Horizontal Back Porch Size */
  145.         vtcTiming.VSyncPolarity = dispPtr->vMode.vpol;        /**< Vertical Sync Polarity */
  146.         vtcTiming.Interlaced = 0;                /**< Interlaced / Progressive video */
  147.         /* Setup the VTC Source Select config structure. */
  148.         /* 1=Generator registers are source */
  149.         /* 0=Detector registers are source */
  150.         memset((void *)&SourceSelect, 0, sizeof(SourceSelect));
  151.         SourceSelect.VBlankPolSrc = 1;
  152.         SourceSelect.VSyncPolSrc = 1;
  153.         SourceSelect.HBlankPolSrc = 1;
  154.         SourceSelect.HSyncPolSrc = 1;
  155.         SourceSelect.ActiveVideoPolSrc = 1;
  156.         SourceSelect.ActiveChromaPolSrc= 1;
  157.         SourceSelect.VChromaSrc = 1;
  158.         SourceSelect.VActiveSrc = 1;
  159.         SourceSelect.VBackPorchSrc = 1;
  160.         SourceSelect.VSyncSrc = 1;
  161.         SourceSelect.VFrontPorchSrc = 1;
  162.         SourceSelect.VTotalSrc = 1;
  163.         SourceSelect.HActiveSrc = 1;
  164.         SourceSelect.HBackPorchSrc = 1;
  165.         SourceSelect.HSyncSrc = 1;
  166.         SourceSelect.HFrontPorchSrc = 1;
  167.         SourceSelect.HTotalSrc = 1;
  168.         XVtc_SelfTest(&(dispPtr->vtc));
  169.         XVtc_RegUpdateEnable(&(dispPtr->vtc));
  170.         XVtc_SetGeneratorTiming(&(dispPtr->vtc), &vtcTiming);
  171.         XVtc_SetSource(&(dispPtr->vtc), &SourceSelect);
  172.     /*
  173.          * Enable VTC core, releasing backpressure on VDMA
  174.          */
  175.         XVtc_EnableGenerator(&dispPtr->vtc);
  176.         dispPtr->state = DISPLAY_RUNNING;
  177.         return XST_SUCCESS;
  178. }
  179. /* ------------------------------------------------------------ */
  180. /***        DisplayInitialize(DisplayCtrl *dispPtr,u16 vtcId)
  181. **
  182. **        Parameters:
  183. **                dispPtr - Pointer to the struct that will be initialized
  184. **                vtcId - Device ID of the VTC core as found in xparameters.h
  185. **
  186. **        Return Value: int
  187. **                XST_SUCCESS if successful, XST_FAILURE otherwise
  188. **
  189. **        Errors:
  190. **
  191. **        Description:
  192. **                Initializes the driver struct for use.
  193. **
  194. */
  195.   int DisplayInitialize(DisplayCtrl *dispPtr, u16 vtcId)
  196. {
  197.         int Status;
  198.         XVtc_Config *vtcConfig;
  199.         /*
  200.          * Initialize all the fields in the DisplayCtrl struct
  201.          */
  202.         dispPtr->state = DISPLAY_STOPPED;
  203.         dispPtr->vMode = VMODE_1280x720;//原代码为VMODE_800x480;
  204.         /* Initialize the VTC driver so that it's ready to use look up
  205.          * configuration in the config table, then initialize it.
  206.          */
  207.         vtcConfig = XVtc_LookupConfig(vtcId);
  208.         /* Checking Config variable */
  209.         if (NULL == vtcConfig) {
  210.                 return (XST_FAILURE);
  211.         }
  212.         Status = XVtc_CfgInitialize(&(dispPtr->vtc), vtcConfig, vtcConfig->BaseAddress);
  213.         /* Checking status */
  214.         if (Status != (XST_SUCCESS)) {
  215.                 return (XST_FAILURE);
  216.         }
  217.         return XST_SUCCESS;
  218. }
  219. /* ------------------------------------------------------------ */
  220. /***        DisplaySetMode(DisplayCtrl *dispPtr, const VideoMode *newMode)
  221. **
  222. **        Parameters:
  223. **                dispPtr - Pointer to the initialized DisplayCtrl struct
  224. **                newMode - The VideoMode struct describing the new mode.
  225. **
  226. **        Return Value: int
  227. **                XST_SUCCESS if successful, XST_FAILURE otherwise
  228. **
  229. **        Errors:
  230. **
  231. **        Description:
  232. **                Changes the resolution being output to the display. If the display
  233. **                is currently started, it is automatically stopped (DisplayStart must
  234. **                be called again).
  235. **
  236. */
  237. int DisplaySetMode(DisplayCtrl *dispPtr, const VideoMode *newMode)
  238. {
  239.         int Status;
  240.         /*
  241.          * If currently running, stop
  242.          */
  243.         if (dispPtr->state == DISPLAY_RUNNING)
  244.         {
  245.                 Status = DisplayStop(dispPtr);
  246.                 if (Status != XST_SUCCESS)
  247.                 {
  248.                         xdbg_printf(XDBG_DEBUG_GENERAL, "Cannot change mode, unable to stop display %d\r\n", Status);
  249.                         return XST_FAILURE;
  250.                 }
  251.         }
  252.         dispPtr->vMode = *newMode;
  253.         return XST_SUCCESS;
  254. }
  255. /*
  256. //获取LCD屏ID
  257. //PG6=R7(M0);PI2=G7(M1);PI7=B7(M2);
  258. //M2:M1:M0
  259. //0 :0 :0        //4.3寸480*272 RGB屏,ID=0X4342
  260. //0 :0 :1        //7寸800*480 RGB屏,ID=0X7084
  261. //0 :1 :0        //7寸1024*600 RGB屏,ID=0X7016
  262. //1 :0 :0        //4.3寸800*480 RGB屏,ID=0X4384
  263. //1 :0 :1        //10.1寸1280*800 RGB屏,ID=0X1018
  264. //返回值:LCD ID:0,非法;其他值,ID;
  265. u16 LTDC_PanelID_Read(XGpio * axi_gpio_inst,unsigned chanel)
  266. {
  267.         u32 idx=0;
  268.         idx = XGpio_DiscreteRead(axi_gpio_inst,chanel);   //读取按键数据
  269.         switch(idx)
  270.         {
  271.                 case 0:return 0x4342;                //4.3寸屏,480*272分辨率
  272.                 case 1:return 0x7084;                //7寸屏,800*480分辨率
  273.                 case 2:return 0x7016;                //7寸屏,1024*600分辨率
  274.                 case 4:return 0x4384;                //4.3寸屏,800*480分辨率
  275.                 case 5:return 0x1018;                 //10.1寸屏,1280*800分辨率
  276.                 default:return 0;
  277.         }
  278. }
  279. */
复制代码
display_ctrl.h
  1. #ifndef DISPLAY_CTRL_H_
  2. #define DISPLAY_CTRL_H_
  3. /* ------------------------------------------------------------ */
  4. /*                                Include File Definitions                                                */
  5. /* ------------------------------------------------------------ */
  6. #include "xil_types.h"
  7. #include "xvtc.h"
  8. #include "lcd_modes.h"
  9. //#include "xgpio.h"
  10. /* ------------------------------------------------------------ */
  11. /*                                        Miscellaneous Declarations                                        */
  12. /* ------------------------------------------------------------ */
  13. #define BIT_DISPLAY_RED 16
  14. #define BIT_DISPLAY_GREEN 8
  15. #define BIT_DISPLAY_BLUE 0
  16. /*
  17. * This driver currently supports frames.
  18. */
  19. #define DISPLAY_NUM_FRAMES 1
  20. /* ------------------------------------------------------------ */
  21. /*                                        General Type Declarations                                        */
  22. /* ------------------------------------------------------------ */
  23. typedef enum {
  24.         DISPLAY_STOPPED = 0,
  25.         DISPLAY_RUNNING = 1
  26. } DisplayState;
  27. typedef struct {
  28.                 XVtc vtc;                         /*VTC driver struct*/
  29.                 VideoMode vMode;         /*Current Video mode*/
  30.                 double pxlFreq;                /* Frequency of clock currently being generated */
  31.                 DisplayState state; /* Indicates if the Display is currently running */
  32. } DisplayCtrl;
  33. /* ------------------------------------------------------------ */
  34. /*                                        Procedure Declarations                                                */
  35. /* ------------------------------------------------------------ */
  36. int DisplayStop(DisplayCtrl *dispPtr);
  37. int DisplayStart(DisplayCtrl *dispPtr);
  38. int DisplayInitialize(DisplayCtrl *dispPtr,u16 vtcId);
  39. int DisplaySetMode(DisplayCtrl *dispPtr, const VideoMode *newMode);
  40. int DisplayChangeFrame(DisplayCtrl *dispPtr, u32 frameIndex);
  41. //u16 LTDC_PanelID_Read(XGpio * axi_gpio_inst, unsigned chanel);
  42. /* ------------------------------------------------------------ */
  43. /************************************************************************/
  44. #endif /* DISPLAY_CTRL_H_ */
复制代码
lcd_modes.h
  1. #ifndef LCD_MODES_H_
  2. #define LCD_MODES_H_
  3. typedef struct {
  4.         char label[64]; /* Label describing the resolution */
  5.         u32 width; /*Width of the active video frame*/
  6.         u32 height; /*Height of the active video frame*/
  7.         u32 hps; /*Start time of Horizontal sync pulse, in pixel clocks (active width + H. front porch)*/
  8.         u32 hpe; /*End time of Horizontal sync pulse, in pixel clocks (active width + H. front porch + H. sync width)*/
  9.         u32 hmax; /*Total number of pixel clocks per line (active width + H. front porch + H. sync width + H. back porch) */
  10.         u32 hpol; /*hsync pulse polarity*/
  11.         u32 vps; /*Start time of Vertical sync pulse, in lines (active height + V. front porch)*/
  12.         u32 vpe; /*End time of Vertical sync pulse, in lines (active height + V. front porch + V. sync width)*/
  13.         u32 vmax; /*Total number of lines per frame (active height + V. front porch + V. sync width + V. back porch) */
  14.         u32 vpol; /*vsync pulse polarity*/
  15.         double freq; /*Pixel Clock frequency*/
  16. } VideoMode;
  17. static const VideoMode VMODE_480x272 = {
  18.         .label = "480x272@60Hz",
  19.         .width = 480,
  20.         .height = 272,
  21.         .hps = 482,
  22.         .hpe = 523,
  23.         .hmax = 525,
  24.         .hpol = 0,
  25.         .vps = 274,
  26.         .vpe = 284,
  27.         .vmax = 286,
  28.         .vpol = 0,
  29.         .freq = 9
  30. };
  31. static const VideoMode VMODE_640x480 = {
  32.         .label = "640x480@60Hz",
  33.         .width = 640,
  34.         .height = 480,
  35.         .hps = 656,
  36.         .hpe = 752,
  37.         .hmax = 799,
  38.         .hpol = 0,
  39.         .vps = 490,
  40.         .vpe = 492,
  41.         .vmax = 524,
  42.         .vpol = 0,
  43.         .freq = 25.12
  44. };
  45. static const VideoMode VMODE_800x480 = {
  46.         .label = "800x480@60Hz",
  47.         .width = 800,
  48.         .height= 480,
  49.         .hps   = 840,
  50.         .hpe   = 968,
  51.         .hmax  = 1056,
  52.         .hpol  = 0,
  53.         .vps   = 490,
  54.         .vpe   = 492,
  55.         .vmax  = 525,
  56.         .vpol  = 0,
  57.         .freq  = 33.0
  58. };
  59. static const VideoMode VMODE_800x600 = {
  60.         .label = "800x600@60Hz",
  61.         .width = 800,
  62.         .height = 600,
  63.         .hps = 840,
  64.         .hpe = 968,
  65.         .hmax = 1055,
  66.         .hpol = 1,
  67.         .vps = 601,
  68.         .vpe = 605,
  69.         .vmax = 627,
  70.         .vpol = 1,
  71.         .freq = 40.0
  72. };
  73. static const VideoMode VMODE_1024x600 = {
  74.         .label = "1024x600@60Hz",
  75.         .width = 1024,
  76.         .height = 600,
  77.         .hps = 1164,
  78.         .hpe = 1184,
  79.         .hmax = 1344,
  80.         .hpol = 0,
  81.         .vps = 620,
  82.         .vpe = 623,
  83.         .vmax = 635,
  84.         .vpol = 0,
  85.         .freq = 50.0
  86. };
  87. static const VideoMode VMODE_1280x800 = {
  88.         .label = "1280x800@60Hz",
  89.         .width = 1280,
  90.         .height = 800,
  91.         .hps = 1360,
  92.         .hpe = 1370,
  93.         .hmax = 1440,
  94.         .hpol = 0,
  95.         .vps = 810,
  96.         .vpe = 813,
  97.         .vmax = 823,
  98.         .vpol = 0,
  99.         .freq = 70.0
  100. };
  101. static const VideoMode VMODE_1280x1024 = {
  102.         .label = "1280x1024@60Hz",
  103.         .width = 1280,
  104.         .height = 1024,
  105.         .hps = 1328,
  106.         .hpe = 1440,
  107.         .hmax = 1687,
  108.         .hpol = 1,
  109.         .vps = 1025,
  110.         .vpe = 1028,
  111.         .vmax = 1065,
  112.         .vpol = 1,
  113.         .freq = 108.0
  114. };
  115. static const VideoMode VMODE_1280x720 = {
  116.         .label = "1280x720@60Hz",
  117.         .width = 1280,
  118.         .height = 720,
  119.         .hps = 1390,
  120.         .hpe = 1430,
  121.         .hmax = 1649,
  122.         .hpol = 1,
  123.         .vps = 725,
  124.         .vpe = 730,
  125.         .vmax = 749,
  126.         .vpol = 1,
  127.         .freq = 74.25, //74.2424 is close enough
  128. };
  129. static const VideoMode VMODE_1920x1080 = {
  130.         .label = "1920x1080@60Hz",
  131.         .width = 1920,
  132.         .height = 1080,
  133.         .hps = 2008,
  134.         .hpe = 2052,
  135.         .hmax = 2199,
  136.         .hpol = 1,
  137.         .vps = 1084,
  138.         .vpe = 1089,
  139.         .vmax = 1124,
  140.         .vpol = 1,
  141.         .freq = 148.5 //148.57 is close enough
  142. };
  143. #endif /* LCD_MODES_H_ */
复制代码
        
(3)main.c

  1. #include "stdio.h"
  2. #include "xil_printf.h"
  3. #include "xparameters.h"
  4. #include "xil_cache.h"
  5. #include "xaxivdma.h"
  6. #include "vdma_api/vdma_api.h"
  7. #include "display_ctrl/display_ctrl.h"
  8. #include "xclk_wiz.h"
  9. #include "clk_wiz/clk_wiz.h"
  10. #include "sleep.h"
  11. //======================宏定义======================//
  12. #define VDMA_ID                        XPAR_AXIVDMA_0_DEVICE_ID                //VDMA器件ID
  13. #define VTC_ID                     XPAR_VTC_0_DEVICE_ID                       //VTC器件ID
  14. #define CLK_WIZ_ID      XPAR_CLK_WIZ_0_DEVICE_ID                   //时钟IP核器件ID
  15. #define DDR_BASE_ADDR   XPAR_PS7_DDR_0_S_AXI_BASEADDR        //DDR的基地址(在xparameters.h或lscript.ld查看)
  16. #define MEM_BASE_ADDR        (DDR_BASE_ADDR + 0x01000000)        //DDR中存储数据缓存的基地址(确保在堆栈已使用DDR范围之后,lscript.ld查看)
  17. #define PIXEL_BYTE                3                //一个像素数据所占字节(RGB888 3字节)
  18. //==================函数、变量声明==================//
  19. XClk_Wiz         CLK_WIZ;                                //时钟IP核实例
  20. XAxiVdma         Vdma;                                        //VDMA实例
  21. VideoMode   vd_mode;                                //lcd_modes.h中定义的结构体,包含视频分辨率格式的各个参数
  22. DisplayCtrl dispCtrl;                                //display_ctrl.h中定义的结构体,包含视频分辨率格式的各个参数
  23. static void Set_Mode(int mode);//调整输出分辨率
  24. static void Write_Colorbar();            //向DDR数据缓存区域写数据
  25. //======================主函数======================//
  26. int main()
  27. {
  28.         xil_printf("VDMA VGA Colorbar Test\r\n");
  29.         for (int i=1; i<=3; i++)
  30.         {
  31.                 //调整输出分辨率
  32.                 Set_Mode(i);
  33.                 //配置时钟IP输出频率(单位MHz)
  34.                 clk_wiz_cfg(CLK_WIZ_ID, vd_mode.freq);
  35.                 xil_printf("%u,%u",vd_mode.width,vd_mode.height);
  36.                 //配置并启动VDMA:(本例未使用中断)
  37.                 //(VDMA实例指针,器件ID,图像宽度,图像高度,帧缓存起始地址,中断帧计数(传输多少帧产生中断),中断使能,读写模式)
  38.                 run_vdma_frame_buffer(&Vdma, VDMA_ID,  vd_mode.width, vd_mode.height, (int)MEM_BASE_ADDR, 0, 0, ONLY_READ);
  39.                 //初始化dispCtrl结构体(vd_mode默认1280x720@60)、初始化VTC
  40.                 DisplayInitialize(&dispCtrl, VTC_ID);
  41.                 //设置VTC时序参数
  42.                 DisplaySetMode(&dispCtrl, &vd_mode);
  43.                 //启动VTC时序生成
  44.                 DisplayStart(&dispCtrl);
  45.                 //向DDR数据缓存区域写数据(写彩条图像)
  46.                 Write_Colorbar((u8*)MEM_BASE_ADDR , vd_mode.width, vd_mode.height);
  47.                 sleep(5); //每隔5s切换一次分辨率
  48.         }
  49.         return 0;
  50. }
  51. //=============向DDR数据缓存区域写数据==============//
  52. /*
  53. * IMG_Buffer        指针,指向图像缓存的起始地址
  54. * IMG_WIDTH        图像宽度
  55. * IMG_HIGHT        图像高度
  56. */
  57. void Write_Colorbar(u8 *IMG_Buffer, u32 IMG_WIDTH, u32 IMG_HIGHT)
  58. {
  59.     u8 RGB_r, RGB_g, RGB_b;
  60.     int x, y, addr;
  61.     int segment_width = IMG_WIDTH / 7;  // 每种颜色占1/7宽度
  62.     // 向DDR缓存区域写像素数据(RGB888)
  63.     for(y = 0; y < IMG_HIGHT; y++) {
  64.         for(x = 0; x < IMG_WIDTH; x++) {
  65.             // 根据x坐标确定颜色
  66.             if(x < segment_width * 1) {        // 红色
  67.                 RGB_r = 0xFF; RGB_g = 0x00; RGB_b = 0x00;
  68.             }
  69.             else if(x < segment_width * 2) {   // 橙色
  70.                 RGB_r = 0xFF; RGB_g = 0x4F; RGB_b = 0x00;
  71.             }
  72.             else if(x < segment_width * 3) {   // 黄色
  73.                 RGB_r = 0xFF; RGB_g = 0xBF; RGB_b = 0x00;
  74.             }
  75.             else if(x < segment_width * 4) {   // 绿色
  76.                 RGB_r = 0x00; RGB_g = 0xFF; RGB_b = 0x00;
  77.             }
  78.             else if(x < segment_width * 5) {   // 青色
  79.                 RGB_r = 0x00; RGB_g = 0xFF; RGB_b = 0xFF;
  80.             }
  81.             else if(x < segment_width * 6) {   // 蓝色
  82.                 RGB_r = 0x00; RGB_g = 0x00; RGB_b = 0xFF;
  83.             }
  84.             else {                             // 紫色
  85.                 RGB_r = 0x7F; RGB_g = 0x00; RGB_b = 0xFF;
  86.             }
  87.             addr = y * (IMG_WIDTH * PIXEL_BYTE) + x * PIXEL_BYTE;
  88.             IMG_Buffer[addr + 0] = RGB_b;  // B
  89.             IMG_Buffer[addr + 1] = RGB_g;  // G
  90.             IMG_Buffer[addr + 2] = RGB_r;  // R
  91.         }
  92.     }
  93.     // 刷新Cache,数据更新至内存
  94.     Xil_DCacheFlush();
  95.     xil_printf("Colorbar data ready\r\n");
  96. }
  97. //==================调整输出分辨率==================//
  98. void Set_Mode(int mode)
  99. {
  100.         switch(mode){
  101.                 case 1 : vd_mode = VMODE_640x480; break;
  102.                 case 2 : vd_mode = VMODE_800x600; break;
  103.                 case 3 : vd_mode = VMODE_1280x720; break;
  104.                 default : vd_mode = VMODE_1280x720; break;
  105.         }
  106. }
复制代码
四、效果

        下载后,隔断 5s 依次切换 640*480@60Hz、800x600@60Hz、1280*720@60Hz 三种分辨率进行彩条显示(gif 图片压缩后导致看起来有杂点很有点糊,实际显示器上面很清晰)



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4