4. 开发环境搭建
U-Boot移植,说白了就是让Bootloader认识你的板子。很多新手一上来就想着改代码,其实最关键的步骤反而不是改,而是搞清楚你的板子跟哪个参考板最像。我这些年移植过的板子少说也有几十块,踩过的坑能写满一本笔记本。今天咱们就从零开始,把U-Boot移植的完整流程走一遍。
4.1 获取U-Boot源码
U-Boot的源码管理用的是git,这个没什么好说的。我个人习惯从官方仓库拉取LTS版本,稳定且社区支持好。
git clone https://source.denx.de/u-boot/u-boot.git
cd u-boot
git checkout v2024.01
为什么要切到具体版本?因为master分支可能正在开发中,今天能编过明天可能就挂了。我在项目中遇到过好几次,追着master跑结果编译环境跟着变,最后浪费一整天排查。
4.2 理解U-Boot的板级结构
拿到源码后,先别急着编译。你得搞清楚U-Boot是怎么组织板级代码的。说白了,每个板子对应三个核心目录:
| 目录/文件 | 作用 | 我常踩的坑 |
|---|---|---|
board/<vendor>/<board_name>/ |
板级初始化代码、低层驱动 | 忘记改board.c中的board_init函数 |
include/configs/<board_name>.h |
板级配置宏定义 | DDR参数配错,板子直接变砖 |
arch/arm/dts/<board_name>.dts |
设备树描述硬件拓扑 | 引脚复用没对上,外设死活不工作 |
嗯,这里要注意:设备树现在是U-Boot的主流配置方式。老版本的board.c里硬编码的初始化逻辑,现在都移到dts里了。你想想看,改一个dts文件比改C代码安全多了,至少不会因为一个指针越界就死机。
4.3 选择参考板
移植U-Boot最聪明的做法不是从头写,而是找一个跟你目标板最接近的参考板,然后复制粘贴再修改。我一般按这个优先级找:
- 同芯片厂商、同系列 —— 比如你的板子是i.MX8M Mini,那就找i.MX8M Nano的参考板
- 同SoC、不同外设 —— 比如都是全志H3,但你的板子网卡芯片不同
- 同架构、同内存类型 —— 实在找不到,至少DDR控制器要一样
核心原则: 参考板的DDR初始化代码可以直接复用,这是移植成功的关键。DDR参数配错了,U-Boot连串口都打印不出来。
4.4 添加新板级支持
假设我选好了参考板,现在要添加自己的板子。以添加一块名为"myboard"的板子为例:
4.4.1 创建板级目录
mkdir board/myvendor/myboard
cp -r board/refvendor/refboard/* board/myvendor/myboard/
复制完后,记得把目录里的文件名和内容中的"refboard"全部替换成"myboard"。我曾经有一次漏改了Kconfig里的板名,结果编译出来的U-Boot还是参考板的配置,串口打印的还是参考板的名字,排查了半天才发现。
4.4.2 配置单板
U-Boot用Kconfig管理配置,所以你得在几个地方注册你的板子:
arch/arm/mach-imx/Kconfig—— 添加你的板子选项board/myvendor/myboard/Kconfig—— 板级配置菜单board/myvendor/myboard/MAINTAINERS—— 维护者信息
举个例子,在Kconfig里添加:
config TARGET_MYBOARD
bool "Support myboard"
select CPU_V8
select IMX8M
help
Support for MyBoard based on i.MX8M Mini
4.4.3 创建设备树
设备树是U-Boot认识硬件的眼睛。复制参考板的dts,然后修改:
cp arch/arm/dts/refboard.dts arch/arm/dts/myboard.dts
你需要改的主要是:
- 内存节点 —— 容量和地址
- 串口节点 —— 引脚复用和时钟
- 网卡节点 —— PHY地址和复位引脚
- GPIO和LED —— 板级特色功能
4.5 编译U-Boot
配置和编译命令其实很固定:
make myboard_defconfig
make -j$(nproc)
但这里有个坑:交叉编译工具链必须提前配好。我习惯用环境变量指定:
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm
如果你用的是ARM 32位,CROSS_COMPILE就是arm-linux-gnueabihf-。这个搞错了,编译出来的二进制在目标板上跑不起来。
4.6 烧录与验证
编译成功后,你会得到u-boot.bin或u-boot.imx(取决于芯片)。烧录方式因平台而异:
| 芯片平台 | 烧录方式 | 常见工具 |
|---|---|---|
| i.MX系列 | SD卡烧录 | dd if=u-boot.imx of=/dev/sdb bs=1k seek=1 |
| 全志系列 | FEL模式 + USB烧录 | sunxi-fel |
| Rockchip系列 | Maskrom模式 + 工具烧录 | rkdeveloptool |
烧录完成后,上电看串口输出。如果能看到U-Boot的启动日志,恭喜你,移植成功了第一步。如果没有任何输出,别慌,先检查:
- 串口电平是否匹配(3.3V vs 1.8V)
- DDR初始化是否成功(很多芯片会通过LED闪烁指示)
- 启动介质选择是否正确(SD卡还是eMMC)
我的调试习惯: 第一次移植时,我会在board_init_f函数里加一个GPIO翻转的代码。如果GPIO能翻转,说明CPU已经跑起来了,问题出在后面的初始化。这个技巧帮我快速定位过至少5次DDR配置错误。
4.7 本章知识体系
下面这张图总结了U-Boot移植的核心流程,我建议你把它打印出来贴在工位上:
这张图把整个流程串起来了。你注意看,从获取源码到烧录验证,每一步都依赖上一步的正确性。尤其是选择参考板这一步,很多人图省事随便选一个,结果后面DDR初始化调了一周都没搞定。我建议你花半天时间仔细对比参考板和目标板的原理图,把差异列出来再动手。