ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Zynq视频输出通路实战:VDMA+VTC+AXI4-Stream Video Out搭建与调试

Zynq视频输出通路实战:VDMA+VTC+AXI4-Stream Video Out搭建与调试 这一篇是Zynq PS-SDK系列的第十二篇话题终于轮到视频输出通路了。很多人玩Zynq到一定阶段都会遇到一个坎PS侧已经能用DDR存数据了PL侧也能跑逻辑了但怎么把一幅图像真正送到显示器上答案通常绕不开VDMA、VTC、AXI4-Stream to Video Out这三个IP的组合。先说清楚这条通路是干嘛的。VDMA负责把DDR里的帧数据读到AXI4-Stream总线上VTC负责产生行场同步时序AXI4S-VideoOut则把Stream总线的数据包和VTC的时序打包成标准的并行视频信号比如RGB888VsyncHsyncDE。这三个IP串起来就构成了一条“DDR→VDMA→AXI4S→VideoOut→屏幕”的完整视频输出链路。这篇文章适合两类人一类是刚开始在Vivado里搭视频通路、对着IP配置界面一头雾水的初学者另一类是已经能跑通demo但想彻底搞懂每根连线、每个参数为什么这么设的开发者。我会从整体方案讲到Block Design连线再到SDK驱动框架最后把实际调试中容易踩的坑全部列出来。硬核内容偏多建议收藏后对着工程逐步操作。1. 总体方案一条视频通路是怎么被拆解的1.1 三个IP的分工与数据流拿到一个视频输出需求先别急着连线把数据流理清比什么都重要。我的习惯是画一张简单的数据流向图PS侧通过DDR控制器在内存里放好一帧RGB图像数据VDMA通过AXI4-HP口把DDR里的数据搬出来转换成AXI4-Stream时序送到VideoOut IPVTC作为独立的时序发生器输出Vsync、Hsync、Active Video等信号给VideoOutVideoOut把带同步信号的数据封装成并行像素输出最后经电平转换芯片如HDMI transmitter送到屏幕。这个架构之所以经典是因为它把“数据搬运”和“时序产生”两个职责完全解耦了。VDMA只关心数据怎么搬不关心屏幕是什么分辨率VTC只管时序不关心数据内容。换分辨率时只需要改VTC参数和VDMA的帧宽高配置不需要动数据通路逻辑。这就是硬件模块化的价值每个IP只做一件事但组合起来能覆盖所有常见的视频输出场景。1.2 为什么选VDMA而不是直接读写DDR有人可能会问我直接在PL里写一个AXI Master逻辑去读DDR不行吗当然可以但你要自己处理DDR控制器带宽调度、不同行之间的地址跳变、帧中断和同步逻辑。VDMA把这些全部封装好了它支持一维和二维DMA传输能直接把一帧图像中非连续地址的矩形区域搬出来还带有帧同步寄存器、软化复位、GenLock同步等机制。用一个成熟的IP替换数千行自研代码工程风险低太多。VTC和VideoOut的组合也有讲究。有些方案会直接选择AXI4-Stream to Video Out内部自带的一个简单时序生成逻辑但那个只适合固定分辨率最简单的场景可配置性很差。单独加一个VTC的好处是分辨率可以通过寄存器实时改甚至可以在运行中动态切换时序这在做多分辨率自适应的时候是关键能力。1.3 数据格式与尺寸规划搭建之前先想清楚你最终输出的视频格式。最常见的1080p60、24位RGB、像素时钟148.5MHz。DDR里一帧数据量是1920×1080×3字节约6.22MB60帧时带宽需要373MB/s左右。Zynq-7000的HP口能提供足够带宽DDR3跑个533MHz完全无压力但必须走HP口而不是GP口GP口理论带宽会卡脖子。数据位宽的规划也影响后续连线AXI4-Stream的总线宽度可以是64bit、32bit而VideoOut的像素接口往往是24bit。VDMA会把64bit数据按字节流拆分VideoOut再从流里还原成像素。只要字节序和后端接口颜色分量顺序一致一般不会出问题。色彩顺序常见的有RGB888、BGR888、YUV422等选RGB888最省事。2. Block Design硬件搭建实战2.1 工程准备与IP清单我用的环境是Vivado 2021.2Zynq-7020或7010都可以。新建一个RTL工程后创建Block Design需要添加的IP清单如下ZYNQ7 Processing SystemAXI VDMAVideo Timing ControllerAXI4-Stream to Video OutAXI GPIO用于复位和状态监测可选但推荐Processor System Reset帮助管理复位时钟生成器Clocking Wizard用于产生像素时钟这些IP在Vivado的IP Catalog里都能直接搜到不需要额外安装第三方库。需要注意IP版本与Vivado版本的匹配关系2021.2版本里VDMA是6.3、VTC是6.2、VideoOut是1.1版本差异一般不影响功能但连线端口名称有细微差别参考本文时请注意对比自己的版本。2.2 PS侧配置要点双击ZYNQ7 Processing System进行配置。关键点是使能HP0和HP1两个Slave AXI接口其中HP0用于VDMA读取DDR数据HP1可以留给VDMA的S2MM通道或者留着做其他用途。如果你只是视频输出可以让VDMA的MM2S通道走HP0。PS侧还有一个需要关注的配置是DDR型号的选择。选错DDR颗粒会导致启动阶段内存测试失败或带宽异常必须和你板子上的DDR颗粒对应。Zynq-7020开发板常用的是MT41K256M16HA-125也可以选择EZ-010等预设。FCLK_CLK0分配100MHz用于AXI总线和外设时钟FCLK_CLK1可选用于VideoOut的Axis时钟或另作他用。2.3 VDMA参数配置详解VDMA的配置界面是整个工程里最容易把人绕晕的地方。先从基本选项说起Address Width选择32Burst Size选16Memory Map Data Width选64Stream Data Width选择32或24。这里有个关键点Stream Data Width代表的是AXI4-Stream总线一次传输的字节数如果选64bitVideoOut那边也要匹配64bit否则会数据错位。实际项目中我习惯选32bit配合1080p是刚刚好的带宽。Frame Buffers选3这个数量直接影响后续上层软件能实现几缓冲。3代表三缓冲可以避免撕裂但会增加DDR占用一帧6.22MB三帧约18.7MB对7020的DDR容量来说完全没有压力。如果只写一帧静态图像选2或3都行但为了以后动画显示不撕裂推荐直接选3。使用高级选项的Sync Parameters里启用GenLock和Frame Counter工作模式设为Master这样VDMA能输出帧完成中断。如果做帧同步还需要把Completion Interrupt和Error Interrupt都打开方便软件调试。垂直尺寸和水平尺寸先随便填比如1920和1080后面SDK运行时会用寄存器动态配置但提前填上能让仿真阶段更直观。2.4 VTC时序参数配置VTC配置界面比较直观左边是主要视频时序参数Activate Generation选项要勾选。水平同步脉冲、水平后沿、水平有效像素、水平前沿垂直方向也对应设置。以1920×108060为例典型参数如下水平有效像素1920水平后沿148水平同步脉冲44水平前沿88垂直有效行数1080垂直后沿36垂直同步脉冲5垂直前沿4这些参数来源于VESA标准不是随便填的。把水平总周期加起来就是220019201484488垂直总周期是112510803654时钟频率148.5MHz刷新率等于148.5MHz÷2200×1125≈60Hz。你可以用任意分辨率只要保持“像素时钟总周期×刷新率”这个关系即可例如720p60的像素时钟是74.25MHz总周期是1650×750。VTC还有个关键选项是极性设置Active High还是Active Low。默认情况下VESA标准常用负极性行场同步Active Low但很多HDMI transmitter芯片要求正极性Active High这个必须要查后端芯片的数据手册。错误极性会导致屏幕直接不同步或图像偏移是排查“黑屏”问题时最容易被忽略的原因之一。2.5 AXI4-Stream to Video Out参数配置这个IP的配置界面相对简单但有一个选择至关重要在“Interface”选项里选择Stream Data Width我选24bit。另外一个关键下拉菜单是“Clock Mode”或“Timing Mode”必须选“Independent”或“External”这决定了由外部VTC输入时序而不是内部生成。具体来说AXI4-Stream to Video Out有两种工作方式内置时序逻辑和外接VTC。内置模式只支持固定简单的时序最多满足调试需求要做正经的视频输出你需要在Block Design里把VTC的输出连接到VideoOut的vtc_hsync、vtc_vsync、vtc_active_video等输入端口。VideoOut内部会把这些时序信号转换成最终的video_vs、video_hs、video_de、video_active和像素总线。颜色分量映射也需要提前规划AXI4S-VideoOut输入的数据字节序与输出像素的R、G、B分量有固定对应关系一般用RGB888顺序不会有问题。但如果你在PS侧把像素按BGR顺序填的就会看到红蓝交换的现象这个在调试时可以通过交换像素数据的高低位或改变填充顺序来修复。2.6 完整连线与地址分配IP添加完毕后在Block Design里需要完成以下关键连线PS的M_AXI_GP0连接到VDMA/M_AXI_S2MM和VTC/M_AXI_Lite的S_AXI_LITE端口PS的S_AXI_HP0连接到VDMA的M_AXI_MM2S端口用于DDR数据读取VDMA的M_AXIS_MM2S连接到VideoOut的S_AXISVTC的生成时序输出连接到VideoOut的vtc_*输入端口PS的FCLK_CLK0连接所有IP的AXI时钟并且连接Processor System Reset的slowest_sync_clk像素时钟来自Clocking Wizard的107.5MHz或148.5MHz输出连接VTC的clk和VideoOut的像素时钟端口同时也要连接VDMA如果需要走视频时钟域需要谨慎处理地址分配在Address Editor中进行VDMA和VTC的lite接口分别分配范围比如0x43000000和0x44000000GPIO可以放在0x43010000之类的位置。地址冲突会导致SDK无法正确读写寄存器很基础但值得反复检查。连线时注意VDMA的m_axi_mm2s_aclk、s_axi_lite_aclk与VideoOut的axis_aclk来自不同时钟域时必须确保两个时钟域之间的握手逻辑能正确工作。VDMA内部已经做了跨时钟域处理你只需要在Block Design里把m_axi_mm2s_aclk连到与DDR交互的时钟一般是PL0或FCLK_CLK0的100MHz把axis_aclk连到像素时钟域VTC则和VideoOut共用像素时钟。3. 时钟与复位最容易出事的隐藏细节3.1 像素时钟从哪里来视频通路的时钟是整个系统能否正常工作的基石。1080p60的像素时钟是148.5MHz这个频率必须稳定。如果板载晶振是50MHz或100MHz需要用Clocking Wizard配置MMCM/PLL来倍频输入时钟选开发板的PL时钟通常是50MHz或100MHz分频系数要算清楚比如100MHz输入倍频到297MHz再二分频得到148.5MHz。VTC和VideoOut都应用像素时钟作为工作时钟。这里要特别提醒VideoOut的axis_aclk与像素时钟之间允许异步跨时钟域但时序必须保证AXI4-Stream的tready/tvalid能够正确握手。如果你在调试时发现数据不通优先检查两个时钟的频率比例是否符合预期通常是成倍数关系否则会因轴向总线吞吐量不足导致丢帧或卡死。3.2 复位层次的规划复位信号的处理一定要按层次来。PS侧的复位一般由FCLK产生经过Processor System Reset IP同步后输出peripheral_aresetn给AXI Lite外设输出interconnect_aresetn给AXI互联而像素时钟域的复位则应该由Clocking Wizard的locked信号再通过Processor System Reset同步后产生。直接用一个全局复位扔到所有时钟域里都是不规范的很容易出现复位释放时时钟还没稳定的情况。VDMA、VTC和VideoOut各自都有aresetn引脚全部按对应时钟域接好复位。推荐加一个AXI GPIO挂到PS总线上GPIO输出的bit0控制VDMA的soft reset触发bit1控制VTC的下载时序使能。这样SDK里就可以灵活控制IP的启动顺序调试也方便。3.3 跨时钟域的实战心得视频输出通路里至少存在三个时钟域AXI Lite总线时钟通常是100MHz、DDR访问时钟与FCLK或HP口interconnect相关、像素时钟148.5MHz。VDMA作为跨时钟域的核心节点内部已经做了缓冲但你仍然需要确保连接正确——不要把VTC的clk连成AXI Lite时钟否则时序参数会完全错乱。我在另一个项目里犯过一个隐蔽错误VTC和VideoOut的clk接的是同一个像素时钟但VideoOut的reset没有同步到这个时钟域导致上电后第一次同步时序永远起不来。后来每次上电都先用PS复位一下VideoOut才勉强能用。直到改为Processor System Reset分域复位后问题彻底消失。复位同步问题在视频设计里非常常见排查时建议用ILA观察resetn引脚的释放时序。4. SDK裸机驱动与框架代码分析4.1 软件初始化顺序硬件通路搭好了接下来要让PS跑起来控制这条通路。裸机环境中我的初始化顺序如下这套顺序经过多个项目验证能最大程度避免启动闪烁和时序混乱初始化UART打印初始化VDMA驱动XAxiVdma_Initialize初始化VTC驱动XVtc_Initialize将配置写入VTC并勾选生成使能初始化VideoOut驱动XVideo_Out_Initialize配置VDMA使能MMA2S通道设置帧地址使能VDMA开始传输检查VTC Locked状态和VideoOut FIFO状态千万不要先启动VDMA再初始化VTC这样在时序尚未建立时视频数据就会涌入可能导致VideoOut内部FIFO溢出或同步信号错位。先把“节拍器”准备好再让“搬运工”干活顺序非常关键。4.2 VDMA驱动关键代码VDMA驱动属于Xilinx标准驱动库初始化代码比较简单。常用函数是XAxiVdma_Initialize和XAxiVdma_StartWriteTransfer前者通过设备ID获取设备句柄后者启动DMA传输。一个容易忽略的细节是往VDMA寄存器写入帧地址之前必须确保数据已经在DDR中准备好并且CPU的Cache已经刷新到内存。具体来说Zynq的CPU和DDR之间的Cache一致性是由Snoop Control Unit管理的但你如果没有将DDR区域配置为非CacheableCPU写入的帧数据可能仍然滞留在L1或L2 Cache中VDMA从DDR读取的将是旧数据导致花屏。解决办法有两种用Xil_DCacheFlushRange()显式flush或者用Xil_SetTlbAttributes()配置地址范围为非缓存。我的习惯是每次更新完帧数据都调用Xil_DCacheFlushRange()简单可靠。#include xaxivdma.h XAxiVdma Vdma; XAxiVdma_Config *VdmaConfig; u32 FrameAddr[3]; int Vdma_Init(XAxiVdma *VdmaPtr) { VdmaConfig XAxiVdma_LookupConfig(XPAR_AXI_VDMA_0_DEVICE_ID); int Status XAxiVdma_CfgInitialize(VdmaPtr, VdmaConfig); if (Status ! XST_SUCCESS) return XST_FAILURE; XAxiVdma_DmaSetup SetupConfig; SetupConfig.VertSizeInput 1080; SetupConfig.HoriSizeInput 1920 * 3; // 每行字节数必须是64bit对齐 SetupConfig.Stride 1920 * 3; SetupConfig.FrameDelay 0; SetupConfig.EnableCircularBuf 1; SetupConfig.EnableSync 0; SetupConfig.PointNum 0; SetupConfig.EnableFrameCounter 1; SetupConfig.FrameStoreNum 3; XAxiVdma_DmaConfig(VdmaPtr, XAXIVDMA_READ, SetupConfig); XAxiVdma_DmaSetBufferAddr(VdmaPtr, XAXIVDMA_READ, FrameAddr); XAxiVdma_DmaStart(VdmaPtr, XAXIVDMA_READ); }补充一点HoriSizeInput填的是每行总字节数不是像素数。如果是1920×1080的RGB888每像素3字节每行5760字节配置时填5760但如果DMA的Memory Map Data Width是64bit8字节内部会自动做对齐处理你的行字节数不需要手动对齐可又要注意Stride与实际行宽一致。Stride默认等于HoriSizeInput遇到有边界对齐需求时再单独设置。4.3 VTC与VideoOut驱动要点VTC驱动的核心工作机制是把之前Block Design里配置的时序参数变成寄存器写入然后启动生成器。裸机驱动里常用XVtc_Initialize、XVtc_RegUpdate、XVtc_GeneratorEnable这几个接口。配置的时序结构体位域较多建议参考Vivado生成的xttc.h头文件的注释。#include xvtc.h XVtc Vtc; XVtc_Config *VtcConfig; XVtc_Timing VtcTiming; int Vtc_Init(XVtc *VtcPtr) { VtcConfig XVtc_LookupConfig(XPAR_VTC_0_DEVICE_ID); int Status XVtc_CfgInitialize(VtcPtr, VtcConfig, VtcConfig-BaseAddress); if (Status ! XST_SUCCESS) return XST_FAILURE; memset(VtcTiming, 0, sizeof(VtcTiming)); VtcTiming.HActiveVideo 1920; VtcTiming.HFrontPorch 88; VtcTiming.HSyncWidth 44; VtcTiming.HBackPorch 148; VtcTiming.VActiveVideo 1080; VtcTiming.VFrontPorch 4; VtcTiming.VSyncWidth 5; VtcTiming.VBackPorch 36; VtcTiming.HSyncPolarity 0; VtcTiming.VSyncPolarity 0; VtcTiming.VBlankH0 0; VtcTiming.VBlankH1 0; VtcTiming.VBlankV0 0; VtcTiming.VBlankV1 0; VtcTiming.VSyncH0 0; VtcTiming.VSyncH1 0; VtcTiming.VSyncV0 0; VtcTiming.VSyncV1 0; XVtc_SetGeneratorTiming(VtcPtr, VtcTiming); XVtc_RegUpdate(VtcPtr); XVtc_GeneratorEnable(VtcPtr); }关键点在于HSyncPolarity和VSyncPolarity这两个字段0表示Active Low负极性1表示Active High正极性。请务必对照后端芯片手册否则一切看起来都正常但屏幕就是不亮。VideoOut驱动的核心是配置同步信号来源和时钟选择。使用XVideo_Out_Initialize和XVideo_Out_Start两个接口即可。需要注意VideoOut内部有个FIFO用于缓冲Stream数据与同步时序之间的速率差启动时最好检查XVideo_Out_GetVBlankStatus和XVideo_Out_IsIdle等状态确保没有溢出。4.4 双缓冲与帧中断如果只是在屏幕显示一张静态图片按上面的初始化流程就够了。但要做动态图像刷新必须引入帧中断和双缓冲或三缓冲。VDMA的帧完成中断号连接到PS的GIC中断控制器在SDK里注册中断回调在回调函数里更新下一个显示帧地址。具体思路是两个DDR缓冲区A和BGPU或CPU先画到A然后设置VDMA当前读B下一帧读A同时删除中断标志。这样每一帧都在前一次中断完成后才更换显示地址能有效避免撕裂。初始化三个缓冲的目的是让“绘制缓冲”“显示缓冲”“传输缓冲”互相错开内存足够时建议直接三缓冲省去很多同步烦恼。需要注意中断处理函数里尽量不要做耗时的绘图操作只做标志位设置和地址切换。绘图的耗时可能会超过一帧时间16.6ms如果绘图太慢即使双缓冲也会出现跳帧卡顿。中断中切换到新地址时要确保该地址的像素数据已经全部绘制完成并且刷过Cache否则会出现部分行显示旧数据、部分行显示新数据的半帧撕裂问题。5. 常见问题与排查技巧实录5.1 屏幕完全没有信号这种情况优先检查的是硬件输出引脚是否连接到正确的物理接口。比如输出RGB信号后接入HDMI transmitter你需要确认VideoOut输出的行场和DE信号都正确连接且transmitter配置为正确的输入模式。如果以上无误再查VTC是否Locked以及它的时序参数是否与像素时钟匹配。如果VTC处于Unlocked状态说明它没有持续产生或锁定时序常见原因有像素时钟丢失、复位未释放、VTC的Active Generation没使能。还有一个高频失误是VTC的axi_lite时钟与它自己的clk不在同一时钟域导致读写寄存器时无法响应。用ILA在线观测vtc_*输出端口是否有时序波形是最直接的判断手段。5.2 花屏、错位、颜色混乱花屏的排查思路从数据链路入手。第一看VDMA读到的数据是否正确可以在SDK里用简单的自增模式填充DDR填满0x00到0xFF显示出来应该是渐变条纹否则就说明数据写入端或VDMA配置有问题。第二看数据位宽是否匹配VDMA的Stream Data Width和VideoOut的Stream Data Width必须一致不一致会出现数据左移或错位。颜色混乱一般是字节序问题。AXI4-Stream传输是以字节为最小单元的VDMA从DDR读数据时按字节顺序组装VideoOut再把字节流映射为像素分量。如果PS填充的像素顺序是R,G,B而VideoOut内部映射也是R,G,B那颜色正常反过来就是红蓝互换。这个问题修改起来很简单但排查起来费神。我习惯在PS侧填充一个已知颜色的像素矩阵比如一个纯红色矩形用来快速判断颜色分量是否正确。5.3 图像撕裂与抖动的处理撕裂的本质是屏幕扫描显示帧数据时数据源正在更新。双缓冲如果切换时机不对同样会出现撕裂。根本解决方法是利用VDMA的帧中断来同步更新让绘图和显示严格交替。有些人切换到新缓冲时会在中断回调里先更新地址再清除中断标志这样没问题关键是确保地址更新在显示扫描的消隐期内完成否则仍然会撕裂。抖动闪烁更多是时序问题。VTC输出不同步或VideoOut内部FIFO空/满溢出会导致画面闪烁或滚动。检查FIFO残留量大小时可以用XVideo_Out_GetFIFOLevel这类接口获取状态。如果FIFO持续溢出说明VDMA传输速率不够或带宽被其他AXI主设备抢占需要提高DDR优先级或调整VDMA Burst Size。5.4 常见问题速查表现象最可能原因排查方法完全黑屏VTC未锁定/极性错误查看VTC Locked位核对HSync/VSync极性黑屏但有背光DE信号没有输出观察video_de引脚有无脉冲检查VTC ActiveVideo配置花屏AXI位宽不匹配检查VDMA与VideoOut的Stream Width是否一致红蓝交换字节序映射错误在PS填充纯色测试图确认RGB分量顺序画面上下跳动垂直时序参数有误核对VTC的VActive/VSync/VBackPorch等参数左右切割水平时序参数有误核对HActive/HSync/HBackPorch等参数画面缓慢滚动像素时钟与VTC总周期不匹配计算刷新率是否整数检查时钟分频配置偶发撕裂缓冲切换与VSync不同步使用帧中断并在消隐期切换地址5.5 Cache一致性这个老生常谈的坑Zynq在PS侧写DDR数据给PL外设时Cache一致性是绕不开的话题。如果你发现图片更新后屏幕显示还是旧内容大概率是DDR里的数据还被CPU Cache缓存着VDMA读到的是缓存里尚未写回内存的旧数据。每一次帧填充完不要忘记调用Xil_DCacheFlushRange。如果你的图形生成代码是在PL里完成并直接写DDR的那不需要flush但将DMA写入区域配置为Non-Cacheable可以一劳永逸避免此问题。使用Xil_SetTlbAttributes((u32)FrameAddr, 0x14c0)可以把页面设置为不缓存Memory, Device属性但要注意地址必须是4KB对齐并且会影响同一页面内的其他数据。工程上我更推荐显式flush简单明确不引入额外的地址管理复杂度。6. 后续扩展方向6.1 动态分辨率切换有不少场景需要让视频输出支持多分辨率比如输出接口接的是HDMI显示器用户可能切换1080p到720p。这个系统可以做到在SDK里重新调用XVtc_SetGeneratorTiming设置新参数同时修改VDMA的宽高和Stride。但需要注意修改VTC参数后必须重新等待VTC Locked再启动VDMA传输否则会出现几帧错乱。像素时钟也需要软件可配置。Clocking Wizard支持动态重配置通过它的Dynamic Reconfig端口可以用AXI4-Lite接口修改MMCM/PLL参数。这一块实现起来复杂度不低但如果产品需求明确支持多分辨率就必须把像素时钟切换纳入软件管理流程。6.2 多图层叠加与OSD如果要做菜单叠加或者OSD字幕可以在视频通路上串联一个AXI4-Stream的Mux/Blend IP。最简单的做法是VDMA输出视频流、另一个小VDMA输出OSD流经过一个Alpha Blender IP混合后送入VideoOut。把OSD图层做成RGBA格式通过VDMA周期刷新OSD帧内容就能实现动态菜单。Blender的透明通道可以不出现在最终视频接口上它只是用来混合的权重信号。这个扩展在硬件上只需要增加一个VDMA实例和一个Blender IP连线模式与单一VDMA类似唯一要注意的是两条输入流必须共享同一个时序源否则图层之间会出现漂移。让两个VDMA都使用同一个VTC的帧中断作为同步参考是通常做法。6.3 往Linux方向迁移裸机方案稳定之后很多人会考虑把视频输出集成到PetaLinux或Linaro中。Xilinx官方提供DRM/KMS驱动支持VDMA对应xilinx_drm驱动VTC和VideoOut对应xilinx_video驱动。设备树里需要把各IP的中断、地址、时钟约束描述清楚。相比裸机Linux迁移的主要工作量在设备树和DMA分配上视频通路的硬件连接几乎不用变。不过要提醒的是Linux里VDMA的Buffer分配要使用DMA API的连续内存分配接口用户态应用通过DRM的Framebuffer接口填充图像。这一套流程比裸机复杂很多建议先用裸机验证好通路的硬件行为再升级到Linux应用层。硬件通路本身如果有时序稳定性问题在Linux下更难排查。一些实际操作中的体会At the end of the dayZynq的视频通路搭建最考验的还是细心。很多问题表面上看是IP配置不对实际是时钟没有给到、复位没同步好、地址映射错乱这些底层环节。我在调试过程中最深的体会是别着急写软件先把硬件上每一根连线的时钟域和复位域梳理清楚把VTC的每个参数验算一遍再进SDK跑代码效率会翻倍。另外测试图像一定要提前准备好。我通常会在PS里写个简单的画方块函数用纯色块、彩条、渐变条依次测试。纯色能验证数据是否通彩条能验证颜色分量顺序渐变条能验证位宽和像素对齐。这些测试图像能帮你把故障定位到具体的IP避免瞎猜。这套VDMAVTCVideoOut的视频通路我前后在多个项目里用过从1080p到4K分辨率都验证过。核心思路是不变的数据、时序、时钟、复位四个维度分别排查。文章里提到的每个参数和顺序都可以直接作为你第一个工程的基础配置来尝试跑通之后再根据自己的屏幕和场景调整。如果搭建过程中遇到本文没覆盖到的问题欢迎在评论区把现象和Block Design截图发出来我可以结合具体工程帮你定位。
返回列表