
清空记录
历史记录
取消
清空记录
历史记录

在U-Boot 命令行里想读取SoC 温度、查看某个寄存器的值、或执行一个产测功能,却发现没有现成命令——这是BSP工程师调试RK平台时经常遇到的场景。
U-Boot 的交互式命令行允许通过U_BOOT_CMD宏注册自定义命令,只需三步:实现一个符合签名的do_xxx函数、用宏注册命令、在cmd/Makefile中添加一行编译目标。本文以触觉智能常见的瑞芯微RK平台为例(适用 RK3562/RK3576/RK3588等SoC方案),从宏定义展开到完整可编译的 temperature 命令示例,讲解如何添加一条自定义调试命令。
一、U_BOOT_CMD 宏的完整定义
U_BOOT_CMD是U‑Boot命令注册的核心宏,定义在include/command.h中:
// include/command.h (精简)
#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \
U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)
// 展开后的实际声明:
#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
ll_entry_declare(cmd_tbl_t, _name, cmd) = \
{ #_name, _maxargs, _rep, _cmd, _usage, _CMD_HELP(_help) \
_CMD_COMPLETE(_comp) }每个参数的含义:
参数 | 类型 | 说明 |
_name | 标识符 | 命令名称(成为cmd_tbl_t 结构体变量名) |
_maxargs | int | 最大参数个数(含命令本身,典型值 3~8) |
_rep | int | 是否支持自动重复(1 = 支持,0 = 不支持) |
_cmd | 函数指针 | 实现函数:int do_xxx(cmd_tbl_t *, int, int, char * const []) |
_usage | 字符串 | 简短用法说明(help输出第一行) |
_help | 字符串 | 详细帮助文本(help cmd输出) |
U_BOOT_CMD展开后通过链接器列表机制(ll_entry_declare)将cmd_tbl_t结构体放入特定的.u_boot_list_cmd段。U‑Boot启动时,find_cmd()遍历该段查找匹配的命令名。
二、do_xxx函数签名
自定义命令的入口函数必须遵循以下签名:
// 标准签名(cmd_tbl_t 是 struct cmd_tbl_s 的 typedef) int do_xxx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); /* 参数说明: * cmdtp - 命令表项指针(指向当前命令的描述) * flag - 标志位,CMD_FLAG_REPEAT=重复执行,CMD_FLAG_BOOTD=来自bootd * argc - 参数个数(argv[0]是命令本身) * argv - 参数字符串数组 * * 返回值: * CMD_RET_SUCCESS (0) - 命令执行成功 * CMD_RET_FAILURE (1) - 命令执行失败 * CMD_RET_USAGE (-1) - 参数错误,框架自动调用cmd_usage() */
// include/command.h 中 cmd_tbl_t 的完整定义
struct cmd_tbl_s {
char *name; /* 命令名称 */
int maxargs; /* 最大参数个数 */
int repeatable; /* 是否支持自动重复 */
int (*cmd)(struct cmd_tbl_s *, int, int, char * const []); /* 实现函数 */
char *usage; /* 简短用法("help"输出第一行) */
#ifdef CONFIG_SYS_LONGHELP
char *help; /* 详细帮助("help cmd"输出) */
#endif
#ifdef CONFIG_AUTO_COMPLETE
int (*complete)(int argc, char * const argv[],
char last_char, int maxv, char *cmdv[]);
#endif
};
typedef struct cmd_tbl_s cmd_tbl_t;三、cmd/Makefile注册
新命令的.c文件放入cmd/目录后,需要在cmd/Makefile中添加一行才能参与编译:
# cmd/Makefile (位于 cmd/ 目录) # 格式: obj-$(CONFIG_CMD_XXXX) += my_command.o # 示例——RK平台已有命令: obj-$(CONFIG_CMD_BOOT_ANDROID) += boot_android.o android.o obj-$(CONFIG_CMD_BOOT_FIT) += bootfit.o obj-$(CONFIG_CMD_AVB) += avb.o obj-$(CONFIG_CMD_CLK) += clk.o obj-$(CONFIG_CMD_GPIO) += gpio.o obj-$(CONFIG_CMD_TEMPERATURE) += temperature.o # 我们的新命令
对应的Kconfig选项:
# cmd/Kconfig 中按字母顺序添加 config CMD_TEMPERATURE bool "temperature - read SoC/board temperature sensors" default n help Read temperature from SoC internal sensor or external sensor via the U‑Boot driver model (UCLASS_THERMAL).
四、命令执行完整流程
五、完整示例:temperature 命令
以下是一个完整的自定义命令,通过U‑Boot的thermal驱动模型读取SoC温度:
/* cmd/temperature.c — 完整的可编译示例 */
#include <common.h>
#include <command.h>
#include <dm.h>
#include <thermal.h>
/*
* do_temperature - 读取SoC温度传感器
*
* 用法:
* temperature - 列出所有温度传感器
* temperature soc - 读取SoC内部温度
* temperature soc 0 - 读取传感器0的温度
*/
static int do_temperature(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
struct udevice *dev;
int ret, i, temp;
switch (argc) {
case 1:
/* 无参数: 列出所有thermal设备 */
printf("Thermal devices:\n");
for (i = 0; i < 4; i++) {
char name[32];
snprintf(name, sizeof(name), "thermal@%d", i);
ret = uclass_get_device_by_name(UCLASS_THERMAL,
name, &dev);
if (ret)
break;
printf(" %s: found\n", name);
}
if (i == 0)
printf(" (no thermal devices found)\n");
return CMD_RET_SUCCESS;
case 2:
/* 一个参数: 读取温度 */
if (strcmp(argv[1], "soc") == 0) {
/* 查找SoC thermal设备 */
ret = uclass_get_device(UCLASS_THERMAL, 0, &dev);
if (ret) {
printf("Failed to get thermal device: %d\n",
ret);
return CMD_RET_FAILURE;
}
ret = thermal_get_temp(dev, &temp);
if (ret) {
printf("Failed to read temperature: %d\n",
ret);
return CMD_RET_FAILURE;
}
/* thermal_get_temp 返回毫摄氏度 */
printf("SoC temperature: %d.%03d C\n",
temp / 1000, temp % 1000);
return CMD_RET_SUCCESS;
}
return CMD_RET_USAGE;
default:
return CMD_RET_USAGE;
}
}
/* 注册命令 (对应CONFIG_CMD_TEMPERATURE) */
U_BOOT_CMD(
temperature, 3, 0, do_temperature,
"Read SoC/board temperature",
"\n - List thermal devices\n"
"temperature soc\n"
" - Read SoC temperature from first thermal sensor\n"
);编译与测试:
# 1. 创建文件 $ cat > u‑boot/cmd/temperature.c << 'EOF' ... (上述代码) ... EOF # 2. 修改 cmd/Makefile,添加一行 $ echo "obj-\$(CONFIG_CMD_TEMPERATURE) += temperature.o" >> cmd/Makefile # 3. 启用Kconfig选项 $ make menuconfig # → Command line interface → temperature # 或直接修改 defconfig: $ echo "CONFIG_CMD_TEMPERATURE=y" >> configs/evb_rk3576_defconfig # 4. 编译 $ make CROSS_COMPILE=aarch64‑linux‑gnu‑ # 5. 运行结果 U‑Boot> temperature Thermal devices: thermal@0: found U‑Boot> temperature soc SoC temperature: 42.315 °C U‑Boot> temperature bad_arg Usage: temperature - Read SoC/board temperature - List thermal devices temperature soc - Read SoC temperature from first thermal sensor
六、命令参数解析详解
U‑Boot命令的参数解析遵循标准的argc/argv模式:
/* argc/argv 示例: "temperature soc 0" * argc = 3 * argv[0] = "temperature" <- 命令名 * argv[1] = "soc" <- 子命令 * argv[2] = "0" <- 传感器编号 * * 常用解析模式: * 模式1: 字符串比较 (子命令分发) * 模式2: 数字参数 (simple_strtoul 无错误检查) * 模式3: 十六进制参数 * 模式4: 可选参数 */ /* 模式1: 字符串比较 (子命令分发) */ if (!strcmp(argv[1], "soc")) handle_soc(); else if (!strcmp(argv[1], "board")) handle_board(); else return CMD_RET_USAGE; /* 模式2: 数字参数 (simple_strtoul 无错误检查) */ int value = simple_strtoul(argv[2], NULL, 10); /* 模式3: 十六进制参数 */ ulong addr = hextoul(argv[1], NULL); /* 模式4: 可选参数 */ if (argc >= 3) handle_with_arg(argv[2]); else handle_default();
注意:simple_strtoul不会报告转换错误——如果参数不是有效数字,它静默返回 0。如果需要严格校验,可以用strict_strtoul或自行检查转换终点指针。 |
七、添加命令的最佳实践
1.使用Kconfig控制编译—为每条命令添加独立的CONFIG_CMD_XXX开关,避免在非目标平台强制编译
2.善用CMD_RET_USAGE—参数错误时返回CMD_RET_USAGE,框架会自动打印帮助信息
3.help文本格式—usage参数写简短描述(help命令显示),help参数写详细用法(help cmd显示)
4.利用驱动模型—优先通过uclass_get_device()访问硬件,而非直接操作寄存器
5.内存安全—命令行环境可用内存有限,避免大块栈分配,使用malloc/free
/* 更完整的命令模板 */
static int do_mycmd(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
if (argc < 2)
return CMD_RET_USAGE;
if (!strcmp(argv[1], "info")) {
/* 信息查询 */
} else if (!strcmp(argv[1], "set")) {
if (argc < 3)
return CMD_RET_USAGE;
/* 设置操作 */
} else {
return CMD_RET_USAGE;
}
return CMD_RET_SUCCESS;
}Purple Pi OH2开发板,是触觉智能RK3576核心板SOM7609系列配套的评估开发板,搭载4核A72+4核A53+M0多核异构处理器,主频2.2GHz,集成6Tops算力 NPU,轻松应对AI推理、边缘计算与轻量级AI端侧学习。配套完善SDK、丰富资料与Demo,有助于项目前期快速开发验证。
触觉智能SOM7609系列核心板尺寸仅40.5×40.5mm,专为空间受限场景打造。基于RK3576/RK3576J SoC,集成高性能GPU与VPU,支持4K视频编解码与多屏异显;提供PCIe、USB3.2、双路千兆以太网、MIPI-DSI、多路MIP CSI、eDP、CAN、SPI、I2C等丰富接口,灵活扩展。支持Linux、Android、开源鸿蒙OpenHarmony等系统。
