前言:
在瑞芯微平台的项目开发中,不少工程师都踩过这样一个“诡异”的坑: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.2Linux 用户空间操作环境变量
开发后期,不想反复进 U-Boot 命令行,可在 Linux 系统下用fw_printenv/fw_setenv工具直接读写 EMMC 中的 U-Boot 环境变量,使用前需要确保:
已启用 CONFIG_ENV_IS_IN_MMC(否则工具读取不到有效数据)
正确配置 fw_env.config
在U-Boot源码目录下执行:
./make.shenv

执行命令后生成文件

此处需要配置env文件,匹配 EMMC 偏移和大小
git diff fw_env.configdiff --git a/u-boot/tools/env/fw_env.config b/u-boot/tools/env/fw_env.configindex 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_printenvbootdelay
使用fw_setenv设置环境变量 :
fw_setenvbootdelay3fw_printenv
删除一个环境变量:fw_setenv 变量 后不带参数即为删除该变量
fw_setenvbootdelay
注意:如果配置了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.hindex 853c290..446bfe6100644---a/u-boot/include/env_default.h+++b/u-boot/include/env_default.h@@-103,6+103,7@@ const uchar default_environment[]={#ifdefCONFIG_SYS_SOC "soc=" CONFIG_SYS_SOC "\0"#endif+ "YWF_ENV=" "2002""\0"#ifdefCONFIG_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 工具,三种场景全覆盖,掌握这一套配置逻辑,无论是开发调试还是量产维护,再也不用反复踩坑!
-
嵌入式
+关注
关注
5212文章
20746浏览量
338441 -
u-boot
+关注
关注
0文章
141浏览量
39993 -
瑞芯微
+关注
关注
27文章
896浏览量
54723
发布评论请先 登录
U-boot的基本介绍
U-Boot的启动及移植分析
Porting U-Boot to the Control
u-boot的Makefile分析
U-Boot结构功能介绍
u-boot学习指南
u-boot简介
U-Boot架构浅析
u-boot armv8链接脚本
深入理解 RK3506 U-Boot 重定位:从代码到原理
深度解析 RK 平台 U-Boot 环境变量(env):原理、配置与实战
从现象到本质,彻底搞懂U-Boot env存储机制
评论