news 2026/9/5 12:21:33

ZYNQ 7020 UART0串口全工程详解:从MIO配置到裸机回显

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ZYNQ 7020 UART0串口全工程详解:从MIO配置到裸机回显

简介:这是一份基于ZYNQ 7020 SoC的UART0串口通信完整工程包,面向嵌入式开发者与FPGA学习者,解决在Vivado 2018.2环境下从硬件配置到软件驱动的串口通信落地问题。压缩包共544个文件,约5.56MB,包含140个h头文件、91个c源码、48个o目标文件、30个v仿真文件,以及Vivado工程xpr、Block Design的bd、hdf硬件描述等,覆盖工程创建、IP核配置、驱动编写、综合实现与调试全过程,可直接导入使用。已有3770人学习下载。资源附带完整的软件工程与SDK工程文件,可帮助读者快速复现UART0在MIO14/MIO15引脚上的配置,省去从零搭建环境的繁琐步骤,适合对照学习ZYNQ的PS与PL协同开发。 ZYNQ 7020的UART0串口程序,网上能找到的工程其实不少,但真正能“打开工程、烧进板子、立刻出串口打印”的完整工程,反而不多。试过的朋友应该都有体会:要么缺XDC约束文件,要么Vivado版本不一致打不开,要么是MIO引脚和你的板卡对不上,改来改去半天时间就没了。这次我把整理好的UART0全工程文件分享出来,同时把硬件配置到裸机代码的来龙去脉讲清楚,方便直接上手。

这套工程解决的是最常见的基础需求:板卡上电后,通过PS端UART0向PC串口终端打印调试信息,并且能把PC发来的数据原样回显,相当于一个串口自环测试。整套文件里包括Vivado硬件工程、比特流文件、SDK裸机工程和启动镜像说明,照着做基本不用动代码就能跑起来。适合刚入手ZYNQ想快速建立信心的新手,也适合老工程师需要一份干净可用的串口调试底板程序时直接套用。

1. 为什么单独聊UART0:先搞懂它在ZYNQ里的定位

1.1 UART0是PS外设,不是PL逻辑

ZYNQ 7020的核心是ARM Cortex-A9双核处理器加FPGA逻辑的异构架构,厂商给的叫法分别是PS端和PL端。很多人一开始会把UART0理解成“FPGA里写出来的串口逻辑”,其实不是。UART0和UART1都集成在PS端,属于ARM处理器内部的通用异步收发控制器,不占用任何PL逻辑资源。

这意味着你不需要写Verilog、不需要做时序约束,只要在Vivado里把PS端的UART0外设打开,配置好引脚,就能在SDK里用纯C语言操作它。这也是ZYNQ裸机开发最友好的地方——玩过STM32的同志会发现,用库函数操作UART的感觉非常熟悉,只是API名字换成了XUartPs。

1.2 UART0、UART1、PL端串口怎么选

ZYNQ 7020的PS端有两个串口控制器,功能完全一致,区别在于它们能映射到的MIO引脚组不同。MIO是PS端专用引脚,ZYNQ 7020一共有53个,这些引脚被GEM、SDIO、UART、I2C、SPI、GPIO等外设复用,硬件上要靠MIO Mux来分配。所以选UART0还是UART1,第一原则是看你的板卡原理图把哪一路接到了USB转串口芯片上。

另外还有一个路线是走EMIO。EMIO可以把UART0或UART1引出到PL引脚上,这样你可以在FPGA侧随意挑选引脚,灵活性更高。缺点是需要在Vivado里做管脚约束、确认IO电平标准,配置复杂度明显上升。如果板卡已经把UART0或UART1通过MIO接到了Type-C或USB口,我建议就用MIO方案,简单直接,全工程文件跑起来零负担。

项目UART0UART1PL端(AXI UART Lite)
所属位置PS端,MIO/EMIO引出PS端,MIO/EMIO引出PL端,需在FPGA逻辑中例化IP
驱动方式XUartPsXUartPsXLlUart / XUartLite
占用资源不占用PL逻辑不占用PL逻辑占用BRAM/LUT
典型场景调试串口、传感器通信调试串口、蓝牙模块需要多路串口或自定义引脚时
配置复杂度

1.3 一个容易踩的坑:UART0不一定在MIO14

很多开发板习惯把UART0接到MIO14和MIO15,但这不是标准。比如ZedBoard官方板卡默认把UART0放在MIO16和MIO17,有些国产板卡又把UART0放在MIO10和MIO11。所以拿到我的工程文件后,第一件事不是烧写,而是翻开你的板卡原理图,确认UART0或者UART1到底接在哪组MIO上。如果和你手上的板卡不一致,后面我会专门讲怎么在Vivado里改,这个花不了两分钟,但能避免烧进去没反应的尴尬。

2. 全工程文件拆解:下载之后先看懂目录结构

2.1 Vivado硬件工程部分

Vivado工程里最重要的是ZYNQ7 Processing System这个IP,所有PS端配置都在它的配置界面里完成。这个全工程中,我打开IP后在Peripheral IO配置区勾选了UART0,并把它绑定到了对应的MIO引脚组上。

波特率我默认设置为115200,8位数据位、无校验、1位停止位,这是最通用的串口配置,兼容99%的串口调试助手。注意,Vivado IP配置里的这个波特率,其实只是一个默认值,真正的波特率是在SDK里初始化串口时通过XUartPs_SetBaudRate函数再次设置的。也就是说,硬件工程里改不改波特率,最终以软件设置为准,但最好两边保持一致,避免后续调试时自己把自己搞迷糊。

工程里的约束文件(XDC)在纯PS方案下只有一个作用:给PL侧用不到的引脚做固定电平和IO标准设置,防止未连接引脚干扰系统。如果你不需要PL参与,这个约束可以保留原样。

2.2 SDK裸机工程部分

SDK工程结构分两块:BSP(板级支持包)和应用程序。

BSP里包含了Xilinx官方提供的库文件,最核心的是xuartps驱动。这个驱动位于SDK的bsp目录下,编译时会自动把uartps相关的源码包含进来,应用程序里只需要include "xuartps.h"就能调用。我建议你稍微翻一下bsp里面ps7_cortexa9_0/libsrc/uartps/src目录,看看源码结构,了解驱动封装的层次,以后改中断方式、改DMA方式时会事半功倍。

应用程序部分很简单,就是一个main.c文件。我在代码里做了三件事:初始化UART0、设置波特率、循环处理接收和回显。所有打印信息通过xil_printf输出。xil_printf是Xilinx定制的轻量级printf,功能比标准库少,但占用的Flash和内存极小,在裸机调试中非常实用。

2.3 启动镜像与烧写相关文件

ZYNQ的裸机程序最终要生成BOOT.bin才能在SD卡上启动。BOOT.bin由三部分组成:FSBL(First Stage Boot Loader)、bitstream(FPGA配置文件,纯PS方案下可选)、应用程序elf文件。整个打包过程在Vivado里两步就能完成:先Create Boot Image,再生成BOOT.bin。

我的工程里提供了一个已经生成好的BOOT.bin,放在boot目录下,方便不想折腾打包流程的人直接拿去用。但要注意,这个BOOT.bin绑定的是我工程里的硬件配置,你的板卡如果MIO引脚不同,必须回到Vivado重新生成比特流,再重新创建Boot Image。这也是很多人问“为什么我直接烧写别人的BOOT.bin没反应”的根本原因。

3. 把工程跑起来的完整实操流程

3.1 版本兼容性先过关

如果你的电脑上装的是Vivado 2018.3,我这份工程可以完美打开。如果你用的是2019.2以上的版本,直接打开旧工程会出现版本升级提示,正常情况下能自动迁移。但Vivado的版本迁移偶尔会出问题,尤其是IP版本更新之后,ZYNQ7 Processing System IP的配置界面可能多出一些新选项,这些选项会有默认值,自动迁移通常不报错,但保险起见,升级完一定要重新打开IP配置界面看一眼UART0是否还处于使能状态。

从2019.2开始,Xilinx把SDK集成到了Vitis里面,不再是独立的Software Development Kit了。Vitis打开的是.xsa文件(硬件平台文件),而不是旧的.hdf文件。我的工程里两个文件都导出了,你根据自己的工具版本灵活选择。新工程切记:不要手动添加elf文件到boot image,让Vitis自动关联应用工程是最稳妥的。

3.2 核对板卡MIO,修改硬件配置的方法

如果你手上的板卡UART0引脚和我工程里的MIO不一致,操作步骤是这样的:

打开Vivado工程,双击框图里的ZYNQ7 Processing System IP,进入配置界面,在Peripheral IO里找到UART0,展开引脚选择下拉框,选择你的板卡实际接的那组MIO。如果UART0对应的引脚被其他外设占用了,可以改用UART1,或者调整其他外设的MIO分配。改完之后先Validate,确认没有红色报错,再重新Run Synthesis、Run Implementation、Generate Bitstream。

我实测下来,改一个MIO分配再重新走一遍综合和实现,大约需要二十分钟左右。这也是为什么我建议你先确认板卡型号,再决定是直接用还是改工程。

3.3 XUartPs驱动的初始化与收发代码

SDK工程的主程序结构如下,你可以直接参考:

#include "xparameters.h" #include "xuartps.h" #include "xil_printf.h" #include "sleep.h" #define UART_BASEADDR XPAR_XUARTPS_0_BASEADDR #define UART_DEVICE_ID XPAR_XUARTPS_0_DEVICE_ID static XUartPs UartInst; void UartInit(void) { XUartPs_Config *Config; Config = XUartPs_LookupConfig(UART_DEVICE_ID); if (Config == NULL) { xil_printf("UART lookup config failed!\r\n"); return; } if (XUartPs_CfgInitialize(&UartInst, Config, Config->BaseAddress) != XST_SUCCESS) { xil_printf("UART init failed!\r\n"); return; } XUartPs_SetBaudRate(&UartInst, 115200); XUartPs_SetOperMode(&UartInst, XUARTPS_OPER_MODE_NORMAL); } int main(void) { u8 RecvBuf; int RecvCount; UartInit(); xil_printf("ZYNQ 7020 UART0 Demo Ready!\r\n"); while (1) { RecvCount = XUartPs_Recv(&UartInst, &RecvBuf, 1); if (RecvCount > 0) { XUartPs_Send(&UartInst, &RecvBuf, 1); } } }

注意看XUartPs_LookupConfig这行,它的参数是设备ID。UART0对应XPAR_XUARTPS_0_DEVICE_ID,UART1对应XPAR_XUARTPS_1_DEVICE_ID。如果你的板卡实际用的是UART1,记得把这两处宏一起改掉,否则初始化会出错。

xil_printf和UART收发是独立的,xil_printf走的是标准输出重定向机制,它默认绑定到PS端第一个可用的串口。如果初始化UART1但xil_printf仍然输出到UART0,那你给UART1写的打印就会消失,这种问题排查时非常容易绕晕。

3.4 从SD卡启动到烧写,一步不落

把整个工程跑通的最后一步是烧写。我推荐用SD卡启动方式,调试起来最方便。

SD卡要先格式化为FAT32文件系统,然后把BOOT.bin复制到根目录。板卡拨码开关拨到SD启动模式,上电,串口工具连上波特率115200,按下板卡复位键,就能在终端里看到启动打印信息了。整个过程不需要下载器也不需要JTAG,只要有SD卡就行。

另外一个烧写路径是QSPI Flash,适合程序稳定后脱离SD卡运行。操作方法是Vivado的Program Flash Memory,或者老版SDK里的Xilinx Tools - Program Flash Memory。不过QSPI烧写有个小坑,烧写前要确认Flash型号,ZYNQ 7020板卡带的大多数是Winbond或Spansion的串行Flash,选错型号会烧写失败。至于更高级的Multiboot远程升级玩法,那是后话,建议先把SD卡这个基础流程跑通再说。

4. 常见问题与排查技巧实录

4.1 串口打印乱码

乱码最高发的原因是波特率不匹配。检查三个地方:串口助手的波特率是不是115200;SDK里XUartPs_SetBaudRate设的值是不是115200;Vivado里UART0外设配置是否打开了。

第二个容易忽略的原因是PS时钟频率。BSP在编译时会根据xparameters.h里的CPU频率和UART时钟源频率计算分频系数,如果Vivado里的PS_CLK输入频率(比如33.333MHz还是50MHz)和板卡实际晶振不一致,BSP就算错了分频,导致实际波特率跟设置的差一大截。这种情况重新生成BSP包就能解决。方法是在SDK工程上右键,选Regenerate BSP Sources,让BSP重新读取硬件配置。

4.2 串口完全没有输出

先确认是不是USB转串口驱动没装好,在设备管理器里看COM口是否识别。确认之后再用万用表量一下板卡上USB转串口芯片的TXD/RXD有没有电平跳变。如果硬件没问题,下一步检查FSBL有没有跑起来。XSCT连接板卡看寄存器是专业做法,但对新手不友好,简单的方法是看SD卡指示灯有没有在闪烁,有闪烁说明BootROM在读取SD卡,BOOT.bin大概率没问题,问题可能在应用程序elf没被正确加载。

还有一个常见低级错误:SD卡的BOOT.bin文件名大小写不对。ZYNQ要求文件名是BOOT.BIN,但很多读卡器、Windows系统下载时会把文件复制成BOOT.bin,这时候有些板子的BootROM无法识别,表现为无任何串口输出。解决方法是重命名时保持全大写。

4.3 MIO引脚被SD卡或EMMC占用

开发板设计时,SDIO接口通常占用MIO40到MIO47,而串口如果也分配到相邻引脚,加上总线冲突,可能工作在SD卡启动模式时无法正常初始化UART。这种情况下最直接的办法是把UART切到UART1,或者通过EMIO把串口引到PL侧。我见过不少人在这里折腾很久,如果板子原理图上明确标注了“UART0与SDIO共用引脚”,建议直接换用UART1,几行代码的事,不要死磕。

4.4 旧版SDK工程导入新版Vitis

2020.x版本以后,Vitis不再支持直接打开旧版SDK工程目录。你需要先把旧工程里的硬件信息导出成.xsa文件,具体方法是:旧SDK里File - Export Hardware,选择包含bitstream,导出到本地目录。然后在Vitis环境里用这个.xsa创建新的平台工程,再把旧的src目录下的.c和.h文件复制到新工程的src文件夹里。

如果报错说API找不到,检查一下include路径是否包含了libsrc里对应驱动目录。Vitis的BSP依赖关系有时候需要手动刷新,右键平台工程Platform Project - Refresh可能就解决了。

5. 一点实操心得

在ZYNQ上做裸机串口,早期调试阶段我建议把UART0当唯一的“生命线”看待,每一步都尽量让它输出状态信息。上电先打印版本号、配置外设时每成功一步打印一步,程序跑飞了也能从最后一条打印定位到问题位置。

还有一个习惯很好:故意把BOOT.bin里的FSBL换成新生成的,专门验证硬件配置是否和板卡一致。如果FSBL阶段有串口打印,说明MIO配置成功;如果完全没有打印,多半是PS端时钟或MIO引脚没配对,和你的应用层代码没关系。

以后你再做ZYNQ的DMA传输、PCIE设备调试、基于ZYNQ的CNN手写数字识别这类更复杂的功能时,这个UART0工程就是最可靠的调试退路。我曾经在调试PCIE设备不识别的问题时,全靠串口一步步打印枚举状态才最终定位到问题,没有这块串口底板的支撑,排查难度会高出好几个量级。所以,把串口这套东西吃透,是ZYNQ开发路上性价比最高的一笔投入。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 6:17:47

基于FPGA与VHDL的FSK调制器实现:从DDS原理到硬件调试

简介:本资源是一份面向数字通信与FPGA开发初学者的FSK频移键控调制硬件实现方案,聚焦VHDL语言在FPGA平台上的工程落地,适用于通信原理课程设计、嵌入式系统实验及无线收发模块开发等场景。压缩包共65个文件,138KB,核心…

作者头像 李华
网站建设 2026/9/4 20:06:17

ESP32 WiFi时钟制作:从硬件选型到代码优化的完整物联网项目实践

简介:这是一套面向嵌入式初学者与高校课程实践的ESP32 WiFi智能时钟完整开发资料,适用于计算机、自动化、电子信息等专业学生的课程设计、毕业设计及课设项目。资源基于Arduino框架开发,集成WiFi校时、心知天气API接入、DHT11温湿度采集、自动…

作者头像 李华
网站建设 2026/9/4 23:10:43

不会盗QQ,还当什么程序员?

不会盗QQ,还当什么程序员? 上面这个段子估计很多朋友都看过,程序员被黑过无数次,在其他人眼中,仿佛我们需要写得了木马,翻得了围墙,修得了电脑,找得到资源,但凡是跟计算机…

作者头像 李华
网站建设 2026/9/3 12:50:02

小爱音箱Play增强版:红外遥控与蓝牙Mesh网关的全屋智能中枢

之前在帮朋友搭建家庭智能场景时,发现很多人的痛点其实不在“要不要买智能家居”,而在“智能设备太贵”“家里老电器不支持联网”“遥控器满地都是”。翻了一圈市面上的百元级产品,小米小爱音箱Play增强版是个比较特别的组合:它把…

作者头像 李华
网站建设 2026/9/2 6:16:08

[论文分析]Agent Hacks Agent:生产级智能体红队测试的自动研究

Agent Hacks Agent: autoresearch for production-agent red teaming 论文重点 本文提出了 AHA(Agent Hacks Agent) ,一个用于生产级LLM智能体自动化红队测试的可证伪发现框架。其核心创新在于将传统的一次性越狱攻击转化为可复用的漏洞概念…

作者头像 李华
网站建设 2026/9/2 6:14:46

NET10 https证书免费自动更新通过ACME实现

添加certes与AlibabaCloud.SDK.Alidns20150109包 如下图 检查证书是否过期 var cert new System.Security.Cryptography.X509Certificates.X509Certificate2(filePath, password);DateTime expirationDate cert.NotAfter;if (expirationDate.AddDays(-1).Date < DateTime…

作者头像 李华