ZYNQ UART启动过程分析

本文探讨了在Zynq SoC开发过程中, HelloWorld程序中UART波特率115200的配置来源。作者从C代码出发,发现没有直接配置UART,然后转向汇编代码寻找线索,但未在SDK中找到相关代码。最后,作者在Vivado生成的硬件平台文件中找到了答案,是通过ps7_init.c或ps7_init.tcl在启动时配置了UART。此过程揭示了SDK和硬件平台之间的交互以及初始化流程。

  之前在学习各大开发板的时候,都是只浏览了一遍,没有深入研究。最近回头再看一遍,刚开始看hello world就一直存在一个疑问,从C语言的角度入手,似乎没有对UART进行配置,为什么上来就有波特率115200。
  首先直接分析hello world的代码:

/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"


int main()
{
    init_platform();

    print("Hello World\n\r");

    cleanup_platform();
    return 0;
}

  从中看到,C代码只有一个init_platform()函数,然后接直接输出了。

void init_platform()
{
    /*
     * If you want to run this example outside of SDK,
     * uncomment one of the following two lines and also #include "ps7_init.h"
     * or #include "ps7_init.h" at the top, depending on the target.
     * Make sure that the ps7/psu_init.c and ps7/psu_init.h files are included
     * along with this example source files for compilation.
     */
    /* ps7_init();*/
    /* psu_init();*/
    enable_caches();
    init_uart();
}

  enable_caches()这个函数从字面意思就知道,是跟芯片内部高速缓存有关,配置一些SRAM,而外设肯定不会在SRAM中运行的。而另外一个函数init_uart(),里面只是定义了uartns550这个串口的波特率是9600,也不可能是我们调试的串口配置。看起来C语言部分根本没有对串口进行配置。

void disable_caches()
{
#ifdef __MICROBLAZE__
#ifdef XPAR_MICROBLAZE_USE_DCACHE
    Xil_DCacheDisable();
#endif
#ifdef XPAR_MICROBLAZE_USE_ICACHE
    Xil_ICacheDisable();
#endif
#endif
}

void init_uart()
{
#ifdef STDOUT_IS_16550
    XUartNs550_SetBaud(STDOUT_BASEADDR, XPAR_XUARTNS550_CLOCK_HZ, UART_BAUD);
    XUartNs550_SetLineControlReg(STDOUT_BASEADDR, XUN_LCR_8_DATA_BITS);
#endif
    /* Bootrom/BSP configures PS7/PSU UART to 115200 bps */
}

  那么换个思路,参考I.MIX6U等一些ARM处理器系统运行前,BOOT ROM的BCD代码部分会对DDR等外设进行初始化,先在汇编中进行一些寄存器初始化,再配合链接脚本,最终通过Makefile将一些外设提前进行了配置。那么不妨去汇编中找一下代码,看看有没有对串口外设进行初始化。(Makefile部分就先不研究了,毕竟Linux菜鸟一枚)。
  有事没有先问百度。百度一下,果然看到有类似文章: SDK\SDK_Export\hello_world_bsp_0\ps7_cortexa9_0\libsrc\standalone_v3_05_a\路径下的SRC文件夹,里面有asm_vectors.S、boot.S、cpu_init.S、translation_table.s、xil-crt0.S等5个文件。其中boot.s就有代码初始化了。

	/* Initialize STDOUT to 115200bps */

ldr r0, =UART_BAUDRATE

bl Init_Uart

#ifdef PROFILING /* defined in Makefile */

  但我打开我的2016、2017、2019版本的Vivado SDK并没有发现有这一段代码。不管是不是版本原因还是其他问题,那么这条路肯定也是走不通了。
  那么回想创建工程前,我们从Vivado中导入了硬件平台,那么可能是在这部分代码中。打开后发现果然,ps7_init.c和ps7_init.h代码中对寄存器进行了写操作,很可能就是在这里进行了配置。ps7_init() 这个函数就是根据平台不同配置,写入不同对参数。然而,在init_platform()这个函数中ps7_init() 被屏蔽了,也就是说并没有生效,再次迷惑了。注意到上面有一段话说了:
If you want to run this example outside of SDK,uncomment one of the following two lines and also #include “ps7_init.h”
  说明这个可能还是有些作用的。参考官方的ug821-zynq-7000-swdev文档:
在这里插入图片描述
  ps7_init.tcl这个文件和ps7_init.c是一样的效果,那么猜想,当使用JTAG烧录可能是不需要调用ps7_init.c文件,而是直接运行了ps7_init.tcl脚本。直接再次百度,果然已经有人问到这个问题了。
  链接: Xilinx 论坛.
  再次找到CSDN上面的文章,果然,在JTAG的时候,是用脚本文件ps7_init.tcl初始化外设的,而这个文件是从硬件平台导出的。可见没有什么是无缘无故产生的。
  写到最后,其实我们可以去看一下ps7_init.c这个文件究竟写了哪些寄存器,进行了哪些操作。涉及到C语言的一些基础知识,这里就不详细介绍了。而SOC外设寄存器的地址,可以从平台生成的文件ps7_init.html中打开,比如寄存器UART_CLK_CTRL:
在这里插入图片描述
  应用工程中的其他BSP文件,这些才是SDK(新版本叫做Vitis)生成的板级库文件,类似于STM32的官方库、HAL库,我们可以在SDK中直接调用,就像使用Keil一样。
  SDK还有一个作用就是将硬件平台(Vivado)生成的FPGA运行文件.bit文件和硬件启动文件fsbl.elf,以及SDK工程生成的.elf打包生成BOOT.BIN。当然,对于Linux系统也是这样,只不过这个时候要用到的是Linux系统生成的uboot.elf。有时间和兴趣的话,不妨用二进制文档编辑器打开BOOT.bin,看一下相关的启动过程是怎样的。
参考文档:
[1] https://blog.csdn.net/pingis58/article/details/103425981
[2] https://blog.csdn.net/zhaoxinfan/article/details/54958641
[3] https://blog.csdn.net/wangbuu/article/details/80047791
[4] https://blog.csdn.net/claudedy/article/details/90757593

### Zynq-7045 启动流程详解 Zynq-7045 是 Xilinx Zynq UltraScale+ MPSoC 系列中的一个型号,它集成了双核 ARM Cortex-A53 处理系统(PS)和可编程逻辑(PL),支持多种启动方式,包括从 QSPI Flash、NAND Flash、SD 卡以及 JTAG 模式等启动启动流程主要由 BootROM、FSBL(First Stage Boot Loader)、SSBL(Second Stage Boot Loader)和操作系统组成。 #### BootROM 阶段 Zynq-7045 上电后,首先执行的是固化在芯片内部的 BootROM 代码。BootROM 会根据启动模式引脚(如 MIO 引脚)的状态决定从哪个设备加载下一阶段的引导代码。常见的启动模式包括: - **JTAG 模式**:用于调试,启动方式选择拨码开关设置为 `00`(1~2 位)[^2]。 - **QSPI 模式**:从外部 QSPI Flash 加载 FSBL。 - **SD 模式**:从 SD 卡加载引导镜像。 - **NAND 模式**:从 NAND Flash 启动。 #### FSBL 阶段 BootROM 加载 FSBL(通常是 `fsbl.elf`)到 OCM(On-Chip Memory)并执行。FSBL 主要完成以下任务: - 初始化 PS 系统(包括时钟、DDR 控制器等)。 - 加载 PL 的比特流(bitstream)以配置 FPGA 逻辑。 - 加载 SSBL(如 U-Boot 或 Baremetal 应用程序)到 DDR 中并跳转执行。 FSBL 的构建通常在 Xilinx SDK 中完成,需要根据硬件设计(HDF 文件)生成相应的引导代码[^1]。 #### SSBL 阶段 SSBL(Second Stage Boot Loader)负责进一步初始化系统环境并加载操作系统镜像(如 Linux 内核)。常见的 SSBL 有: - **U-Boot**:用于加载 Linux 内核和设备树。 - **Baremetal 应用**:用于裸机运行的简单程序。 在 U-Boot 模式下,U-Boot 会从指定的存储介质(如 SD 卡、QSPI Flash)中加载 Linux 内核镜像(zImage)和设备树(.dtb)到内存中,并启动内核。 #### 操作系统启动阶段 当 U-Boot 将 Linux 内核加载到内存后,会跳转到内核入口点,开始执行 Linux 启动流程。内核初始化硬件、挂载根文件系统,并最终启动用户空间程序(如 init 或 systemd)。 --- ### 启动镜像的构建流程 构建 Zynq-7045 的启动镜像通常包括以下步骤: 1. 使用 Vivado 创建硬件设计并生成 HDF 文件。 2. 在 Xilinx SDK 中创建 FSBL 工程并编译生成 `fsbl.elf`。 3. 如果使用 PL,生成比特流文件(.bit)。 4. 创建 BOOT.bin 文件,包含 BootROM 所需的元数据、FSBL 和比特流。 5. 构建 Linux 内核镜像(zImage)、设备树(.dtb)和根文件系统。 6. 将 BOOT.bin、zImage、.dtb 和 rootfs 放入启动介质(如 SD 卡或 QSPI Flash)。 --- ### 启动过程中的调试方法 - **串口调试**:通过 UART 接口连接调试终端,查看启动过程中的打印信息。评估板 PL 端调试串口 `CON19(RS232)` 可用于查看 PL 初始化日志[^2]。 - **JTAG 调试**:使用 JTAG 连接器连接 Xilinx SDK 或 Vivado Hardware Manager,进行硬件调试和烧录。 - **QSPI Flash 烧录**:使用 Vivado 或 SDK 的 Flash Programmer 工具将 BOOT.bin 烧录到 QSPI Flash 中。 --- ### 启动配置示例(QSPI 模式) ```bash # 在 U-Boot 中加载内核和设备树 setenv bootargs console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait fatload mmc 0 0x3000000 zImage fatload mmc 0 0x2A00000 system.dtb bootz 0x3000000 - 0x2A00000 ``` 该脚本用于从 SD 卡加载 Linux 内核和设备树并启动系统。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值