在U-Boot中为RK3588添加SARADC检测:从零到一的硬件识别方案

电子说

1.4w人已加入

描述

 

 

在嵌入式开发中,我们经常需要在系统启动的早期阶段(U-Boot)识别硬件版本或配置。本文将详细介绍如何在 U-Boot 中为 RK3588 平台添加 SARADCSuccessive Approximation Register Analog-to-Digital Converter)检测功能,通过读取 ADC 电压值来区分不同的硬件版本,并将结果存入环境变量,为后续的启动流程提供依据。

adc

核心思路与应用场景

 

为什么需要在 U-Boot 中做 ADC 检测?

 

 

U-Boot 作为引导加载程序,运行在操作系统内核之前,拥有极高的硬件访问权限。在这个阶段进行 ADC 检测,可以实现:

 

 

硬件版本自动识别:通过读取主板上由电阻分压网络决定的 ADC 引脚电压,U-Boot 可以判断出当前硬件的具体型号或版本。

 

 

动态配置加载:根据识别出的硬件版本,U-Boot 可以加载不同的设备树(Device Tree)、启动参数或执行特定的初始化脚本,实现 一镜像适配多硬件” 的目标。

 

 

故障诊断:检测关键电源电压或传感器状态,在启动早期发现硬件异常。

 

 

第一步:配置 SARADC 设备树 (DTS)

 

要在 U-Boot 中使用 SARADC,首先需要确保其设备树节点已正确配置并启用。

 

 

文件路径u-boot/arch/arm/dts/rk3588-u-boot.dtsi

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
/* 在 rk3588-u-boot.dtsi 文件中找到并确认 saradc 节点 */&saradc {    /*     * u-boot, dm-pre-reloc; 是一个关键属性,     * 它告诉 U-Boot 的驱动模型(Driver Model)     * 在 relocation(重定位)之前就初始化这个设备。     * 因为我们要在 board_init_f 阶段(重定位前)读取ADC,     * 所以必须添加此属性。     */    u-boot, dm-pre-reloc;     status = "okay";};

代码解读:

 

 

&saradc引用主设备树中定义的saradc节点。

 

 

u-boot, dm-pre-reloc;核心配置。确保 SARADC 驱动在 U-Boot 早期阶段(内存重定位前)就被初始化,这样我们才能在board_init_fboard_init_r中调用其功能。

 

 

status = "okay";启用这个设备节点。

 

 

第二步:编写 ADC 检测逻辑

 

接下来,我们在板级初始化文件中添加实际的检测代码。

 

 

文件路径u-boot/arch/arm/mach-rockchip/board.c

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
/* 在 board.c 文件的合适位置(如 board_init_r 函数之前)添加此函数 */void sbc_id_detection(void){    /* 1. 定义变量 */    int closest_level = 7// 默认的最高等级    unsigned int adc_value; // 存储原始ADC读数 (0-4095 for 12-bit)    unsigned int voltage_mv; // 转换后的电压值 (mV)    /* 2. 定义电压区间与硬件版本的对应关系 */    /* 这是一个典型的电阻分压网络设计,不同的电阻组合产生不同的电压。       你需要根据自己的硬件原理图来修改这两个数组中的值。 */    const int min_mv[] = {1640143012201000790,  560,  350,   0};    const int max_mv[] = {1840163014201200990,  770,  550250};    /* 3. 读取ADC通道3的值 */    /* "saradc" 是设备树中的节点名,3 是要读取的通道号 */    if (adc_channel_single_shot("saradc"3, &adc_value) == 0) {        /* 4. 将ADC原始值转换为电压值 (mV) */        /*            计算公式:Vout = Vin * (ADC_Value / 2^n)           - Vin (参考电压) = 1800 mV (根据瑞芯微文档)           - n (ADC位数) = 12 bits, 所以 2^12 = 4096        */        voltage_mv = (adc_value * 1800) / 4095;        /* 5. 根据电压值查找匹配的硬件等级 */        for (int i = 0; i < 8; i++) {            if (voltage_mv >= min_mv[i] && voltage_mv <= max_mv[i]) {                closest_level = i;                break// 找到后立即跳出循环            }        }        /* 6. 将检测结果存入U-Boot环境变量 */        /* 环境变量 SBCID 可以在后续的启动脚本中被读取和使用 */        env_set_ulong("SBCID", closest_level);                /* 调试信息,可以在串口终端看到 */        printf("SARADC: Voltage detected: %d mV, SBCID set to %dn", voltage_mv, closest_level);    } else {        /* 7. 处理ADC读取失败的情况 */        env_set("SBCID""unknown");        printf("SARADC: Failed to read from channel 3. SBCID set to 'unknown'n");    }}/*  * 将检测函数注册到U-Boot的初始化序列中。 * board_init_r 是一个合适的位置,它在设备初始化完成后、 * 环境变量初始化后、启动倒计时开始前执行。 */// 注意:具体的注册方式可能因U-Boot版本而异,// 请查阅你所用U-Boot版本的板级文件,找到合适的位置调用 sbc_id_detection();// 例如,在 board_r.c 的某个初始化函数中添加:// sbc_id_detection();

代码解读:

 

 

1.adc_channel_single_shot(): U-Boot 提供的便捷 API,用于单次读取指定 ADC 设备和通道的值。

 

 

2.电压换算根据瑞芯微手册,SARADC 的参考电压Vref 1.8V1800mV)。代码将 12 位的 ADC 读数(范围 0-4095)线性换算为实际电压。

 

 

3.等级匹配通过for循环将计算出的电压值与预设的min_mvmax_mv数组进行比较,找到对应的硬件等级closest_level

 

 

4.环境变量env_set_ulong()将检测到的等级存入名为SBCID的环境变量。这个变量非常关键,后续的启动脚本(如boot.cmd)就可以通过判断SBCID的值来执行不同的操作。

 

 

第三步:如何使用检测结果(参考)

 

检测结果SBCID已存入环境变量,现在你可以在 U-Boot 的启动脚本中灵活运用它。

 

 

文件路径u-boot/board/rockchip/your_board/your_board.env (或类似的脚本文件)

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
# 在 U-Boot 启动脚本中,可以这样使用 SBCIDif test ${SBCID} -eq 0; then    echo "Detected Board Version A. Loading corresponding Device Tree..."    setenv fdtfile rockchip/rk3588-board-version-a.dtbelif test ${SBCID} -eq 1; then    echo "Detected Board Version B. Loading corresponding Device Tree..."    setenv fdtfile rockchip/rk3588-board-version-b.dtbelse    echo "Detected unknown board or using default configuration."    setenv fdtfile rockchip/rk3588-board-default.dtbfi# 后续的 bootcmd 会使用 $fdtfile 变量来加载正确的设备树# run bootcmd

 

第四步:uboot 命令行中查看

  •  
bdinfo

关键要点与风险预案

 

1.时序问题确保 ADC 检测函数在所有必要驱动初始化之后调用。board_init_r是一个安全的选择。

 

 

2.硬件依赖此方案完全依赖于硬件设计。分压电阻的精度、焊接质量、以及 ADC 引脚的电气连接都会影响检测结果。

 

 

3.区间设计在设计min_mvmax_mv数组时,要考虑到电阻容差和 ADC 采样误差,为每个区间留出足够的余量,避免电压值落在区间边界导致误判。

 

 

4.调试在开发阶段,可以将printf语句打开,通过串口终端观察 ADC 的原始值、换算后的电压值以及最终的SBCID,这对于调试硬件和校准区间非常有帮助。

 

 

下一步

 

代码集成将上述代码片段集成到您的 U-Boot 源码树中,并根据您的具体硬件原理图,精确调整min_mvmax_mv数组的值。

 

 

脚本优化完善您的 U-Boot 启动脚本,利用SBCID环境变量实现更复杂的启动逻辑,例如加载不同的内核参数或根文件系统。

 

 

希望这篇文章能帮助您顺利完成 U-Boot 中的 ADC 检测功能开发。

 

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分