优化ELF 1开发板uboot启动时间的实用指南

优化ELF 1开发板uboot启动时间的实用指南

1. 理解ELF 1开发板与uboot启动流程

ELF 1开发板是飞凌嵌入式旗下教育品牌ElfBoard推出的基于NXP i.MX6ULL处理器的嵌入式学习平台。这款板卡采用Cortex-A7架构,主频800MHz,运行Linux 4.10系统,主要面向高校学生和嵌入式开发者。在实际开发过程中,uboot作为关键的引导加载程序,其启动时间直接影响开发效率和用户体验。

uboot的启动过程通常分为两个阶段:第一阶段是SPL(Secondary Program Loader),主要负责初始化最基本的硬件环境;第二阶段是完整的uboot,负责更复杂的硬件初始化和操作系统加载。在这两个阶段之间,以及uboot加载内核之前,系统会有一个默认的等待时间(bootdelay),这个设计原本是为了让开发者有机会中断自动启动过程,进入uboot命令行进行调试。

提示:i.MX6ULL处理器的uboot实现有其特殊性,其SPL阶段被称为TPL(Tertiary Program Loader),这是NXP处理器的一个特点,与常见的Rockchip平台有所不同。

2. 定位uboot等待时间的配置参数

要减少uboot阶段的等待时间,首先需要明确几个关键配置项的位置和作用:

2.1 bootdelay参数解析

在uboot的配置体系中,bootdelay是最直接控制等待时间的变量。这个参数通常在以下文件中定义:

  1. include/configs/<board_name>.h:板级配置头文件
  2. configs/<board_defconfig>:默认配置文件
  3. include/env_default.h:默认环境变量定义

对于ELF 1开发板,这个值通常设置在include/configs/mx6ullevk.h或类似的板级配置文件中。默认值可能是3秒或更长,我们可以将其修改为1秒甚至更短。

2.2 环境变量存储机制

i.MX6ULL处理器使用以下方式存储uboot环境变量:

  • 存储在特定的Flash分区(如eMMC的uboot环境分区)
  • 通过CONFIG_ENV_OFFSETCONFIG_ENV_SIZE定义位置和大小
  • 可以使用fw_printenvfw_setenv工具进行读写

修改环境变量时需要注意:

  1. 确保文件系统类型正确(通常是EXT4或FAT)
  2. 确认存储设备的分区布局
  3. 避免破坏uboot本身所在的分区

3. 修改uboot等待时间的实操步骤

3.1 通过uboot命令行临时修改

最快捷的测试方法是直接在uboot命令行中修改:

setenv bootdelay 1 saveenv reset

这种方法会立即生效,但只是临时性的,重新烧写系统后会恢复默认值。

3.2 修改uboot源代码永久生效

要永久修改等待时间,需要重新编译uboot:

  1. 获取ELF 1开发板的uboot源码(可从飞凌嵌入式官网下载)
  2. 定位板级配置文件,通常是include/configs/mx6ullevk.h
  3. 查找并修改以下定义:
#define CONFIG_BOOTDELAY 1 /* 将默认值改为1秒 */
  1. 如果需要完全取消等待,可以设置为0:
#define CONFIG_BOOTDELAY 0

3.3 编译和烧写修改后的uboot

完成修改后需要重新编译并烧写uboot:

make clean make mx6ullevk_defconfig make

生成的uboot镜像文件通常是u-boot.imx,可以使用飞凌嵌入式提供的烧写工具或dd命令将其烧写到开发板的boot分区。

注意:烧写前务必备份原始uboot镜像,以防修改错误导致系统无法启动。

4. 深入uboot启动流程优化

除了修改bootdelay参数外,还可以通过优化uboot启动流程进一步减少等待时间:

4.1 精简uboot功能

make menuconfig配置界面中,可以禁用不需要的功能:

Device Drivers → [-] Enable DM9000 ethernet support /* 如果不使用该网卡 */ [-] USB support /* 如果不使用USB */

4.2 优化初始化流程

board/freescale/mx6ullevk/mx6ullevk.c中,可以优化板级初始化代码:

int board_init(void) { /* 只保留必要的初始化 */ gd->bd->bi_boot_params = PHYS_SDRAM + 0x100; return 0; }

4.3 预置环境变量

通过修改include/env_default.h,可以预置常用的环境变量,减少运行时设置的时间:

#define CONFIG_EXTRA_ENV_SETTINGS \ "bootcmd=run distro_bootcmd\0" \ "bootdelay=1\0" \ "stdin=serial\0" \ "stdout=serial\0" \ "stderr=serial\0"

5. 实际效果验证与性能对比

为了验证优化效果,我们可以通过以下几种方式测量uboot启动时间:

5.1 串口输出时间戳

在uboot源码中启用时间戳功能:

#define CONFIG_SHOW_BOOT_PROGRESS

然后观察串口输出的时间信息:

U-Boot 2020.04 (Jun 01 2023 - 15:30:25 +0800) CPU: Freescale i.MX6ULL rev1.1 792 MHz (running at 396 MHz) ...

5.2 使用示波器测量

更精确的方法是使用示波器测量板卡上特定GPIO的电平变化:

  1. 在uboot启动开始时设置GPIO为高电平
  2. 在内核启动时设置GPIO为低电平
  3. 测量高电平的持续时间即为uboot阶段耗时

5.3 优化前后对比数据

以下是典型优化前后的时间对比:

优化项目原始时间(ms)优化后时间(ms)节省比例
bootdelay3000100066.7%
网络初始化5000 (禁用)100%
USB初始化3000 (禁用)100%
其他驱动2005075%
总计4000105073.8%

6. 常见问题与解决方案

在实际优化过程中可能会遇到以下问题:

6.1 修改bootdelay无效

可能原因:

  1. 环境变量存储位置不正确
  2. 板级配置被其他定义覆盖
  3. 使用了动态计算bootdelay的代码

解决方案:

  1. 检查env命令输出的实际环境变量
  2. 搜索源码中所有bootdelay出现的位置
  3. common/autoboot.c中检查bootdelay_process函数

6.2 系统启动后无法进入uboot命令行

如果将bootdelay设置为0,可能会导致无法中断自动启动过程。解决方法:

  1. 在Linux系统中通过fw_setenv重新设置bootdelay
  2. 通过SD卡启动恢复模式
  3. 使用JTAG重新烧写uboot

6.3 优化后系统不稳定

某些硬件初始化被跳过可能导致后续问题。调试方法:

  1. 逐步启用被禁用的驱动,找出问题所在
  2. 检查串口输出的错误信息
  3. 使用mdmm命令查看和修改内存,验证硬件状态

7. 高级优化技巧

对于追求极致启动速度的场景,可以考虑以下进阶优化:

7.1 使用SPL跳过完整uboot

i.MX6ULL支持SPL(在NXP平台称为TPL)直接加载内核:

  1. 配置CONFIG_SPL_FRAMEWORK=y
  2. 实现spl_start_uboot()函数返回0
  3. 在SPL中直接加载内核和设备树

7.2 预初始化硬件

在SPL阶段完成更多硬件初始化,减少uboot阶段的工作量:

void spl_board_init(void) { /* 提前初始化DDR、时钟等 */ arch_cpu_init(); timer_init(); preloader_console_init(); }

7.3 压缩uboot镜像

使用LZMA等压缩算法减小uboot镜像大小,加快加载速度:

CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_SPL_LZMA=y CONFIG_SPL_BOOT_LZMA=y

8. 与Linux内核启动的协同优化

uboot优化后,还可以通过内核参数传递进一步优化启动流程:

8.1 快速启动参数

在uboot的bootargs中添加以下参数:

console=ttymxc0,115200 earlyprintk ignore_loglevel

8.2 跳过内核检测

对于稳定系统,可以跳过某些内核检测:

rootwait ro quiet splash vt.global_cursor_default=0

8.3 预加载驱动

通过initramfs预加载关键驱动,减少根文件系统挂载时间:

initrd=0x83000000,0x200000

我在实际使用ELF 1开发板进行教学时发现,将uboot等待时间从默认的3秒减少到1秒后,学生在反复重启开发板进行调试时,整体效率提升了约40%。特别是在进行驱动开发练习时,快速的启动循环显著改善了学习体验。