4、U-Boot移植(上):U-Boot源码获取与目录结构分析,板级配置文件的修改

各位同学,欢迎来到U-Boot移植的实战环节。这一章我们不讲虚的,直接上手源码。很多新手拿到U-Boot第一反应就是懵——这么多文件夹,从哪看起?别急,我当年也是这样。今天我就带你把U-Boot的“骨架”摸清楚,再手把手改一个板级配置文件。

4.1 源码获取:别下错了版本

U-Boot的官方仓库在source.denx.de,但说实话,我建议你直接从芯片厂商的BSP包里拿。为什么呢?因为官方主线版本对新型号支持往往滞后,而厂商的版本已经验证过了。

我个人习惯用git克隆,这样方便切换分支和打补丁:

git clone https://source.denx.de/u-boot/u-boot.git
cd u-boot
git checkout v2023.04  # 选一个稳定的LTS版本
注意: 扫地机器人常用的芯片,比如全志、瑞芯微、联发科,它们的U-Boot分支往往在厂商自己的仓库里。我曾经在某个项目里直接拉了主线版本,结果发现DDR初始化代码完全不匹配,板子直接变砖。后来老老实实去厂商官网下了BSP包,才搞定。

4.2 目录结构:抓住主线,忽略细节

U-Boot的目录结构乍一看很吓人,其实核心就几个。我把它分成三类:

类别 目录 作用
架构相关 arch/ CPU架构代码,比如arm、riscv、x86
板级相关 board/ 具体板卡的初始化代码
通用代码 common/、drivers/、fs/ 命令、驱动、文件系统支持

你想想看,我们移植U-Boot,最关心的是哪两个目录?没错,就是arch/board/。其他目录比如net/cmd/,除非你要加特殊功能,否则基本不用动。

嗯,这里要注意include/configs/这个目录。它里面放的是板级的配置文件,以.h结尾。这个文件决定了你的板子用什么外设、内存多大、环境变量放哪。说白了,它就是U-Boot的“性格”文件。

4.3 板级配置文件:从零开始改

假设我们要给一款扫地机器人移植U-Boot,芯片是Allwinner H3。那我们需要创建一个板级目录和配置文件。

第一步,复制参考板:

cp -r board/sunxi/board/sunxi/robot_cleaner
cp include/configs/sunxi-common.h include/configs/robot_cleaner.h

第二步,修改robot_cleaner.h。这里我挑几个关键配置讲:

/* 内存配置 */
#define CONFIG_SYS_SDRAM_BASE       0x40000000
#define CONFIG_SYS_SDRAM_SIZE       0x20000000  /* 512MB */

/* 环境变量存放位置 */
#define CONFIG_ENV_OFFSET           0x80000
#define CONFIG_ENV_SIZE             0x20000

/* 外设使能 */
#define CONFIG_MMC
#define CONFIG_USB_EHCI
#define CONFIG_I2C
核心要点: 内存大小一定要和硬件匹配。我遇到过一位学员,把512MB配成256MB,结果系统只认一半内存,扫地机器人跑着跑着就OOM了。这种问题排查起来特别隐蔽。

第三步,修改board/robot_cleaner/下的板级初始化代码。主要是board_init()dram_init()这两个函数:

int board_init(void)
{
    /* 初始化GPIO,比如控制电机使能 */
    gpio_request(CLEANER_MOTOR_EN, "motor_en");
    gpio_direction_output(CLEANER_MOTOR_EN, 1);

    /* 初始化I2C,用于传感器 */
    i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);

    return 0;
}

int dram_init(void)
{
    /* 读取DDR配置参数,这里用固定值 */
    gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
    return 0;
}
我的经验: 如果你用的是DDR3,建议先跑一遍厂商提供的DDR训练工具,把时序参数记下来。我曾经在H3上直接抄了参考板的DDR配置,结果板子在高温下频繁死机。后来发现是DDR的ODT配置不对,改完就稳了。

4.4 编译与验证:别急着烧录

配置文件改完后,先编译看看能不能通过:

make robot_cleaner_defconfig
make -j4

如果编译通过,会生成u-boot.bin。但别急着烧录!我建议你先用QEMU模拟一下:

qemu-system-arm -M cubieboard -kernel u-boot.bin -nographic

为什么这么做?因为QEMU能帮你快速验证基本功能,比如串口输出、内存读写。等QEMU跑通了,再烧到真板上。这样能省下大量调试时间。

避坑指南: 我曾经在某个项目里,直接烧录了未验证的U-Boot,结果板子起不来,串口也没输出。最后发现是时钟配置错了,PLL没锁住。如果先用QEMU验证,至少能确认串口驱动是好的。

4.5 本章小结

这一章我们做了三件事:

  • 从厂商BSP获取U-Boot源码,而不是盲目拉主线
  • 理清了目录结构,重点关注arch/board/include/configs/
  • 动手修改了板级配置文件,包括内存、外设和板级初始化

下一章,我们会深入U-Boot的启动流程,看看它从汇编到C语言是怎么跳转的。到时候我会分享一个我调试启动流程的“血泪史”,保证让你印象深刻。

好了,今天的课就到这里。记得动手实践,光看是学不会的。有问题随时在群里问我。