ARTICLE DETAIL

资讯详情

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

ZYNQ入门实战:从Vivado硬件设计到SDK裸机开发完整流程

ZYNQ入门实战:从Vivado硬件设计到SDK裸机开发完整流程 这些年带过不少刚接触ZYNQ的工程师也经常在论坛上看到有人卡在“Vivado建好了硬件却不知道怎么把程序跑起来”这一步。说句实在话ZYNQ的难点不在某一个工具多难用而在于它的开发模式跟传统单片机和纯FPGA完全不一样——你得先在Vivado里把PS和PL的组合关系定下来再把这个硬件描述文件交到SDK里写软件中间还夹着DDR配置、IP核连线、管脚约束这些容易被忽略的细节。这篇内容就是给真正准备动手的人准备的按一条完整链路把从Vivado工程创建到SDK裸机开发的流程捋一遍常见问题我也结合自己踩过的坑一并整理了希望能帮你在起步阶段少走点弯路。1. 项目概述ZYNQ开发到底在做什么1.1 ZYNQ平台的核心架构PS与PL的分工很多新手第一次看到ZYNQ的架构图就头大其实拆开看并不复杂。ZYNQ内部有两大块PSProcessing System处理系统是ARM Cortex-A9双核处理器加上DDR控制器、UART、SPI、I2C等硬核外设PLProgrammable Logic可编程逻辑就是FPGA那部分逻辑资源。两者通过高性能的AXI总线互联PS能启动Linux跑复杂应用PL能实现高速并行运算关键是可以互相协同。我用一个生活化的类比PS好比是你家楼下的物业经理负责处理日常事务、跑系统、管网络PL则是楼里的电梯和电力系统讲究的是极高响应速度和并行工作能力。物业经理下发指令给电梯电梯执行完再反馈结果两者配合起来才能让整个楼正常运转。ZYNQ的妙处就在这——你不仅可以用ARM跑业务逻辑还能用FPGA做实时数据采集、DMA搬运、高速信号处理两边的优势都占了。1.2 完整开发链路Vivado硬件设计 SDK软件开发的“双轨”模式ZYNQ的开发流程跟普通MCU最大的区别就是“先硬件后软件硬件定义软件”。整个链路可以概括为四步在Vivado里创建工程搭建PS和PL的硬件系统配置DDR型号、UART引脚、时钟频率等把硬件配置导出成XSA文件Xilinx Support Archive这一步相当于把硬件的“说明书”打包给软件工程师打开SDK基于XSA文件创建BSPBoard Support Package和Application工程在SDK里编写C代码、交叉编译、下载调试。这套“双轨”模式的本质是Vivado决定了硬件长什么样SDK则决定了系统跑什么逻辑。硬件配置一旦变化XSA一换SDK里的BSP也得跟着重新生成。很多新手经常犯的错就是改了硬件设计忘了重新导出XSA导致SDK还在用旧的硬件描述最后调试半天发现外设地址对不上。1.3 适合人群与学习路线这篇文章针对的是正在转型做嵌入式或FPGA的开发者尤其是手里有一块ZYNQ-7020开发板、想从零开始跑通整个流程的人。学习路线我建议按“点灯→串口→外设→固化”的顺序来不要一上来就折腾Linux、DMA那些高难度内容先把裸机流程彻底跑通理解PS和PL是怎么配合的后面再进阶PetaLinux或者自定义IP就顺理成章了。2. 开发环境准备Vivado与SDK的安装配置2.1 版本选型的实践心得Vivado的版本号多得让人眼花而且官网下载动辄几十个GB选错版本浪费时间不说还容易踩坑。我的建议是如果用的是ZYNQ-7020这种经典器件优先选Vivado 2018.3到2020.2之间的版本这些版本经过大量用户验证教程最多、问题答案最好搜。2020.2之后的版本对SDK的界面和流程做了不少调整新版本的Vitis把SDK整合进去了如果是新手反而容易被界面变化困扰。我实际用得最多的是Vivado 2019.1原因有几点稳定、Vivado和SDK一体化安装、对ZYNQ-7000系列的器件支持非常成熟。2022.2我也用过界面改了、License机制变了但对新手来说并没有实质性的功能提升反而不少老教程的操作步骤对不上号。表格对比一下版本特点适合人群2018.3经典稳定教程最多新手入门首选2019.1对ZYNQ-7000支持好SDK集成度高裸机开发推荐2020.2增加了部分新器件支持需要兼容新板卡的场景2022.2Vitis取代SDK界面变化大有经验的高级用户2.2 安装过程中的四大经典坑点安装Vivado几乎是每个新手遇到的第一个坎我在这里集中说几个高频问题。第一安装路径必须全英文。这条听着像废话但每年都有人栽在这。路径里一旦出现中文或者特殊符号后面综合、仿真、SDK启动都可能报一些莫名其妙的错排查起来非常痛苦。第二磁盘空间预留要充足。Vivado完整安装需要100GB以上的空闲空间我用的是2019.1装完大概80多GB。如果你只选了“Vivado SDK”的定制安装也要预留至少60GB。装到一半磁盘满了整个环境可能文件不完整修都难修。第三安装过程中偶尔会弹出WinPcap安装失败的提示。这个是Xilinx安装器用来支持硬件服务器功能用的网络抓包库跟本地JTAG调试实际上没有直接关系。出现这个提示不用慌直接忽略继续装即可后续用到远程调试或者硬件服务器再单独安装也行。我有一台电脑当初也是报了WinPcap失败后面该用SDK调试还是一切正常。第四驱动与License的问题。Windows下用Xilinx Cable连接板卡时第一次插上USB线设备管理器里大概率显示一个带感叹号的未知设备。这时候需要手动安装Vivado安装目录下的drivers里的驱动路径一般为Xilinx/Vivado/2019.1/data/xicom/cable_drivers/nt64。装好驱动后设备管理器里会出现“Xilinx USB Cable”之类的设备名。2.3 License配置与板卡驱动License这块我多说一句。很多新手会去纠结破解、激活那些事情我个人的建议是去Xilinx官网申请一个免费的WebPack License对ZYNQ-7020这种中小型器件完全够用。申请流程很简单注册账号→进入License管理页面→选择ZYNQ-7000→生成License文件→在Vivado的License Manager里加载。整个过程大概十几分钟比在网上找那些来路不明的License安全得多。License配置完后记得验证一下打开Vivado的Help→About→License或者直接在启动界面看状态。如果License状态正常就进入下一步创建工程如果提示License不支持当前器件八成是申请时没勾选对器件型号。3. Vivado工程创建与硬件设计流程3.1 新建工程从零搭建硬件平台以ZYNQ-7020为例在Vivado里新建工程第一步就是给工程起名字、选路径同样要求全英文路径。然后来到器件选择界面这里要注意ZYNQ-7020有两个常见封装一个是xc7z020clg484-1一个是xc7z020clg400-2具体的型号以你板卡上的丝印为准。选错封装会直接导致管脚约束无法匹配。创建完工程之后核心动作是“Create Block Design”。在IP Integrator里新建一个Block Design然后添加ZYNQ7 Processing System IP。这时候Vivado会弹出一个极大的配置框别被吓到其实需要改的只有几项DDR配置选板卡对应的DDR型号和位宽ZYNQ-7020开发板最常见的是DDR3、16bit或32bitUARTZYNQ的MIO 14和15默认就是UART1的收发引脚很多板子也是这么连的勾选UART1即可时钟PS端的CPU主频默认是667MHzPLL配置DDR频率按板卡实际参数选GPIO如果需要MIO引脚直接控制LED或者按键在GPIO那个页面勾选对应的MIO位。配置完PS别急着导出还要做一步非常关键的右键点击Block Design里的ZYNQ核选择Create HDL Wrapper。这一步会生成一个顶层Verilog文件把整Block Design包装成一个可综合的模块。如果不做这一步后续综合实现直接报“no top module”。3.2 配置PS端DDR、UART、GPIO等核心外设我详细说一下DDR配置因为这是新手最容易翻车的地方。在ZYNQ7 Processing System的配置界面里DDR配置页有很多参数比如型号选择、位宽、速度等级。很多开发板的DDR型号是MT41K256M16HA-125对应DDR3、16bit、速度等级为-125频率一般跑533MHz或者667MHz。如果你的板子资料不全可以在板卡的原理图或者官方wiki上找DDR颗粒型号。这里有一个容易忽略的点DDR的Bank Address和Row/Column地址位宽必须和颗粒一致。Vivado里的DDR配置页提供了常见型号的下拉选择选对型号后地址参数会自动填好。但如果你的板子是定制的用的颗粒型号不在列表里就得手动改Row Address、Column Address、Bank Address这些参数任何一个填错程序启动时DDR自检都会失败表现为SDK里DDR初始化卡死或读取数据全是0xDEADBEEF。UART的配置相对简单。ZYNQ-7020的MIO 14和MIO 15固定连接到UART1板子上通常通过USB转串口芯片连接到电脑。在Vivado里勾选UART1后不需要额外指定引脚因为MIO是固定的PS引脚不需要PL约束。3.3 创建HDL Wrapper并导出硬件描述文件XSA配置完成后在Flow Navigator里点击Generate Output Products然后点击Run Synthesis进行综合。综合通过后再点击Run Implementation进行实现。这里我特别提醒ZYNQ工程的实现步骤经常“变红”这在热词里出现频率非常高新手看到红色就慌其实大部分变红的原因是时序约束没有正确传递或者Block Design里的地址映射冲突。2019.1之后的版本在实现后会提示是否生成比特流如果只是先验证逻辑可以不生成比特流直接导出XSA。但如果要固化PL的逻辑就必须生成比特流。完整流程是Generate Output Products → Run Synthesis → Run Implementation → Generate Bitstream → File → Export Hardware。在Export Hardware对话框里一定要勾选“Include bitstream”这样导出的XSA文件里才会包含比特流数据。导出完成后能找到一个后缀为.xsa的文件这个文件就是SDK的“硬件说明书”包含PS配置信息、PL比特流、地址映射表、外设参数等。从这一刻起Vivado的使命暂时结束接下来所有工作在SDK里完成。4. SDK开发实战从Hello World到外设驱动4.1 创建BSP与Application工程启动Xilinx SDK时需要指定一个Workspace路径。Workspace就是存放SDK工程的目录建议跟Vivado工程目录分开比如在工程文件夹下建一个sdk_workspace子目录避免两个工具的文件混在一起。第一次打开SDK会弹出“Launch”界面问是否要设置Workspace然后会进入一个欢迎页提示导入硬件平台。此时点击File → New → Project选择“Application Project”在弹窗里填工程名然后点击下一页“Board Support Package”选择“Create New BSP”OS Platform选“standalone”硬件平台选刚导出的XSA。这时候SDK会帮你自动生成BSP里面包含了UART、GPIO、中断控制器等各种驱动库的源码和头文件。这里有个细节值得关注BSP生成的启动文件里会有一段初始化代码负责配置DDR控制器、初始化堆栈、使能Cache等。这段代码就是等效于FSBL功能的前期初始化如果你后续做固化这个部分的重要性会直接体现出来。所以理解BSP的生成逻辑比单纯会点“Next”要重要得多。4.2 第一个程序UART打印Hello World在新建Application Project时SDK会弹出模板选择窗口里面有一堆模板Hello World、Empty Application、Peripheral Tests、Dhrystone等等。对新手来说选“Hello World”或“Empty Application”就够了。选Hello World模板后SDK会生成一个简单的main.c代码里调用了xil_printf往UART输出字符串。关键一步来了用USB线连接板卡和电脑确保串口调试工具比如SecureCRT或者串口助手里能看到对应的COM口。打开板卡电源后在SDK里右键工程名→Run As→Launch on Hardware (System Debugger)SDK会自动通过JTAG下载比特流和ELF程序然后串口工具里就能看到打印输出。如果你的串口工具没有任何输出优先检查几下件事DEVICE是否选对了Vivado里勾了UART1SDK里的BSP配置中stdin/stdout是否指向了ps7_uart_1串口工具波特率是否与BSP里的缺省波特率一致通常9600或115200板卡调试中我遇到最多次的就是第三点波特率不对串口里全是乱码但程序其实已经跑起来了。4.3 常见外设开发GPIO、DMA、USB等要点Hello World跑通之后很多人想操作GPIO。ZYNQ的GPIO分为MIO和EMIO两种MIO是PS的专用引脚Lauch之后直接在代码里访问XGpioPs驱动EMIO则是通过PL扩展的GPIO需要先分配PL引脚再做约束。MIO的操作非常简单调用XGpioPs_LookupConfig获取设备配置调用XGpioPs_CfgInitialize初始化调用XGpioPs_SetDirectionPin设置方向调用XGpioPs_WritePin输出高低电平。如果你用手里的ZYNQ开发板点过灯大概率就是走这个流程。这里提醒一下MIO的点灯操作是不需要重新做Vivado工程的只要之前配置了MIO和GPIO就行但如果要走EMIO那就必须回到Vivado里添加GPIO IP、配置引脚、重新综合和导出。DMA是绕不开的进阶话题。ZYNQ同时支持SGScatter-GatherDMA和简单的寄存器模式DMA在PL端如果用了AXI DMA IPSDK侧通常要配合中断和Buffer描述符来做数据搬运。新手常常在DMA这块卡住有个经典陷阱SDK的DMA传输需要一个“对齐”的内存缓冲区直接malloc出来的内存地址往往不对齐建议用Xil_DCacheFlush和Xil_DCacheInvalidate配合处理Cache一致性否则会出现“DMA搬运的数据是旧数据”这种诡异问题。USB在ZYNQ里属于PS的外设但前提是Vivado里勾选了USB和相应的MIO分配。在裸机环境下跑USB HOST/Device的代码比Linux下复杂主要是USB驱动栈的状态机太绕。如果你只是想要USB通信我个人的建议是要么用PetaLinux去跑要么用PL端加USB Controller IP要么直接外扩USB转串口芯片别跟SDK裸机的USB驱动死磕。5. 固化与烧写让程序脱离JTAG运行5.1 生成FSBL与Boot Image前面在SDK里调试的程序掉电就没了因为程序是烧在RAM里运行的。要让程序上电自动运行需要做两件事生成启动镜像BOOT.BIN和写入Flash。第一步生成FSBLFirst Stage Boot Loader。在SDK里通过File → New → Project → “FSBL”模板创建工程SDK会自动生成一个fsbl.elf。FSBL的作用是系统上电后BootROM把FSBL加载到OCM片上内存FSBL再完成DDR初始化、时钟配置、把比特流下载到PL、最后把应用代码从Flash拷贝到DDR并跳转执行。第二步生成BOOT.BIN。在SDK里选择Xilinx → Create Boot Image在弹窗中按顺序添加三样东西FSBL的elf文件、硬件比特流.bit、你的应用程序elf文件。顺序不能错错了系统可能能启动一部分但应用跑不起来。很多教程会让人去用命令行工具bootgen生成Boot Image其实SDK图形界面已经封装好了我建议新手先用Create Boot Image图形界面等理解了镜像结构再回头研究bootgen脚本也不迟。5.2 QSPI Flash固化完整流程固化的标准套路有两种一种是利用SDK的“Program Flash”工具直接在JTAG模式下把Boot Image写进Flash另一种是先通过代码把镜像加载到DDR里再调XilSpiPs库往QSPI Flash里写。对于新手我用得最多的还是SDK自带的Program Flash Memory工具。具体操作步骤如下确保BOOT.BIN已经生成路径一般在工程目录/sdk_workspace/工程名/Debug/下在SDK里选择Xilinx → Program FlashFlash Type选“qspi-x4-single”或者“qspi-ospi”这种具体看板卡的Flash类型Image File选择BOOT.BIN路径Offset Address用默认的0x0点击Program等待进度条走完。写完之后把板卡启动模式拨到QSPI方式一般是四位拨码开关具体看板卡说明书重新上电或复位程序就会自动运行。如果程序没起来先看看启动模式拨码是否拨对了再检查BOOT.BIN里有没有包含bitstream。5.3 JTAG固化Flash时必须接DDR吗这个问题被问过太多次了直接说结论不是必须但大多数情况下建议接DDR。为什么这么说因为SDK的Program Flash工具在烧写时并不是直接把BOOT.BIN逐字节写进Flash那么简单。它实际上是把FSBL先加载到内存里运行再由运行起来的FSBL配合工具把镜像写入QSPI。FSBL运行时需要一个缓冲区来暂存镜像数据。如果你在设计里配置了DDRFSBL默认会把DDR初始化好然后用DDR去搬运数据如果工程里没有DDR那FSBL会用OCM但OCM只有256KB放不下大一点的镜像。所以答案取决于你的BOOT.BIN有多大。如果你的应用很小比如裸机Hello WorldBOOT.BIN通常不到100KB不接DDR也没问题。但如果包含完整的Linux镜像或者较大的FPGA比特流加应用程序镜像动辄几十MB不初始化DDR就没法往Flash里写。实际开发中几乎没有不含DDR的ZYNQ工程所以“JTAG固化Flash时必须使用DDR”在绝大多数场景下成立。6. 常见问题排查与避坑实录6.1 Vivado工程与综合实现问题先聊“Implement Design变红”的问题。我在前面提到过这属于ZYNQ新手的高频bug。你点了Run Implementation后日志最后一行报[TIMING-1]或者[PLACE-1]之类的错误进度条变成红色其实就是实现流程中断。常见诱因有顶层模块没有用HDL Wrapper导致工具找不到顶层工程里混入了其他工程残留的XDC约束文件引脚位置跟实际板卡不符时钟频率配置过高时序不满足要求。排查思路是先看Messages窗口找到红色的Critical Warning或Error双击能跳转到具体位置。如果是时序问题最简单的急救方案是把PS端CPU或DDR的时钟频率往下调一档再综合试试定位到问题后再细查约束。Vivado里还有个叫BUFGMUX的错误很多时候也是时钟网络的问题。比如你在Block Design里把同一个时钟接到了多个需要不同时钟域的IP上生成了不兼容的时钟结构。解决思路是确保每个时钟域都有明确的来源在需要跨时钟域的地方用AXI Clock Converter或异步FIFO做隔离。6.2 SDK编译与调试问题SDK编译报错里常见的有两类一类是链接时报undefined reference另一类是头文件找不到。第一类通常是因为你没有在BSP设置里启用对应的库比如用了XGpioPs但BSP里没勾选“xilgpio”第二类是工程路径问题建议把整个工程放在纯英文且没有空格的路径下再Project → Clean一下。调试时的断点失灵也是个经典问题。SDK调试器默认情况下会在main入口停一下但如果你在中断服务函数里设了断点可能会遇到断点不生效的情况。这是因为代码运行时启用了O2优化某些变量和断点被编译器优化掉了。把编译优化等级改成O0再试通常在工程属性里的Optimization选项可以调。还有一个我印象很深的坑SDK调试时程序进入了一个死循环CPU复位后依然卡住。后来发现是OCM被占满、堆栈溢出导致的。裸机工程没有虚拟内存保护堆栈写穿后程序行为完全不可预测表现就是各种“无理由”死机。解决方法是把链接脚本里堆栈大小调大或者简化代码逻辑别在中断里做耗时的循环。6.3 硬件连接与配置问题硬件层面的问题往往比软件更难排查。最常见的是“SDK连接板子失败”点Run时弹窗提示找不到cable或者device。这时候按以下顺序排查设备管理器里看驱动是否正常出现感叹号就重装驱动确认JTAG档位和跳线是否正确有些板卡在JTAG模式下需要特定的跳线用Vivado的Hardware Manager连接一次能连上说明硬件没问题再回SDK操作尝试更换USB线或USB口有的USB口是纯充电口不能传数据。关于“zynq裸机USB通信方案”的搜索热度一直很高。很多人想把ZYNQ的USB用作数据传输但裸机环境下的USB驱动确实不友好。如果你只是想在PC和ZYNQ之间传数据我实测下来最简单可靠的是在PS上用UART速度不高但非常稳定在PL端做USB UART桥接或者直接用CP210x这类USB转串口芯片如果必须高速优先考虑在Linux环境里用标准的USB gadget/host框架别在裸机里硬啃。同理“QT ZYNQ serialport库编译”这种问题也常见于嵌入式Linux场景一般需要先交叉编译Qt再把串口模块的插件编译进Qt安装目录。裸机SDK里没有Qt的概念这个方向属于PetaLinux的范畴需要的开发者可以等后续专门写一篇讲PetaLinux的文章。6.4 关于Xilinx FIR核与多相滤波的补充热词里有“vivado fir核多相滤波”虽然这篇主要聊SDK但既然搜到这个大概率是PL开发遇到瓶颈的人我简单补一刀。Xilinx FIR Compiler IP支持多相结构的抽取和插值滤波配置时要注意多相因子Polyphase Factor在“Hardware Oversampling Specification”或滤波系数重排相关页面设置FIR核的时钟频率要满足输出采样率×抽取比×滤波器阶数/2的吞吐需求多相滤波的系数重排规则容易搞错建议先用MATLAB的polyphase函数验证结果再对照IP的仿真输出。FIR核的仿真和调试在Vivado里用AXI接口比较方便SDK侧不用参与太多但如果PL端有CPU介入做系数更新就涉及AXI Lite寄存器操作这部分回到我们前面讲的GPIO/DMA代码套路逻辑是相通的。7. 写在最后的实际体会ZYNQ这套东西说白了就是个跨界产品要求你既懂FPGA的硬件思维又懂ARM的软件思维。很多人卡住不是因为他笨而是因为第一次接触这种“硬件也能改、软件也能跑”的异构系统思路一时间转不过弯来。我的建议始终是别贪多先照着版本文档把Vivado导出XSA、SDK烧个Hello World、固化到QSPI这三步滚瓜烂熟ZYNQ的门就算真正迈进去了。我自己带项目时最常用的调试三板斧就是看串口日志、读寄存器值、查地址映射表。遇到问题别急着怀疑工具先看看自己的硬件配置是否跟代码一致再确认XSA有没有更新很多玄学问题最后都能归结到这些基础环节。开发板上如果还有SD卡接口建议你下一步把启动模式切换到SD卡方式试试——SD卡固化比QSPI更灵活迭代Linux内核和根文件系统时特别方便。这个坑我当年也是一步一步踩过来的等你在SDK裸机流程上积累够感觉了自然会有兴趣去探索更完整的启动和部署方案。
返回列表