1. 多板型固件统一方案的背景与价值在嵌入式开发领域我们经常会遇到这样的场景基于同一款RK SoC比如RK3568或RK3588开发了多款硬件配置不同的板卡。这些板卡可能内存容量不同、外设接口有差异或者是针对不同应用场景做了定制化设计。传统做法是为每款板卡单独维护一套固件这不仅增加了开发工作量还给后期维护和升级带来了巨大挑战。我去年参与的一个智能终端项目就遇到了这个问题。项目使用了RK3568平台但因为客户需求差异衍生出了7个硬件版本。每次功能升级都要重复编译7次固件测试团队也需要对每个版本进行完整验证整个流程耗时耗力。后来我们采用了HWID多DTB的方案将维护成本降低了70%。这种方案的核心价值在于降低维护成本只需维护一套代码仓库通过硬件识别自动适配不同板型提升部署效率产线烧录时无需频繁更换固件镜像减少人为错误避免因选错固件版本导致的批量返工灵活应对硬件迭代新增板型时只需扩展DTB配置无需重构整个系统2. 硬件层面的HWID设计原理2.1 HWID的物理实现方式要让固件能自动识别不同板型首先需要在硬件上设计可靠的识别机制。常见的有三种实现方案ADC电压检测通过电阻分压网络产生不同电压值典型电路VCC → 电阻R1 → ADC引脚 → 电阻R2 → GND计算公式Vadc VCC × R2/(R1R2)优点成本低占用IO少缺点受电源波动影响精度要求高GPIO组合编码使用多个GPIO的高低电平组合例如用3个GPIO可表示8种板型2^3优点识别可靠抗干扰强缺点占用IO资源较多EEPROM存储在板卡上预烧录识别信息优点可存储更多元信息缺点增加BOM成本以RK3568-EVB开发板为例其HWID设计采用ADC方案// 板型定义与ADC值对应关系 #define BOARD_EVB1 1023 // ADC通道1满量程 #define BOARD_EVB2 852 // ADC通道1约83%量程2.2 硬件设计注意事项在实际项目中我总结出几个硬件设计要点ADC采样稳定性建议增加0.1uF滤波电容采样次数≥3次取平均电阻选型使用1%精度电阻温度系数≤100ppm防误触设计GPIO方案要加上拉/下拉电阻避免悬空状态测试点预留在生产测试环节需要预留HWID测量点曾经有个项目因为ADC分压电阻选用了5%精度的普通电阻导致量产后出现约3%的板卡识别错误。后来改用金属膜电阻并调整分压比后才解决问题。3. U-Boot阶段的硬件识别3.1 U-Boot配置修改要让U-Boot支持HWID功能需要先开启相关配置选项。以RK3568为例--- a/configs/rk3568_defconfig b/configs/rk3568_defconfig -217,3 217,4 CONFIG_RK_AVB_LIBAVB_USERy CONFIG_OPTEE_CLIENTy CONFIG_OPTEE_V2y CONFIG_OPTEE_ALWAYS_USE_SECURITY_PARTITIONy CONFIG_ROCKCHIP_HWID_DTBy这个配置会启用Rockchip的HWID驱动主要实现以下功能初始化ADC或GPIO硬件读取当前板型的识别码根据识别码选择对应的DTB文件3.2 DTB选择机制U-Boot中HWID的处理流程如下编译时将所有板型的DTB打包成multi-dtb镜像启动时读取硬件识别码在multi-dtb中匹配对应的DTB节点将匹配的DTB地址传递给内核关键代码位于drivers/misc/rockchip-hwid.cint board_fdt_blob_setup(void *blob, struct bd_info *bd) { int hwid rockchip_get_hwid(); return fdt_multi_dtb_select(blob, hwid); }4. Linux内核的适配改造4.1 内核设备树配置内核侧需要确保所有板型的DTB都被编译出来。修改内核编译脚本DTBS[RK3568-EVB] OrderedDict([ (rk3568-evb2-lp4x-v10, #_saradc_ch1852), (rk3568-evb1-ddr4-v10, #_saradc_ch11023) ])这个配置表示当ADC通道1值为852时使用evb2的设备树当值为1023时使用evb1的设备树#_saradc_ch1是Rockchip定义的硬件匹配语法4.2 内核驱动适配对于有差异的外设驱动需要通过HWID做运行时判断。以以太网PHY为例static int phy_init_hw(struct phy_device *phydev) { int board_type rockchip_get_board_type(); switch(board_type) { case BOARD_EVB1: phy_write(phydev, 0x1E, 0x21); // EVB1特殊配置 break; case BOARD_EVB2: phy_write(phydev, 0x1F, 0x40); // EVB2特殊配置 break; } return 0; }5. 构建系统的自动化改造5.1 编译脚本修改Android构建系统需要修改build.sh支持多DTB编译function build_multidtb() { if [ $TARGET_PRODUCT rk3588_s ]; then for (( i 0 ; i ${#RK3588_DTS[]} ; i )) do echo make ${RK3588_DTS[$i]} ..... make $ADDON_ARGS ARCH$KERNEL_ARCH ${RK3588_DTS[$i]}.img -j$BUILD_JOBS done ./scripts/mkmultidtb.py RK3588-EVB fi echo build dtb succes................. }主要新增功能遍历编译所有板型的DTB调用mkmultidtb.py生成复合DTB保留原有单板编译路径5.2 资源文件处理不同板型可能需要不同的启动logo或充电图片建议通过资源覆盖机制实现out/target/product/rk3568/ ├── obj/BOARD1/resource.img ├── obj/BOARD2/resource.img └── resource.img - obj/$(BOARD_TYPE)/resource.img6. 量产测试与问题排查6.1 生产测试要点在量产阶段需要重点验证HWID识别率抽样测试1000次识别要求错误率0.1%DTB匹配正确性通过内核日志确认加载的DTB版本外设功能验证针对不同板型的特色外设做专项测试建议在U-Boot中添加测试命令 hwid test Testing ADC channel 1... Sample 1: 852 mV Sample 2: 853 mV Sample 3: 851 mV Board type: RK3568-EVB2 (code:2)6.2 常见问题解决问题1HWID识别不稳定检查ADC参考电压是否稳定增加软件去抖算法如中值滤波问题2DTB匹配失败确认mkmultidtb.py中的板型定义与硬件一致检查U-Boot的fdt_control参数设置问题3资源文件不匹配验证resource.img的生成逻辑检查板型标识的传递链路7. 方案扩展与优化对于更复杂的场景可以考虑以下增强方案动态设备树叠加void apply_board_overlay(void *fdt) { int hwid get_hardware_id(); switch(hwid) { case BOARD_A: fdt_apply_overlay(fdt, board_a.dtbo); break; case BOARD_B: fdt_apply_overlay(fdt, board_b.dtbo); break; } }AB分区升级在bootloader中实现双备份DTB存储升级时先校验新DTB与当前HWID的兼容性验证通过后再执行分区切换在实际项目中我还遇到过需要支持热插拔板卡识别的场景。这时需要在驱动中注册notifier当检测到硬件变化时动态重载设备树。这种方案实现起来比较复杂但对某些工业应用场景很有价值。