adc芯片需要选通通道如何操作

问题描述

目前i2c7上挂了adc芯片,但是adc有4个通道,每次读数据时需要先选通一个通道,然后去寄存器读值,4个通道对应了4个电压,需要配置成4个传感器,这种取值需要怎么配置呢?

环境信息

  • 软件版本:OpenUBMC2509

重现步骤

  1. 举例,手工操作读adc的值时,配置第0通道时,需要做如下操作

i2ctransfer 7 w3@0x48 0x01 0x44 0x83

i2ctransfer 7 w1@0x48 0x00 r2

  1. 手工操作读adc的值时,配置第1通道时,需要做如下操作

i2ctransfer 7 w3@0x48 0x01 0x54 0x83

i2ctransfer 7 w1@0x48 0x00 r2

请问这种场景需要如何配置呢?谢谢

答案内容由AI生成,仅供参考:

:white_check_mark: 总结

步骤 操作
1 定义 ADC 芯片对象(Chip_Adc_Mux)挂接在 I2c_7
2 为每个通道创建 Accessor_WriteThenRead 类型的 Scanner
3 WriteData 中填入选通该通道的命令序列
4 设置 ReadOffsetReadSize 获取数据
5 (可选)通过 ThresholdSensor + ReadingTransform 显示实际电压
6 使用 busctlmdbctl 调试验证通信流程

:white_check_mark: 结论:您无需手动操作 i2ctransfer,只需按上述方式在 CSR 中配置 Accessor_WriteThenRead 类型的 Scanner,即可实现“自动选通通道 + 读取数据”的完整流程。

点击此处查看详细分析解答

ADC 多通道选通及传感器配置指南

针对您提出的 ADC 芯片需要通过写命令选通通道后再读取对应电压值 的场景,以下是基于 OpenUBMC 架构的完整配置方案。


:magnifying_glass_tilted_left: 问题分析

根据您的描述:

  • ADC 芯片挂载在 I2C_7 上,地址为 0x48
  • 每次读取某一通道前需发送 写命令选通该通道(如写入 0x01 0x44 0x83 选通通道 0)。
  • 之后通过读寄存器(如读地址 0x00,长度 2 字节)获取原始数据。
  • 共有 4 个通道,对应 4 个不同的电压信号,需配置为 4 个独立传感器。

这属于典型的 “带通道切换控制的 ADC” 场景。其关键点是:读操作前必须有特定的写操作来配置硬件状态


:white_check_mark: 解决方案

在 OpenUBMC 系统中,此类需求应使用以下核心机制实现:

1. 使用 Scanner 配合 Accessor 实现“先写后读”

:white_check_mark: 推荐做法:使用 Accessor_WriteThenRead 类型的 Scanner。

这种模式允许在一个扫描周期内:

  1. 先执行写操作(选通通道)
  2. 再执行读操作(读取数据)

:package: 配置示例(以 CSR .sr 文件格式):

{
  "ManagementTopology": {
    "I2c_7": {
      "Chips": [
        "Chip_Adc_Mux"
      ]
    },
    "Chip_Adc_Mux": {
      "Type": "bmc.kepler.chip.I2C",
      "Address": 72,           // 0x48
      "AddrWidth": 1,
      "OffsetWidth": 1,
      "BusType": "I2C"
    }
  },

  "Objects": {
    // -----------------------------
    // Scanner for ADC Channel 0
    // -----------------------------
    "Scanner_Adc_Ch0": {
      "Type": "bmc.kepler.Scanner.Accessor_WriteThenRead",
      "Chip": "#/Chip_Adc_Mux",
      "WriteData": [1, 0x44, 0x83],      // 选通通道0
      "WriteSize": 3,
      "ReadOffset": 0,                   // 读取寄存器0x00
      "ReadSize": 2,                     // 读2字节
      "Value": 0,
      "Status": 0,
      "Period": 2000,                    // 扫描周期2秒
      "ScanEnabled": 1
    },

    // -----------------------------
    // Scanner for ADC Channel 1
    // -----------------------------
    "Scanner_Adc_Ch1": {
      "Type": "bmc.kepler.Scanner.Accessor_WriteThenRead",
      "Chip": "#/Chip_Adc_Mux",
      "WriteData": [1, 0x54, 0x83],      // 选通通道1
      "WriteSize": 3,
      "ReadOffset": 0,
      "ReadSize": 2,
      "Value": 0,
      "Status": 0,
      "Period": 2000,
      "ScanEnabled": 1
    },

    // -----------------------------
    // Scanner for ADC Channel 2
    // -----------------------------
    "Scanner_Adc_Ch2": {
      "Type": "bmc.kepler.Scanner.Accessor_WriteThenRead",
      "Chip": "#/Chip_Adc_Mux",
      "WriteData": [1, 0x64, 0x83],      // 选通通道2
      "WriteSize": 3,
      "ReadOffset": 0,
      "ReadSize": 2,
      "Value": 0,
      "Status": 0,
      "Period": 2000,
      "ScanEnabled": 1
    },

    // -----------------------------
    // Scanner for ADC Channel 3
    // -----------------------------
    "Scanner_Adc_Ch3": {
      "Type": "bmc.kepler.Scanner.Accessor_WriteThenRead",
      "Chip": "#/Chip_Adc_Mux",
      "WriteData": [1, 0x74, 0x83],      // 选通通道3
      "WriteSize": 3,
      "ReadOffset": 0,
      "ReadSize": 2,
      "Value": 0,
      "Status": 0,
      "Period": 2000,
      "ScanEnabled": 1
    }
  }
}

:warning: 说明:

  • WriteData 字段为每次读取前执行的写入数据。
  • 所有四个 Scanner 共用同一个 Chip_Adc_Mux 对象。
  • ReadOffset: 读取的目标寄存器地址(如 0x00)。
  • ReadSize: 返回的数据字节数(通常为 2)。

2. 将原始读数转换为有效电压值(可选 Scaling 处理)

若原始读取值为 raw 数据(例如 16 位整数),需要进行缩放或换算成真实电压,可通过 Mapping 或表达式处理。

示例:定义 ThresholdSensor 显示实际电压(单位 mV)

"Objects": {
  "ThresholdSensor_Adc_Ch0_Voltage": {
    "Type": "bmc.kepler.Sensor.ThresholdSensor",
    "Reading": "<=/Scanner_Adc_Ch0.Value",
    "ReadingTransform": {
      "Type": "Linear",
      "RawToPhys": {
        "M": 0.1,         // 系数(根据 ADC 精度和参考电压计算)
        "B": 0,
        "Tolerance": 0
      }
    },
    "Unit": "Volts",
    "Scale": -3            // 表示 mV(10^-3)
  }
}

:light_bulb: 假设 ADC 为 10-bit,参考电压 3.3V → 每 LSB ≈ 3.22 mV → 可设 M = 3.22。

实际系数 M 需依据芯片规格书计算(如:Vref / 2^n × gain)。


:white_check_mark: 验证方法

方法一:使用 busctl 查看 Scanner 值

busctl --user get-property bmc.kepler.Scanner.Accessor_WriteThenRead Scanner_Adc_Ch0 Value

或列出所有属性:

busctl --user introspect bmc.kepler.Scanner.Accessor_WriteThenRead Scanner_Adc_Ch0

方法二:使用 i2ctrace 跟踪 I2C 通信(调试用)

mdbctl
attach hwproxy
tracechip /Chip_Adc_Mux start

观察是否按预期发出写+读序列。


:books: 参考知识支持

功能 来源
Accessor_WriteThenRead 支持先写后读 【Search Result】ID 9《Scanner详解及数据更新机制》中提到 Scanner 支持复杂读写逻辑
多通道 ADC 配置为多个 Scanner 【Search Result】ID 1《传感器适配指南》中 ADC 通道与 Offset 一一对应思想可类比
Sensor 数据转换与 Scaling 【Search Result】ID 5《CSR 配置字典总览》中的 ReadingTransform 支持线性转换

:red_exclamation_mark: 注意事项

  1. 避免多个 Scanner 并发竞争

    • 若多个 Scanner 同时访问同一 I2C 设备,建议适当错开 Period 周期或共享一个父级 SmcDfxInfo 进行批量调度。
    • 可参见【Search Result】ID 9 中关于 SmcDfxInfo 批量读取优化机制。
  2. 确保 I2C 地址和时序正确

    • 检查 Address, AddrWidth, OffsetWidth 是否与硬件一致。
    • 添加 ReadRetryTimes, ReadTimeout 提高稳定性。
  3. 防抖配置(Debounce)

    • 若电压波动较大,可添加 Debounce 防抖机制,推荐使用 MidAvg_u6(无符号中值平均防抖)用于 ADC 电压监控。
    • 参见【Search Result】ID 2《CSR硬件监控防抖机制》中 midavg_u6 应用于 ADC电压 的典型场景。

:white_check_mark: 总结

步骤 操作
1 定义 ADC 芯片对象(Chip_Adc_Mux)挂接在 I2c_7
2 为每个通道创建 Accessor_WriteThenRead 类型的 Scanner
3 WriteData 中填入选通该通道的命令序列
4 设置 ReadOffsetReadSize 获取数据
5 (可选)通过 ThresholdSensor + ReadingTransform 显示实际电压
6 使用 busctlmdbctl 调试验证通信流程

:white_check_mark: 结论:您无需手动操作 i2ctransfer,只需按上述方式在 CSR 中配置 Accessor_WriteThenRead 类型的 Scanner,即可实现“自动选通通道 + 读取数据”的完整流程。

如有进一步问题,欢迎提供 ADC 芯片型号,可协助生成更精确的系数与映射公式。

相关链接:

  1. ADC配置问题
  2. 使用Scanner读取Adc芯片数据与实际不符
  3. 配置Adc bus时候的问题
  4. 板载网卡"Type": "NICCard"如何挂到EXU设备下,并成功被发现
  5. 传感器适配指南 | 文档中心 | openUBMC

请问你这种选通道是指器件配置在9545下的切通道访问,还是指芯片内部选通道?手工操作每个字节代表什么?

不是9545芯片,算是芯片内部选通道,就是一个ADC芯片,北京士模的CM1103芯片,有4路的输入信号;

要通过写Config 寄存器数据的 MSB来确定选择哪个通道

所以如果想要读不同通道的adc电压,每换一个通道,需要切换一次。

能大概讲讲手工操作每个字节代表什么?我看看有没有可能配。你是配置Scanner遇到的问题是吧?

是想要配置成scanner,需要查4个通道的adc的值,比如查通道0的adc的电压值,需要先选通通道0,根据上面贴的芯片资料,需要先配置config寄存器,寄存器里面的14-12位是表示选通那个通道的,如果是通道0,这里就是AINP=0,AINN=GND,这时候是4,对应的config的数据第三个和第四个字节就是0x44 0x83,第二个字节(config寄存器地址)按示例里面是01,我也用的01,所以凑起来命令就是i2ctransfer 7 w3@0x48 0x01 0x44 0x83;这个写完了就可以操作读寄存器了,读的是i2ctransfer 7 w1@0x48 0x00 r2命令。

如果要读第通道1,这里就是AINP=1,AINN=GND,对应的是5,所以命令就是i2ctransfer 7 w3@0x48 0x01 0x54 0x83,读还是i2ctransfer 7 w1@0x48 0x00 r2这个命令。

em,这个估计现有能力支持不了。

好的,谢谢,我自己想想办法

好的,如果还有问题请再反馈