• 正文
  • 相关推荐
申请入驻 产业图谱

从现象到本质,彻底搞懂U-Boot env存储机制

16小时前
173
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

前言:

瑞芯微平台的项目开发中,不少工程师都踩过这样一个“诡异”的坑:setenv改完、saveenv也保存了,重启设备后环境变量却莫名地回到了默认值。本文将带你从现象到本质,彻底搞懂U-Boot环境变量的存储机制,并给出完整的配置方案。

一、问题复现

日常开发调试时,我们会需要修改 U-Boot 环境变量(比如调整启动延时bootdelay、修改启动命令),操作步骤很简单,举个例子:

1. 设备上电,串口按Ctrl+C进入 U-Boot 命令行;

2. 查看当前变量:printenv;


3. 修改目标变量(示例改启动延时为 3 秒):setenv bootdelay 3;


4. 保存配置:saveenv,提示保存成功;


5. 重启设备,再次printenv——修改完全消失,变回默认值!


问题的本质在哪里?

二、根因分析

要理解这个现象,需要先搞清楚U-Boot环境变量的存储机制。U-Boot在编译时通过一系列CONFIG宏来决定环境变量的存储位置,而瑞芯微平台的SDK默认配置是:

CONFIG_ENV_IS_NOWHERE

这个配置的语义非常直白——环境变量“无处可存”,这个配置下,环境变量仅存在内存中,saveenv只是临时写入内存,断电 / 重启后内存数据清空,变量自然恢复默认,这就是修改失效的根源。

想要永久保存变量,必须开启存储介质持久化配置,瑞芯微平台常用且推荐以下选项:

配置宏 存储介质
CONFIG_ENV_IS_IN_MMC eMMC / SD卡
CONFIG_ENV_IS_IN_NAND NAND Flash
CONFIG_ENV_IS_IN_SPI_FLASH SPI Flash
CONFIG_ENV_IS_IN_BLK_DEV BLK框架层设备(RK平台推荐)

因此对于瑞芯微平台,尤其是使用eMMC作为存储介质的场景,推荐启用CONFIG_ENV_IS_IN_MMC,将环境变量直接写入eMMC的指定扇区,实现真正的持久化存储

三、解决方案

眺望电子的瑞芯微系列核心板均使用 EMMC 颗粒存储,打开CONFIG_ENV_IS_IN_MMC,搞定永久保存。

3.1  开启Uboot核心配置

在U-Boot的配置中,关闭CONFIG_ENV_IS_NOWHERE,并启用:

CONFIG_ENV_IS_IN_MMC

同时需要关注两个关键参数:

CONFIG_ENV_OFFSET    0x3f8000    // 环境变量在eMMC中的起始偏移地址 
CONFIG_ENV_SIZE      0x8000      // 环境变量占用空间大小(默认32KB)

注意:CONFIG_ENV_OFFSET和CONFIG_ENV_SIZE的具体值需要根据你的分区表和固件布局来确认。后续配置fw_env.config时也会用到这两个值,务必保持一致。

完成上述配置后重新编译U-Boot并烧录,此时通过setenv + saveenv修改的环境变量就会被写入eMMC,重启后依然有效。

3.2  Linux 用户空间操作环境变量

开发后期,不想反复进 U-Boot 命令行,可在 Linux 系统下用fw_printenv/fw_setenv工具直接读写 EMMC 中的 U-Boot 环境变量,使用前需要确保:

已启用 CONFIG_ENV_IS_IN_MMC(否则工具读取不到有效数据)

正确配置 fw_env.config

在U-Boot源码目录下执行:

./make.sh env

执行命令后生成文件


此处需要配置env文件,匹配 EMMC 偏移和大小

git diff fw_env.config
diff --git a/u-boot/tools/env/fw_env.config b/u-boot/tools/env/fw_env.config
index 7916ebd..fd2f7aa 100644
--- a/u-boot/tools/env/fw_env.config
+++ b/u-boot/tools/env/fw_env.config
@@ -8,8 +8,8 @@
 
 # NOR example
 # MTD device name      Device offset   Env. size       Flash sector size       Number of sectors
-/dev/mtd1              0x0000          0x4000          0x4000
-/dev/mtd2              0x0000          0x4000          0x4000
+#/dev/mtd1             0x0000          0x4000          0x4000
+#/dev/mtd2             0x0000          0x4000          0x4000
 
 # MTD SPI-dataflash example
 # MTD device name      Device offset   Env. size       Flash sector size       Number of sectors
@@ -23,7 +23,7 @@
 # end of the device/partition, rather than a forwards offset from the start.
 
 # Block device example
-#/dev/mmcblk0          0xc0000         0x20000
+/dev/mmcblk0           0x3f8000        0x80000
 #/dev/mmcblk0          -0x20000        0x20000
 
 # VFAT example

编译后将fw_env.config 移动到板子的/etc 路径下;

将fw_printenv 移动到板子的/usr/local/bin 路径下;

后续可用该工具进行boot的变更,进行fw_printenv 操作前需要先进行fw_printenv 的软连接

ln -s /usr/bin/fw_printenv /usr/bin/fw_setenv

fw_printenv 查看某个变量:

fw_printenv bootdelay

使用fw_setenv设置环境变量 :

fw_setenv bootdelay 3
fw_printenv

删除一个环境变量:fw_setenv 变量 后不带参数即为删除该变量

fw_setenv bootdelay

注意:如果配置了CONFIG_ENV_IS_IN_MMC 配置,系统启动时会从emmc中读取env信息,此处EMMC的env信息并不会随着烧录而进行更改 将会永远保持不变。

可以通过瑞芯微的擦除所有扇区工具进行清除,清除该EMMC的env信息之后,后续初次重启将会变为默认的env信息。

四、进阶操作

如果需要固件携带一组默认的环境变量,而不是依赖首次启动后的手动配置,那如何从源码中进行环境变量的更改呢???

要想从源码目录进行参数的更改需要进行如下操作:

默认环境变量定义在:

u-boot/include/env_default.h

找到default_environment数组,这里列出了所有编译期固化的环境变量。例如,修改bootdelay的默认值,可以找到:

"bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0"

然后修改对应的CONFIG_BOOTDELAY配置即可。


如果需要添加全新的自定义环境变量,直接在数组中添加一行:

diff --git a/u-boot/include/env_default.h b/u-boot/include/env_default.h
index 853c290..446bfe6 100644
--- a/u-boot/include/env_default.h
+++ b/u-boot/include/env_default.h
@@ -103,6 +103,7 @@ const uchar default_environment[] = {
 
#ifdef
 CONFIG_SYS_SOC
        "soc="          CONFIG_SYS_SOC                  "\0"
 
#endif
+       "YWF_ENV="   "2002" "\0"
 
#ifdef
 CONFIG_SILENT_CONSOLE
        "silent=enable\0"
 
#endif

"YWF_ENV=" "2002" "\0"

重新编译U-Boot后,这个新变量就会出现在默认环境变量中,用户依然可以通过setenv在运行时覆盖它。

五、总结

瑞芯微 U-Boot 环境变量修改失效,核心就是关闭CONFIG_ENV_IS_NOWHERE、开启CONFIG_ENV_IS_IN_MMC,配合saveenv即可永久保存;

本文从日常调试用 U-Boot 命令行,批量维护改源码默认值,后期运维用 Linux 工具,三种场景全覆盖,掌握这一套配置逻辑,无论是开发调试还是量产维护,再也不用反复踩坑!

关注“眺望电子”,获取更多嵌入式Linux调试实战经验!

相关推荐