4.3.7. ADC 调试指南
4.3.7.1. 概述
ADC( Analog-to-Digital Converter,模数转换器)主要
4.3.7.2. 特点
多通道
输入:支持 8 路 独立 模拟 输入 通道( CH0-CH7 ),其中 CH3-7 在 EVB 板上 靠近 40pin 的 位置,参考 ADC 接口章节。 灵活
配置:支持 CPU 和 DMA 模式,而且 都 能 分别 支持 单次 采样 和 连续 采样。 用户
态 接口:通过 sysfs 节点 直接 读取 原始 电压 值,支持 两种 获取数据 的 方式 分别 为 signle 模式 和 scan 模式。 电压
量程: 0~1.8V 分辨率: 10bit
注:
当
4.3.7.3. 功能描述
典型应用
传感器
电池
工业
功能原理
在
工作方式
ADC 本身
IIO , 工业
输入输出 接口 , 它 是 为了 统一 管理 ADC 和 DAC 设备 而 设立 的, 接入 IIO 的 常见 设备 有 加速度计、光 传感器、陀螺仪、气压计、磁力计。可以 理解 为 通过 IIO 接口,可以 访问 这 一系列 本质 是 ADC 或者 DAC 的 传感器 设备 ; IIO 子系统 框架 主要 包括 IIO sysfs , IIO core , IIO drivers Cdev。在 使用 的 时候 可以 理解 为 使用 IIO 框架 将 ADC 设备 管理 起来 了。 DMA , 直接
内存 访问,即 一种 允许 外设 直接 与 主存 进行 数据传输,而 不 需要 通过 CPU,它 显著 提高 了 数据 传输速度。 实现 DMA 的 时候,一般 是 有 一个 DMA 控制器, CPU 只 需要 配置 DMA 控制器 的 参数,并 将 控制权 交给 DMA 控制器, 然后 就 可以 继续执行 其他 任务,不 需要 参与 具体 的 数据传输 过程。
单次
连续
如果
4.3.7.4. 驱动代码
uboot
uboot/drivers/adc/guc_adc.c
dts 配置
adc: adc@34190000 {
compatible = "guc,igav04a"; /*定义 adc 设备的兼容性属性,用于设备匹配*/
status = "okay";
/* 定义 adc 设备的寄存器基地址和长度 */
reg = <0x34190000 0x10000>, /*adc*/
<0x34180100 0x10>; /*password*/
clocks = <&adcclk>; /* 定义 adc 设备使用的时钟源 */
clock-names = "adc-clk"; /* 定义时钟名称,用于与时钟源关联 */
vref-supply = <®_adc_vref_1v8>; /* 定义 adc 设备的参考电源供应 */
#io-channel-cells = <1>; /* 定义 io 通道单元数,表示每个 io 通道需要1个单元来描述 */
guc,adc-channels = <0 1 2 3 4 5 6 7>; /* 定义 adc 支持的通道列表 */
guc,passwd = <12345678>; /* 定义 efuse 偏移量,用于读取 efuse 中的校准数据 */
efuse-offset = <0x74>; /* 定义 efuse 偏移量,用于读取 efuse 中的校准数据 */
#address-cells = <1>; /* 定义子节点的地址单元数,表示子节点需要用1个单元来描述地址 */
#size-cells = <0>; /* 定义子节点的大小单元数,表示子节点不需要用单元来描述大小 */
};
kernel
驱动
代码 ADC 的 驱动 代码 主要 存在 与 kenel 里面
驱动
关键
guc_adc_probe():设备
guc_adc_read_raw():处理
IIO 的
industrialio-core.c
industrialio-buffer.c
industrialio-event.c
IIO sysfs/Cdev 对
IIODriver 不同 IIO 设备
iio_interrupt_trigger_poll
->iio_trigger_poll
->iio_pollfunc_store_time
->guc_adc_trigger_handler
也
DMA 控制器
kernel/drivers/dma/dw-axi-dmac
.
├── dw-axi-dmac.h
├── dw-axi-dmac-platform.c
└── Makefile
DTS 配置
示例:
arch/arm64/boot/dts/hobot/x5.dtsi
adc: adc@34190000 {
compatible = "guc,igav04a";
status = "disabled";
reg = <0x34190000 0x10000>, /* adc */
<0x34180100 0x10>; /* password */
interrupt-parent = <&gic>; /* 定义中断父设备为 gic(通用中断控制器) */
interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>; /* 定义 adc 设备的中断号和触发类型,这里为 GIC_SPI 74号中断,上升沿触发 */
clocks = <&hpsclks X5_LSIO_ADC_CLK>,<&hpsclks X5_LSIO_ADC_PCLK>; /* 定义 adc 设备使用的时钟源,包括 adc 时钟和 adc 外围时钟 */
clock-names = "adc-clk","adc-pclk"; /* 定义时钟名称,用于与时钟源关联 */
assigned-clock-rates = <32000000>; /* 定义 adc 设备的时钟频率,这里设置为32000000Hz */
/* disable efuse binding by default */
nvmem-cells = <&efuse_adc_offset>, <&efuse_adc_trimming>;
nvmem-cell-names = "adc-offset", "adc-trimming";
vref-supply = <®_adc_vref_1v8>; /* 定义 adc 设备的参考电源供应 */
#io-channel-cells = <1>; /* 定义 io 通道单元数,表示每个 io 通道需要1个单元来描述 */
guc,adc-channels = <0 1 2 3 4 5 6 7>;
guc,passwd = <12345678>;
#address-cells = <1>;
#size-cells = <0>;
guc,sample-rate=<50000>; /* 定义 adc 设备的采样率,单位为 Hz */
resets = <&socrst LSIO_ADC_RESET>; /* 定义 adc 设备的复位信号,用于设备复位 */
reset-names = "guc-adc"; /* 定义复位信号的名称 */
};
如果
dmas = <&axi_dmac 34>; /* ADC 使用的是 DMA 34 通道 */
dma-names = "rx"; /* 定义 DMA 通道的名称 rx*/
通过guc,sample-rate 字
guc,sample-rate=<260000>; # 对应 1.56MHz
guc, sample-rate=<210000>; # 对应 1.25MHz
guc,sample-rate=<130000>; # 对应 0.78MHz
guc,sample-rate=<100000>; # 对应 0.63MHz
例如:
adc: adc@34190000 {
compatible = "guc,igav04a";
status = "disabled";
reg = <0x34190000 0x10000>, /* adc */
<0x34180100 0x10>; /* password */
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>;
clocks = <&hpsclks X5_LSIO_ADC_CLK>,<&hpsclks X5_LSICO_ADC_PCLK>;
clock-names = "adc-clk","adc-pclk";
assigned-clock-rates = <32000000>;
/* disable efuse binding by default */
nvmem-cells = <&efuse_adc_offset>, <&efuse_adc_trimming>;
nvmem-cell-names = "adc-offset", "adc-trimming"",
vref-supply = <®_adc_vref_1v8>;
#io-channel-cells = <1>;
guc,adc-channels = <0 1 2 3 4 5 6 7>;
guc,passwd = <12345678>;
#address-cells = <1>;
#size-cells = <0>;
guc,sample-rate=<160000>;
resets = <&socrst LSIO_ADC_RESET>;
reset-names =
"guc-adc";
dmas = <&axi_dmac 34>;
dma-names = "rx"
};
内核
配置:
arch/arm64/configs/hobot_x5_soc_defconfig
CONFIG_DW_AXI_DMAC=y /* 如果需要用到 DMA 则需要确认是否有开启,默认是开启的 */
CONFIG_IIO=y
CONFIG_GUC_ADC=y
4.3.7.5. 功能使用
uboot
ADC 在 uboot 阶段
用户态使用
IIO 的
/sys/bus/iio/devices/iio:deviceX/
/dev/iio:deviceX
非连续采样
非
单通道
#in_voltageN_raw 表示通道 N , 比如这里举例通道 0
cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw
多通道
#in_voltageN_raw 表示通道 N
cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw
cat /sys/bus/iio/devices/iio:device0/in_voltage1_raw
cat /sys/bus/iio/devices/iio:device0/in_voltage2_raw
cat /sys/bus/iio/devices/iio:device0/in_voltage3_raw
cat /sys/bus/iio/devices/iio:device0/in_voltage4_raw
cat /sys/bus/iio/devices/iio:device0/in_voltage5_raw
cat /sys/bus/iio/devices/iio:device0/in_voltage6_raw
cat /sys/bus/iio/devices/iio:device0/in_voltage7_raw
连续采样 -scan 模式
连续
DMA 模式
在
单通道
方式
一:使用 hexdump 读取
#in_voltageN_en 表示通道 N
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/in_voltage0_en
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/enable
hexdump -d -v /dev/iio\:device0
root@buildroot:/userdata# hexdump -d -v /dev/iio\:device0
0000000 00025 00021 00025 00029 00037 00061 00045 00037
0000010 00039 00035 00043 00041 00040 00048 00049 00040
0000020 00046 00053 00044 00049 00045 00053 00041 00045
0000030 00032 00025 00045 00056 00056 00046 00036 00056
0000040 00033 00041 00053 00048 00055 00037 00032 00041
0000050 00046 00049 00049 00060 00044 00036 00045 00048
0000060 00043 00030 00050 00025 00048 00028 00035 00046
0000070 00040 00036 00035 00035 00032 00032 00026 00023
0000080 00044 00032 00033 00041 00028 00040 00040 00056
0000090 00041 00044 00029 00037 00027 00041 00043 00037
00000a0 00033 00032 00017 00028 00037 00044 00016 00026
00000b0 00048 00045 00026 00024 00037 00030 00030 00044
00000c0 00024 00035 00043 00039 00044 00040 00040 00043
00000d0 00040 00037 00037 00040 00042 00024 00033 00039
······
关闭连续采样 :
echo 0 > /sys/bus/iio/devices/iio\:device0/buffer0/enable
echo 0 > /sys/bus/iio/devices/iio\:device0/buffer0/in_voltage0_en
其它通道 : 只需修改 in_voltage0_en 字段即可。
方式
二:使用 iio_readdev 读取 ( iio_readdev 获取 方式 : http://ftp.cn.debian.org/debian/pool/main/libi/libiio/ , 选择 其中 的 libiio-utils_0.26-2_arm64.deb , 解压 之后 找到 iio_readdev 放到 系统 中 即可 使用)
voltageN 表示通道 N
iio_readdev -u local: -b 256 -s 0 -T 0 34190000.adc voltage0 | hexdump -d -v
root@buildroot:/userdata# ./iio_readdev -u local: -b 256 -s 0 -T 0 34190000.adc voltage0 | hexdump -d -v
WARNING: High-speed mode not enabled
0000000 00032 00027 00035 00037 00019 00030 00035 00032
0000010 00028 00026 00028 00024 00008 00030 00024 00028
0000020 00035 00024 00024 00019 00020 00029 00029 00024
0000030 00024 00033 00039 00030 00023 00027 00025 00041
0000040 00030 00024 00032 00036 00030 00023 00025 00036
0000050 00036 00045 00029 00030 00032 00029 00023 00032
0000060 00032 00035 00041 00028 00029 00025 00024 00021
0000070 00029 00021 00026 00035 00036 00021 00035 00030
0000080 00049 00029 00030 00035 00028 00037 00035 00029
0000090 00035 00020 00027 00033 00026 00016 00021 00016
00000a0 00038 00012 00013 00021 00028 00014 00036 00024
00000b0 00014 00016 00049 00022 00029 00028 00007 00025
00000c0 00030 00029 00047 00037 00032 00032 00031 00032
······
其他通道 : 只需修改 voltage0 字段即可。
多通道
DMA 不
方式
一:使用 hexdump 读取
echo 50 > /sys/bus/iio/devices/iio\:device0/cycle_period
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/in_voltage0_en
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/in_voltage2_en
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/in_voltage5_en
echo 1 > /sys/bus/iio/devices/iio\:device0/bbuffer0/enable
hexdump -d /dev/iio\:device0
方式
二:使用 iio_readdev 读取
echo 50 > /sys/bus/iio/devices/iio\:device0/cycle_period
iio_readdev -u local: -b 256 -s 0 -T 0 3419000.adc voltage0 voItage2 voltage5 | hexdump
注意 cycle_periiod 文件
CPU 模式
连续
echo userspace > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
echo 1500000 > /sys/devices/system/cpu/cpufreq/policy0/scaling_setspeed
同样,在
单通道
方式
一:使用 hexdump 读取
例如测试 channel 0 , 执行如下操作 :
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/in_voltage0_en
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/enable
hexdump -d /dev/iio\:device0
显示信息如下 :
root@buildroot:/userdata# hexdump -d /dev/iio\:device0
0000000 00028 00037 00045 00032 00039 00039 00035 00048
0000010 00041 00032 00040 00037 00037 00026 00043 00031
0000020 00044 00035 00039 00030 00026 00027 00025 00041
0000030 00035 00041 00040 00032 00019 00020 00045 00028
0000040 00033 00035 00032 00026 00029 00044 00035 00043
0000050 00036 00039 00033 00035 00040 00032 00049 00040
0000060 00032 00043 00040 00049 00039 00053 00043 00045
0000070 00049 00037 00039 00039 00036 00037 00037 00028
0000080 00041 00032 00024 00035 00035 00033 00032 00045
0000090 00040 00049 00036 00046 00053 00046 00043 00032
00000a0 00045 00032 00031 00045 00027 00039 00045 00040
······
方式
二:使用 iio_readdev 读取
直接使用 iioreaddev 命令进行读取 , 例如测试 channel 0 测试方式如下 :
iio_readdev -u local: -b 256 -s 0 -T 0 34190000.adc voltage0 | hexdump -d
测试 channel 1:
iio_readdev -u local: -b 256 -s 0 -T 0 34190000.adc voltage1 | hexdump -d
34190000.adc 表示检测设备 , 来源为 :
root@buildroot:/userdata# ./iio_attr -a -s -c
Using auto-detected IIO context at URI "local:"
IIO context has 2 devices:
iio:device0, 34190000.adc: found 8 scan channels
trigger0, 34190000.adc-dev0: found 0 scan channels
root@buildroot:/userdata#
voltage0: 表示通道 0
显示信息如下 :
root@buildroot:/userdata# ./iio_readdev -u local: -b 256 -s 0 -T 0 34190000.adc voltage0 | hexdump -d
WARNING: High-speed mode not enabled
0000000 00029 00019 00030 00028 00028 00044 00036 00045
0000010 00043 00045 00044 00024 00035 00029 00035 00037
0000020 00016 00021 00044 00032 00032 00030 00030 00029
0000030 00043 00024 00049 00036 00024 00039 00038 00039
0000040 00037 00036 00030 00048 00049 00045 00046 00039
0000050 00029 00024 00032 00035 00035 00029 00040 00048
0000060 00024 00027 00028 00032 00025 00039 00035 00035
0000070 00043 00035 00040 00048 00036 00044 00048 00048
0000080 00035 00046 00043 00043 00035 00045 00039 00032
0000090 00036 00028 00043 00044 00048 00046 00052 00052
00000a0 00040 00035 00036 00035 00042 00048 00037 00046
00000b0 00040 00032 00025 00051 00035 00032 00036 00048
00000c0 00039 00053 00035 00039 00040 00023 00049 00037
······
多通道
方式
一:使用 hexdump 读取
例如测试 channel 012 执行如下操作 :
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/in_voltage0_en
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/in_voltage1_en
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/in_voltage2_en
echo 1 > /sys/bus/iio/devices/iio\:device0/buffer0/enable
hexdump -d /dev/iio\:device0
显示信息如下 :
root@buildroot:/userdata# hexdump -d /dev/iio\:device0
0000000 00032 00038 00003 00037 00032 00003 00046 00029
0000010 00003 00030 00041 00003 00039 00053 00003 00032
0000020 00043 00003 00030 00035 00003 00023 00025 00003
0000030 00040 00032 00003 00024 00048 00003 00045 00039
0000040 00003 00039 00045 00003 00039 00047 00003 00052
0000050 00030 00003 00046 00040 00003 00041 00037 00003
0000060 00049 00046 00003 00049 00043 00003 00040 00046
0000070 00003 00037 00044 00003 00040 00041 00003 00048
0000080 00059 00003 00056 00056 00003 00055 00046 00003
0000090 00058 00046 00003 00054 00041 00003 00045 00050
00000a0 00003 00045 00045 00003 00053 00041 00003 00026
00000b0 00050 00003 00053 00039 00003 00045 00050 00003
00000c0 00047 00049 00003 00045 00043 00003 00045 00044
00000d0 00003 00037 00031 00003 00040 00037 00003 00035
00000e0 00038 00003 00045 00032 00003 00040 00023 00003
00000f0 00044 00037 00003 00028 00030 00003 00035 00037
······
方式
二:使用 iio_readdev 读取
直接使用 iioreaddev 命令进行读取 , 例如测试 channel0,1,2 测试方式如下 :
iio_readdev -u local: -b 256 -s 0 -T 0 34190000.adc voltage0 voltage1 voltage2 | hexdump -d
显示信息如下:
root@buildroot:/userdata# ./iio_readdev -u local: -b 256 -s 0 -T 0 34190000.adc voltage0 voltage1 voltage2 | hexdump -d
WARNING: High-speed mode not enabled
0000000 00048 00040 00003 00039 00044 00003 00044 00046
0000010 00003 00048 00042 00003 00061 00053 00003 00036
0000020 00046 00003 00049 00041 00003 00047 00037 00003
0000030 00044 00045 00003 00050 00056 00003 00061 00061
0000040 00005 00069 00052 00007 00057 00061 00008 00048
0000050 00052 00012 00056 00045 00003 00053 00058 00012
0000060 00045 00043 00003 00049 00045 00003 00043 00041
0000070 00003 00044 00039 00003 00045 00046 00003 00053
0000080 00043 00003 00043 00052 00003 00053 00054 00003
0000090 00058 00055 00003 00060 00049 00003 00057 00048
00000a0 00003 00040 00040 00003 00039 00045 00003 00040
00000b0 00048 00008 00040 00044 00003 00037 00033 00003
00000c0 00048 00043 00003 00050 00056 00003 00039 00039
00000d0 00003 00049 00025 00003 00045 00061 00005 00047
电压
电压 = 采样
例如
电压 = 524 * (1800 / 1024) = 524 * 1.7578125 = 921.09375 mv
4.3.7.6. 常见问题
Q1 :采样
检查
多次
Q2 :无法
确认CONFIG_GUC_ADC=y。
检查 DTS 中 ADC 节点
使用 dmesg | grep adc 查看
Q3 : 使用 single 模式
single 模式 单通道
非 连续 采样 几乎 不 消耗 cpu,所以 该 模式 下 cpu loading 几乎 为 0. scan 模式
DMA 方式 CPU 固定
到 1.5G 下 CPU 利用率 (单核)
| 采样率 | 实际 |
CPU loading(%) |
|---|---|---|
| 1.25MHz | 200k | 8% |
| 0.83MHz | 138k | 5% |
| 0.78MHz | 130k | 5% |
| 1.79MHz | 290k | 9% |
| 0.6MHz | 100k | 4% |
CPU 默认 1.2G 频率
| 采样率 | 实际 |
CPU loading(%) |
|---|---|---|
| 1.25MHz | 200k | 19% |
| 0.83MHz | 138K | 12% |
| 0.78MHz | 130K | 12% |
| 1.79MHz | 290k | 23% |
| 0.6MHz | 100k | 10% |
CPU 方式 CPU 固定
到 1.5G,DDR 固定 到 3200 下 cpu 利用率 ( 单核 )。
| 采样率 | 实际 |
CPU loading(%) |
|---|---|---|
| 500KHz | 500k | 6% |
CPU 默认
Q4 :以 cycle_period 为
600KHz 采样率
| 10ms | 50ms | 100ms | |
|---|---|---|---|
| 单通道 | 2-5% | 2-5% | 2-5% |
| 多通道 (3) | 4-6% | 2-5% | 3-5% |
900KHz 采样率
| 10ms | 50ms | 100ms | |
|---|---|---|---|
| 单通道 | 4-6% | 4-6% | 4-6% |
| 多通道 | 5-8% | 4-7% | 4-7% |
1MHz 采样率
| 10ms | 50ms | 100ms | |
|---|---|---|---|
| 单通道 | 6-7% | 6-7% | 6-7% |
| 多通道 | 5-8% | 5-8% | 5-8% |
1.2MHz 采样率
| 10ms | 50ms | 100ms | |
|---|---|---|---|
| 单通道 | 6-8% | 6-8% | 6-8% |
| 多通道 | 7-9% | 6-8% | 6-8% |
1.5MHz 采样率
| 10ms | 50ms | 100ms | |
|---|---|---|---|
| 单通道 | 8-10% | 8-10% | 8-10% |
| 多通道 | 12-14% | 9-11% | 7-9% |