ARTICLE DETAIL

资讯详情

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

Zynq FPGA扩展9路串口:基于UART Lite IP的硬件设计与Linux驱动实战

Zynq FPGA扩展9路串口:基于UART Lite IP的硬件设计与Linux驱动实战 简介本资源面向Zynq嵌入式开发工程师与FPGA系统集成人员聚焦PL侧扩展多路UART通信的实际工程痛点——当Zynq PS端仅提供2路串口无法满足工业控制、传感器汇聚等多设备通信需求时提供一套完整、可复现的9路UARTLite硬件软件协同实现方案。资源包含606个文件涵盖Vivado工程源码73个Verilog、32个VHDL模块、约束文件49个XDC、综合/实现报告36个DCP、14个RPT、设备树适配文件4个DTSI、2个DTS、Shell/Tcl自动化脚本30个SH、18个TCL及详细调试文档PDF总大小27.43MB。已有948人学习下载内容覆盖从PL端UARTLite IP例化、AXI互联配置、Linux设备树修改、驱动加载到终端回环验证的全流程特别补充了常见编译报错、设备节点缺失、波特率异常等真实调试陷阱与解决路径所有工程均通过__synthesis_is_complete__标记验证完成开箱即用。1. 项目概述从零构建一个基于Zynq的9路串口系统最近在做一个工业数据采集的项目主控用的是Xilinx Zynq-7000系列的芯片需求是要接一堆串口传感器。Zynq的PS处理器系统端自带的UART控制器通常就一两个完全不够用。这时候PL可编程逻辑端的灵活性就派上用场了——我们可以用Xilinx提供的免费IP核UART Lite在FPGA逻辑里“造”出多个串口。这个项目就是记录我如何从零开始在Vivado里用UART Lite IP核例化了9个串口并最终在Linux系统下通过设备树正确驱动起来的全过程。如果你也在为Zynq串口资源不够而发愁或者想搞明白如何让PS和PL协同工作这篇详细的踩坑记录应该能帮到你。整个流程可以拆解成几个核心环节首先是在Vivado中搭建硬件平台包括Zynq PS的配置、UART Lite IP的添加与连线、以及AXI总线的连接然后是生成硬件描述文件XSA并导入到Vitis或SDK中进行软件平台配置最关键的一步是编写正确的设备树Device Tree源文件.dts将PL端的这9个UART Lite设备准确地描述给Linux内核最后是编译、部署和测试。听起来步骤不少但跟着做一遍你会发现思路很清晰。我不仅会列出每一步的操作更会解释“为什么这么做”比如地址分配的原则、设备树节点与硬件描述的对应关系等这些都是官方文档里不一定会细讲但实际调试中至关重要的经验。2. 硬件平台搭建在Vivado中构建9路UART Lite系统2.1 创建工程与Zynq PS基础配置首先打开Vivado我用的版本是2022.1不同版本界面可能略有差异但核心流程一致创建一个新的RTL工程。选择对应的Zynq器件型号这个一定要和你手头的开发板匹配比如我使用的是xc7z020clg400-1。创建Block Design这是Vivado图形化设计IP Integrator的核心。从IP Catalog中搜索并添加“ZYNQ7 Processing System” IP核。双击它进行配置这一步是决定PS端资源的关键。DDR配置在“PS-PL Configuration” - “HP Slave AXI Interface”中根据板载DDR型号和原理图正确配置内存类型、大小和时钟。如果配错后续Linux可能无法启动或运行不稳定。外设接口使能在“MIO Configuration”里至少需要使能一个PS端的UART比如UART 1用于Linux系统调试输出。同时根据需求使能SD卡、以太网等外设的管脚。时钟配置在“Clock Configuration”中确保给PL提供的时钟FCLK_CLK0已经打开并设置合适的频率比如100MHz。这个时钟将作为我们PL部分逻辑的主时钟。AXI接口使能这是PL和PS通信的桥梁。在“PS-PL Configuration” - “General” - “Enable AXI interface”下确保“AXI HP interface”或“AXI GP interface”至少有一组被使能。对于UART Lite这类低速外设使用AXI GP Master接口通常为M_AXI_GP0就足够了。它的位宽是32位带宽完全能满足多个串口的需求。配置完成后点击“Run Block Automation”Vivado会自动完成Zynq IP核的一些必要连接。此时在Diagram视图中你应该能看到一个配置好的Zynq PS核。2.2 例化并连接9个UART Lite IP核接下来是PL部分的核心操作添加UART Lite。添加第一个UART Lite IP在IP Catalog中搜索“AXI UART Lite”添加到Block Design中。双击对其进行配置。波特率在“Hardware Options”选项卡下设置“Baud Rate”为你需要的值例如115200。这里设置的是IP核硬件自带的波特率生成器参数软件驱动后续需要与之匹配。数据位、停止位等通常使用默认的8-N-18位数据无校验1位停止位即可。UART Lite IP核相对简单不支持硬件流控RTS/CTS。注意IP版本尽量使用较新的版本以获得更好的稳定性和兼容性。连接AXI总线这是关键一步。UART Lite的“S_AXI”接口需要连接到Zynq PS的AXI Master接口如M_AXI_GP0上。点击Vivado上方的“Run Connection Automation”在弹出的对话框中勾选这个UART Lite IP。Vivado会自动完成几件事创建一个AXI Interconnect IP用于总线互联。将Zynq的M_AXI_GP0连接到Interconnect。将UART Lite的S_AXI连接到Interconnect。自动分配一个地址空间给这个UART Lite设备如0x43C0_0000。务必记下这个地址后续设备树要用。将Zynq提供的复位和时钟FCLK_CLK0, FCLK_RESET0_N连接到IP核。引出外部接口UART Lite IP的“TX”和“RX”信号需要连接到芯片的物理管脚。右键点击这两个端口选择“Make External”这会生成两个顶层端口tx_0和rx_0。复制并修改生成9路现在我们有了一套完整的单路UART Lite。为了生成9路不需要手动添加8次。更高效的方法是在Block Design中选中刚才配置好的UART Lite IP核以及与之相连的AXI Interconnect的一部分如果有的话按CtrlC复制再按CtrlV粘贴。重复8次。然后逐一修改每个UART Lite IP核的“Name”属性比如uartlite_0,uartlite_1...uartlite_8。Vivado在自动连接时会为每一个实例分配新的、不重叠的地址空间如0x43C1_0000, 0x43C2_0000...。连接时钟与复位确保每一个UART Lite实例的s_axi_aclk都连接到Zynq提供的FCLK_CLK0s_axi_aresetn都连接到FCLK_RESET0_N。这个复位是低电平有效。整理外部端口9个IP会生成18个外部端口9TX9RX。为了顶层清晰可以选中所有tx端口右键“Group Ports”命名为uart_tx[8:0]。同样将rx端口分组为uart_rx[8:0]。这样在顶层模块中就是两个总线信号非常整洁。注意Vivado自动分配的地址空间通常是连续的但一定要在“Address Editor”标签页中手动检查一遍确认9个UART Lite的“Offset Address”没有冲突且范围Range设置合理通常32K或64K就足够。2.3 约束管脚与生成输出产品硬件设计的最后一步是管脚约束和系统集成。创建顶层HDL Wrapper在Sources面板右键点击你的Block Design.bd文件选择“Create HDL Wrapper”让Vivado自动生成顶层的Verilog或VHDL文件。管脚约束XDC文件根据你的开发板原理图为uart_tx[8:0]和uart_rx[8:0]这18个信号分配具体的FPGA管脚。例如set_property PACKAGE_PIN AB12 [get_ports {uart_tx[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {uart_tx[0]}] # ... 为其他17个端口同样指定管脚和IO标准务必注意IO电平标准LVCMOS33, LVCMOS18等要与板卡电压匹配。生成比特流点击“Generate Bitstream”。Vivado会执行综合、实现、布局布线最终生成一个.bit文件。这个过程时间较长取决于设计复杂度。导出硬件平台比特流生成后在菜单栏选择“File” - “Export” - “Export Hardware”。勾选“Include bitstream”导出为XSA文件.xsa。这个文件包含了完整的硬件描述信息是进行软件开发的桥梁。3. 软件环境配置与设备树编写3.1 在Vitis中创建平台与应用项目打开Vitis或旧版的SDK新建一个工作空间。然后创建“Platform Project”在向导中导入我们刚才生成的.xsa文件。Vitis会解析硬件生成对应的硬件平台。接下来基于这个硬件平台创建一个“Application Project”。对于Linux驱动开发我们通常不在这里写应用而是为了生成两个关键文件FSBLFirst Stage Bootloader和设备树源文件.dts。生成FSBL在创建应用项目时可以选择模板“Zynq FSBL”。编译后会生成fsbl.elf。这是Zynq启动链的第一环负责初始化PS、加载PL比特流等。生成设备树模板在Vitis中找到你的硬件平台项目右键点击选择“Generate Device Tree”。这会产生一个基于当前硬件设计的.dts文件框架。但是这个自动生成的设备树通常不完整特别是对于PL端自定义的IP需要我们进行大量手动修改和补充。我们将以这个文件为起点进行编辑。3.2 深度解析与编写设备树.dts设备树是Linux内核识别硬件拓扑结构的关键。对于PL端的自定义IP我们需要在设备树中为其创建节点内核中的驱动程序才能与之匹配并驱动它。这是本项目最核心也最容易出错的部分。首先找到Vitis为你的硬件平台生成的设备树源文件通常位于platform_project/export/platform_project/sw/platform_project/bsp/device-tree目录下文件名为system.dts或pl.dtsi。我们需要在amba_pl节点下这是PL部分在设备树中的总线为我们的9个UART Lite添加子节点。以下是一个示例添加了两个其余7个依此类推/ { amba_pl: amba_pl { #address-cells 1; #size-cells 1; compatible simple-bus; ranges; /* 第一个UART Lite对应硬件地址 0x43C00000 */ serial0: serial43c00000 { compatible xlnx,xps-uartlite-1.00.a; reg 0x43c00000 0x10000; // 起始地址和范围64KB clock-frequency 100000000; // 输入时钟频率与FCLK_CLK0一致 current-speed 115200; // 默认波特率 device_type serial; port-number 0; // 自定义属性用于标识 status okay; }; /* 第二个UART Lite对应硬件地址 0x43C10000 */ serial1: serial43c10000 { compatible xlnx,xps-uartlite-1.00.a; reg 0x43c10000 0x10000; clock-frequency 100000000; current-speed 115200; device_type serial; port-number 1; status okay; }; // ... 请继续添加 serial2 到 serial8地址依次为 0x43C20000 ... 0x43C80000 }; };关键参数解析与避坑指南compatible属性这是驱动匹配的“身份证”。对于Xilinx的UART Lite IP核必须使用xlnx,xps-uartlite-1.00.a。内核源码中drivers/tty/serial/xilinx_uartlite.c驱动正是通过这个字符串来匹配的。写错了驱动就加载不上。reg属性这是最重要的属性定义了IP核在内存映射中的地址和范围。0x43c00000 0x10000表示从地址0x43c00000开始占用0x1000064KB的空间。这个起始地址必须与Vivado Address Editor中分配给该IP核的“Offset Address”完全一致。范围可以给得大一些但必须覆盖IP核的实际寄存器空间。clock-frequency单位是Hz。这里必须填写连接到此IP核s_axi_aclk引脚上的时钟频率也就是我们在Vivado中配置的FCLK_CLK0的频率例如100MHz。驱动会用它来计算波特率分频器。current-speed期望的默认波特率。驱动加载时会尝试设置为此值。这个值必须与你在Vivado中配置UART Lite IP核时设置的“Baud Rate”一致否则通信会乱码。port-number这不是标准属性是我自定义的用于在驱动或应用层方便地识别是哪个物理串口。你也可以不用。status设置为“okay”表示启用该设备。实操心得设备树编译后会生成一个二进制的.dtb文件。在Linux启动时Bootloader如U-Boot会将其加载到内存并传递给内核。一个快速验证设备树是否正确的方法是在Linux启动后查看/proc/device-tree/amba_pl/目录下的结构或者使用dmesg | grep xuartlite查看内核是否成功探测到了这些设备。如果没看到首先检查compatible字符串和reg地址。4. 系统集成、启动与测试4.1 制作启动镜像BOOT.BINZynq需要从一个特定的启动镜像启动这个镜像通常包含多个部分。我们需要使用Vitis的“Create Boot Image”工具或者命令行工具bootgen来打包。启动镜像的典型组成顺序是FSBL (fsbl.elf)第一阶段引导加载程序。PL比特流 (system.bit)FPGA的配置文件用于配置PL部分的逻辑我们的9路串口就在这里面。注意.bit文件需要从Vivado工程目录下的*.runs/impl_1文件夹中获取或者由Vivado在Export Hardware时包含。U-Boot (u-boot.elf)第二阶段引导加载程序负责加载设备树、Linux内核等。可选PMU Firmware (pmufw.elf)对于Zynq UltraScale等系列可能需要。在Vitis中可以创建一个新的“Create Boot Image”工程按顺序添加上述文件输出格式选择BIN即可生成BOOT.BIN。4.2 部署与上电启动将以下文件放入SD卡的FAT32分区BOOT.BIN启动镜像image.ub这是一个包含Linux内核、设备树和根文件系统的FIT镜像或者你也可以分开存放uImage,system.dtb,rootfs.cpio.gz等你的根文件系统。将SD卡插入开发板设置启动模式为SD卡启动上电。通过PS端的调试串口如UART1观察启动日志。你应该能看到类似这样的信息xuartlite 43c00000.serial: at MMIO 0x43c00000 (irq -1) is a xuartlite xuartlite 43c10000.serial: at MMIO 0x43c10000 (irq -1) is a xuartlite ...这表示内核已经成功识别并驱动了我们在PL端创建的UART Lite设备。4.3 用户空间测试与配置驱动加载成功后在Linux的/dev目录下会生成对应的设备节点通常是ttyUL0,ttyUL1, ...ttyUL8。基础测试# 查看设备节点 ls -l /dev/ttyUL* # 使用cat监听一个端口需要先设置参数 stty -F /dev/ttyUL0 115200 raw cat /dev/ttyUL0 # 在另一个终端发送数据 echo Hello UART0 /dev/ttyUL0如果连接了串口线比如USB转TTL你可以在电脑端用串口助手看到发送的数据。配置为系统控制台如果你想将其中一个PL串口例如ttyUL0用作Linux控制台可以在内核启动参数bootargs中设置consolettyUL0,115200这样内核的启动信息以及登录提示都会从这个串口输出。这对于没有多余PS串口或需要远程调试的场景非常有用。使用setserial工具虽然UART Lite驱动不支持所有标准串口的设置但一些基础信息可以查看setserial -g /dev/ttyUL05. 常见问题排查与调试技巧实录在实际操作中你几乎一定会遇到各种问题。下面是我踩过的一些坑和解决方法。5.1 PL比特流加载失败现象启动日志中FSBL阶段报错提示加载比特流失败或者系统启动后/dev下没有出现ttyUL*设备。排查检查.bit文件确认打包进BOOT.BIN的.bit文件是最新从Vivado工程生成的并且对应的硬件设计.bd就是包含9路UART的那个。检查电源和时钟在Vivado中确认Zynq PS给PL的供电FCLK_CLK0是否已使能并输出。可以在Block Design中双击Zynq IP核查看“Clock Configuration”和“Power Management”设置。查看FSBL日志通过调试串口仔细观察FSBL阶段的输出看是否有关于PL配置的警告或错误。5.2 内核无法探测到UART Lite设备现象dmesg | grep xuartlite无输出/proc/device-tree下没有对应节点。排查设备树.dts文件这是头号嫌疑犯。用dtc工具反编译你的.dtb文件检查amba_pl节点下的子节点是否存在compatible和reg属性是否正确。dtc -I dtb -O dts system.dtb -o system_decompiled.dts地址冲突确认设备树中reg的地址与Vivado Address Editor中的地址完全一致包括大小写通常是全小写。同时检查9个串口的地址范围是否重叠。驱动编译确认你使用的Linux内核配置中已编译了CONFIG_SERIAL_XILINX_PS_UARTLITE驱动通常标记为Xilinx PS UARTLITE serial port support。检查内核启动日志看是否有驱动初始化失败的信息。5.3 串口通信乱码或无法收发现象能收到数据但全是乱码或者发送数据对方收不到。排查波特率不匹配最常见这是“三处波特率必须一致”原则。Vivado IP配置UART Lite IP核硬件参数中的波特率如115200。设备树节点current-speed属性值如115200。用户空间设置使用stty或编程时设置的波特率如115200。 这三者必须完全相同。如果IP核硬件波特率是115200而设备树设成了9600驱动会按9600去设置分频器导致实际波特率错误。时钟频率错误设备树中的clock-frequency必须等于PL端IP核的实际输入时钟FCLK_CLK0。如果这里是100MHz你错写成了50MHz驱动计算出的分频系数就会错波特率也就不准了。硬件连接问题检查FPGA管脚约束是否正确物理连线是否接反TX接RXRX接TX地线是否共地。用示波器测量TX引脚看是否有波形输出并测量其波特率是否准确。5.4 多路串口中断处理问题现象本例中我们没有使用中断所有UART Lite的interrupts属性在设备树中都被设置为0或255表示无中断驱动使用轮询模式。这在波特率不高如115200时完全可行。进阶如果你需要高性能或低延迟可以启用中断。需要在Vivado中将UART Lite的interrupt端口引出连接到Zynq PS的IRQ_F2PPL到PS的中断总线上并在设备树中正确配置中断号。这涉及到更复杂的硬件连线和设备树中断控制器配置调试难度会增大。对于初学者建议先从轮询模式开始。5.5 系统稳定性问题现象系统运行一段时间后死机或串口偶尔丢数据。排查PL时钟稳定性确保给PL的时钟FCLK_CLK0是干净的、稳定的。可以在Vivado中插入ILA集成逻辑分析仪核来监测时钟和信号质量。电源完整性PL部分同时激活9个串口会增加功耗。检查板卡电源设计是否能满足要求特别是当所有串口同时高速收发时。驱动并发访问如果多个进程或线程同时读写同一个/dev/ttyULx设备需要应用程序自己做好同步。内核驱动本身对单个设备的访问是串行化的。整个流程走下来从Vivado画图到设备树编写再到最终系统跑通最关键的就是“对应关系”硬件地址、设备树节点、驱动匹配字符串、时钟频率、波特率这几组参数必须环环相扣严丝合缝。任何一个环节的疏忽都会导致调试陷入困境。我的建议是每做完一步就做好记录尤其是那些自动生成的地址和参数最好整理成一个表格方便后续对照排查。本文还有配套的精品资源点击获取
返回列表