4、硬件平台分析:目标板硬件资源梳理
做 U-Boot 移植,第一步不是看代码,而是看板子。我见过不少新手上来就翻源码,结果连 DDR 型号都搞不清楚,折腾几天发现是硬件不匹配。说白了,你得先搞清楚你的板子上有什么,才能告诉 U-Boot 怎么跑。
这一章,我们就来聊聊怎么梳理目标板的硬件资源。我会带着你过一遍 CPU、DDR、Flash、网口、串口这些关键外设,再讲讲怎么看原理图和 datasheet。嗯,这些都是我这些年移植踩坑总结出来的经验。
4.1 核心硬件资源清单
拿到一块新板子,我习惯先列一个硬件清单。就像搬家前先清点家具一样,心里有数才能动手。下面这张表,是我每次移植前必填的模板:
| 硬件模块 | 关键参数 | 数据手册关注点 | U-Boot 对应配置 |
|---|---|---|---|
| CPU | 架构、主频、核数 | 启动模式、复位向量、MMU | CONFIG_SYS_ARCH, CONFIG_SYS_CPU |
| DDR | 容量、位宽、频率、颗粒型号 | 时序参数、初始化序列、ODT | CONFIG_NR_DRAM_BANKS, DDR 时序结构体 |
| Flash | 类型(NAND/SPI NOR/eMMC)、容量、页大小 | 命令集、坏块管理、擦除时间 | CONFIG_MTD, CONFIG_CMD_NAND |
| 网口 | MAC 型号、PHY 型号、MII/RMII | PHY 地址、寄存器映射、中断引脚 | CONFIG_PHYLIB, CONFIG_ETH |
| 串口 | UART 实例、波特率、流控 | 寄存器基址、时钟源、FIFO 深度 | CONFIG_CONS_INDEX, 串口初始化函数 |
4.2 CPU:从复位到跑起来
CPU 是板子的心脏。移植 U-Boot 时,你首先要回答一个问题:CPU 上电后从哪里开始执行?
不同的架构,复位向量不一样。ARM 一般是 0x00000000 或者 0xFFFF0000,RISC-V 可能是 0x80000000。你得去 datasheet 里找到 Reset Vector 这一节。我记得有一次移植 RISC-V 的板子,datasheet 上写的是 0x80000000,结果实际板子是从 0x20000000 启动的。后来发现是 Boot ROM 做了地址映射。嗯,这种坑,不看原理图根本发现不了。
除了复位向量,还要关注:
- 启动模式选择: 很多 CPU 有多组 BOOT 引脚,决定从 SPI Flash、NAND 还是 SD 卡启动。你得确认板子上的硬件连接。
- 时钟树: CPU 主频、总线频率、外设时钟是怎么来的?PLL 配置对不对?U-Boot 的 lowlevel_init 里通常要初始化时钟。
- MMU 和 Cache: 早期启动阶段,MMU 一般是关闭的。但有些板子需要提前开一段 Cache 来加速。
4.3 DDR:移植成败的关键
DDR 初始化是 U-Boot 移植里最头疼的部分,没有之一。为什么?因为 DDR 的时序参数极其敏感,差一个 cycle 就可能起不来。
你需要从 DDR 颗粒的 datasheet 里找到这些参数:
- tRCD, tRP, tRAS, tRFC: 这些是行地址到列地址的延迟、预充电时间等。U-Boot 的 DDR 初始化代码里会用到。
- CAS Latency (CL): 列地址选通延迟。这个值决定了 DDR 的读取速度。
- ODT (On-Die Termination): 终端电阻配置。配错了,信号反射会导致数据错误。
- DDR 控制器配置: 你的 CPU 内部集成了 DDR 控制器,它需要知道 DDR 颗粒的位宽、Bank 数、行/列地址宽度。
我个人习惯,先把 DDR 的初始化代码单独拿出来调试。用 JTAG 或者串口打印,确认 DDR 能正常读写。怎么确认?写一个 0xAA55AA55 到某个地址,再读回来,看看是不是一样的。如果不对,先检查时序参数。
避坑指南: 我曾经在一块 i.MX6 板子上,DDR 死活初始化不过。折腾了两天,最后发现是原理图上 DDR 的 DQS 信号走线等长没做好。软件上怎么调都没用,最后还是硬件改版才解决。所以,DDR 问题不一定是软件问题,也可能是信号完整性。
4.4 Flash:存放 U-Boot 的地方
U-Boot 本身是存放在 Flash 里的。你得搞清楚 Flash 的类型和接口:
- SPI NOR Flash: 常见于小容量场景,比如 16MB 或 32MB。U-Boot 可以直接在 NOR Flash 里执行(XIP),也可以拷贝到 DDR 里跑。你需要关注 SPI 控制器的时钟频率和命令集。
- NAND Flash: 容量大,但需要坏块管理。U-Boot 的 NAND 驱动要支持 ECC 校验。我记得第一次移植 NAND 时,忘了配置 ECC 算法,结果读出来的数据全是错的。
- eMMC: 相当于 SD 卡焊在板子上。U-Boot 通过 MMC 控制器访问。你需要确认 eMMC 的初始化序列和分区表。
Flash 的地址映射也很重要。U-Boot 编译出来的二进制文件,要烧写到 Flash 的特定偏移地址。比如,很多板子把 U-Boot 放在 Flash 的 0x0 地址,环境变量放在 0x100000 之后。这些偏移量,你得在 include/configs/your_board.h 里定义好。
4.5 网口与串口:调试的生命线
串口是 U-Boot 调试的命根子。没有串口打印,你根本不知道板子跑到哪一步了。所以,移植的第一步,永远是让串口能输出。
你需要确认:
- UART 实例: 板子上用的是 UART1 还是 UART2?基地址是多少?
- 时钟源: UART 的波特率发生器需要时钟。这个时钟是从哪来的?PLL 还是外部晶振?
- 引脚复用: 原理图上,UART 的 TX/RX 引脚有没有被其他外设复用?需要在 pinctrl 里配置。
网口呢,主要是为了 tftp 下载内核和文件系统。U-Boot 的网卡驱动通常分两部分:MAC 控制器和 PHY 芯片。MAC 控制器集成在 CPU 里,PHY 芯片是外挂的。你需要知道 PHY 的地址(通常是 0x00 到 0x1F 之间的一个值),以及 PHY 的寄存器映射。
4.6 原理图与数据手册查阅方法
很多新手拿到原理图和 datasheet,不知道从哪看起。我分享一下我的查阅顺序:
- 先看原理图的电源树: 板子上有哪些电压域?1.8V、3.3V、VDD_CORE 分别是给谁供电的?电源不对,芯片不工作。
- 再看时钟树: 晶振频率是多少?PLL 怎么配置?时钟是芯片的脉搏,必须搞清楚。
- 然后看启动配置: BOOT 引脚是拉高还是拉低?这决定了 U-Boot 从哪个设备加载。
- 最后看外设连接: DDR 的地址线、数据线怎么连的?网口的 PHY 地址是多少?串口的 TX/RX 接到了哪个引脚?
数据手册呢,我建议先看 Feature List 和 Block Diagram,了解芯片的整体架构。然后跳到 Memory Map,找到各个外设的基地址。最后再看 Register Description,配置具体的寄存器。
4.7 知识结构图:硬件资源梳理流程
下面这张图,是我梳理硬件资源的完整流程。你可以把它当作一个 checklist,每完成一步,就打个勾。
这张图看起来简单,但每一步都可能踩坑。尤其是第 4 步「列出外设清单」,很多人会漏掉一些细节,比如 GPIO 的上下拉、中断引脚的极性。我的建议是,多花点时间在原理图上,把每个引脚的连接都看一遍。
4.8 实战:从原理图到 U-Boot 配置
最后,我们用一个实际例子来串一遍。假设你拿到一块板子,CPU 是 STM32MP157,DDR 是两片 512MB 的 DDR3L,网口 PHY 是 RTL8211F。
你会怎么做?
- 看原理图: 找到 DDR 部分的连接,确认地址线、数据线、控制信号的连接方式。确认 PHY 的地址是 0x01(通过 RXD 引脚拉高配置)。
- 看 datasheet: 找到 STM32MP157 的 DDR 控制器章节,配置时序参数。找到 RTL8211F 的 datasheet,确认寄存器 0x00 的 PHY ID 是 0x001CC916。
- 配置 U-Boot: 在
include/configs/stm32mp15.h里,设置 DDR 的基地址为 0xC0000000,大小为 1GB。设置 PHY 地址为 1,MAC 模式为 RGMII。 - 编译烧写: 编译 U-Boot,烧写到 SPI NOR Flash 的 0x0 地址。上电,看串口输出。
如果串口没输出,别慌。先检查电源,再检查时钟,最后检查 UART 的引脚配置。一步一步来,总能找到问题。
总结一下: 硬件资源梳理,说白了就是「看文档、对原理、填表格」。这个过程很枯燥,但它是 U-Boot 移植的地基。地基打不牢,后面全是白费功夫。我每次移植新板子,都会在这个阶段花上半天到一天时间。磨刀不误砍柴工,这句话在嵌入式开发里尤其适用。