跳转至

ADC

本章节介绍使用主板上的 ADC 功能。

Warning

Rockchip 平台 SARADC 最大采集电压 1.8V,严禁过压使用!
Allwinner 平台 GPADC 最大采集电压 1.8 V,LRADC 最大采集电压 1.266V,严禁过压使用!

各平台拓展引脚 ADC 引脚信息如下:

主板 SOC 平台 Kernel 拓展引脚
K1 RK3568 Rockchip 5.10 SARADC X1
K1B RK3568 Rockchip 5.10 SARADC X1
K1Mini RK3568 Rockchip 5.10 / 6.1 SARADC X1
K2B H618 Allwinner 5.4
K2C H618 Allwinner 5.4
K3 RK3562 Rockchip 5.10 SARADC X1
K3B RK3562 Rockchip 5.10 / 6.1 SARADC X1
K4B T113 Allwinner 5.4 GPADC X1
K5C A133 Allwinner 4.9 LRADC X1
K7 RK3576 Rockchip 6.1 SARADC X3
K7C RK3576 Rockchip 6.1 SARADC X3
K7S/F RK3576 Rockchip 6.1
K8 RK3588 Rockchip 5.10 SARADC X1
K8D RK3588S2 Rockchip 5.10 / 6.1 SARADC X2
K9 T527 Allwinner 5.15
K10B A733 Allwinner 5.15 GPADC X1
K11C RK3566 Rockchip 5.10 / 6.1 SARADC X1

术语说明

术语 说明
ADC Analog-to-Digital Converter
SARADC Successive approximation ADC
GPADC General Purpose ADC
LRADC Low Rate ADC

规格

ADC 分辨率 最大采样率 检测电压范围
SARADC 12-bit 1MHz 0~1.8V
GPADC 12-bit 1MHz 0~1.8V
LRADC 6-bit 2KHz 0~1.266 V

ADC 引脚定位

  • ADC 引脚

Note

主板拓展引脚标注 △ 符号对应引脚图 1 号引脚,结合引脚数字丝印,确认实际引脚序号。

K7 引脚示意图:K7 主板配备 3 路 ADC,对应引脚 36(SARADC_VIN4)、38(SARADC_VIN5)、40(SARADC_VIN6)。

image-20251112185736716

DTS 配置

不同平台 DTS 配置不相同,请根据主板对应平台查看对应的 DTS 节点配置。

Rockchip SARADC

Rockchip 平台 SARADC 的节点配置示例如下:

saradc: adc@ff280000 {
    compatible = "rockchip,saradc";
    reg = <0xff280000 0x1000>;
    clocks = <&cru SCLK_SARADC>;
    clock-names = "saradc";
    resets = <&cru SRST_SARADC>;
    reset-names = "saradc";
    #io-channel-cells = <1>;
    status = "okay";
};

Allwinner GPADC

Allwinner 平台 Kernel 4.9 GPADC 的节点配置示例如下:

/*
 * channel_num: Maxinum number of channels supported on the platform.
 * channel_select: channel enable slection. channel0:0x01 channel1:0x02 channel2:0x04 channel3:0x08
 * channel_data_select: channel data enable. channel0:0x01 channel1:0x02 channel2:0x04 channel3:0x08.
 * channel_compare_select: compare function enable channel0:0x01 channel1:0x02 channel2:0x04 channel3:0x08.
 * channel_cld_select: compare function low data enable setection: channel0:0x01 channel1:0x02 channel2:0x04 channel3:0x08.
 * channel_chd_select: compare function hig data enable setection: channel0:0x01 channel1:0x02 channel2:0x04 channel3:0x08.
 */
gpadc:gpadc{
    compatible = "allwinner,sunxi-gpadc"; //表征具体的设备,用于驱动和设备的绑定;
    reg = <0x0 0x05070000 0x0 0x400>; //设备使用的寄存器地址;
    interrupts = <GIC_SPI 0 IRQ_TYPE_NONE>; //设备使用的中断配置;
    clocks = <&clk_gpadc>; //设备使用的时钟配置
    channel_num = <2>; //使用的通道
    channel_select = <0x05>; //通道选择
    channel_data_select = <0>; //使能通道数据
    channel_compare_select = <0x05>; //使用通道比较功能
    channel_cld_select = <0x05>; //使用数据小于比较功能
    channel_chd_select = <0>; //使用数据大于比较功能
    channel0_compare_lowdata = <1700000>; //数据小于该值触发中断
    channel0_compare_higdata = <1200000>; //数据大于该值触发中断
    channel1_compare_lowdata = <460000>;
    channel1_compare_higdata = <1200000>;
    channel0_compare_lowdata = <1500000>; //数据小于该值触发中断
    channel0_compare_higdata = <1200000>; //数据大于该值触发中断
    key_cnt = <5>; //按键数量,注:以下部分只有GPADC0用于按键会用到
    key0_vol = <210>; //按键电压
    key0_val = <115>; //按键上报的值
    key1_vol = <410>;
    key1_val = <114>;
    key2_vol = <590>;
    key2_val = <139>;
    key3_vol = <750>;
    key3_val = <28>;
    key4_vol = <880>;
    key4_val = <102>;
    status = "okay";
}

Allwinner 平台 Kernel 5.15 GPADC 的节点配置示例如下:

/*
*channel_num: Max number of channels supported on the platform.
*channel_select: channel enable slection. channel0:0x01 channel1:0x02 channel2:0x04 channel3:0x08
*channel_data_select: channel data enable. channel0:0x01 channel1:0x02 channel2:0x04 channel3:0x08.
*channel_compare_select: compare function enable channel0:0x01
* channel1:0x02 channel2:0x04 channel3:0x08.
*channel_cld_select: compare function low data enable setection: channel0:0x01
* channel1:0x02 channel2:0x04 channel3:0x08.
*channel_chd_select: compare function hig data enable setection: channel0:0x01
* channel1:0x02 channel2:0x04 channel3:0x08.
*/
    gpadc0:gpadc{
        channel_num = <10>; //最大通道数(即最大keypad数)
        channel_select = <0x3>; //通道选择 (选择0 1 通道)
        channel_data_select = <0x3>; //使能通道数据
        channel_compare_select = <0x3>; //使用通道比较功能
        channel_cld_select = <0x3>; //使用数据小于比较功能
        channel_chd_select = <0x3>; //使用数据大于比较功能
        channel0_compare_lowdata = <1700000>; //channel0数据小于该值触发中断
        channel0_compare_higdata = <200000>; //channel0数据大于该值触发中断
        channel1_compare_lowdata = <1700000>; //channel1数据小于该值触发中断
        channel1_compare_higdata = <200000>;   //channel1数据大于该值触发中断
        status = "okay";
        //支持多个adc通道作按键,按键配置方式如下:
        keyadc0 {
            key_cnt = <5>; //按键个数
            key0_vol = <115>; //按键按下时电压值,单位为毫伏
            key0_val = <115>;
            key1_vol = <240>;
            key1_val = <114>;
            key2_vol = <360>;
            key2_val = <139>;
            key3_vol = <480>;
            key3_val = <28>;
            key4_vol = <600>;
            key4_val = <102>;
        };
        keyadc1 {
            key_cnt = <5>;
            key0_vol = <115>;
            key0_val = <115>;
            key1_vol = <240>;
            key1_val = <114>;
            key2_vol = <360>;
            key2_val = <139>;
            key3_vol = <480>;
            key3_val = <28>;
            key4_vol = <600>;
            key4_val = <102>;
        };
    ................
}

Allwinner LRADC

Allwinner 平台 LRADC 的节点配置示例如下:

sunxi_keyboard:keyboard {
    compatible = "allwinner,keyboard";
    reg = <0x0 0x01c21800 0x0 0x400>; /* 寄存器地址 */
    interrupts = <GIC_SPI 30 IRQ_TYPE_NONE>; /* 中断 */
    status = "okay"; /* 使能该节点 */
    key_cnt = <5>;
    key0 = <115 115>; /*根据实际情况,左边115是电压,单位为mV,右边115为该电压对应的键值*/
    key1 = <235 114>;
    key2 = <330 139>;
    key3 = <420 28>;
    key4 = <520 102>;
};

驱动路径

各平台驱动路径如下(相对 SDK 根目录):

// rk356x-linux / rk-linux6.1 / rk3576-linux / rk-android14.0
drivers/iio/adc/rockchip_saradc.c

// a133-linux / t113-linux / h618-android12.0
drivers/input/sensor/sunxi_gpadc.c
drivers/input/keyboard/sunxi-keyboard.c

// a733-linux / a733-android13.0
longan/bsp/drivers/gpadc/sunxi_gpadc.c
longan/bsp/drivers/lradc/sunxi-lradc.c

GPADC/LRADC 测试

查看 ADC 模块的 event 节点:

cat /proc/bus/input/devices

hexdump 读取输入设备 0 数据:

hexdump /dev/input/event0

getevent 是 Android 系统中用于查看输入设备事件命令:

getevent -l

evtest 是 Linux 系统下开源的输入设备事件测试工具:

evtest /dev/input/event0

SARADC 测试

Rockchip 平台 SARADC 是注册为 iio 子系统设备,可以通过下面的方式进行读取 ADC 数据。

IIO 读取

列举系统中已注册的 IIO 设备:

ls /sys/bus/iio/devices/

查看目标 IIO 设备 0 的所有可操作接口:

ls /sys/bus/iio/devices/iio\:device0/

Note

接口下的关键节点
in_voltageX_raw: X 为 ADC 通道编号(如 0、6 等),存储对应通道的 ADC 原始采样数值。
in_voltage_scale: 电压换算比例系数(单位:V/LSB),用于将原始采样值转换为实际电压。

电压计算公式:

实际电压值 = in_voltageX_raw 读取值 × in_voltage_scale 读取值

读取电压比例系数(用于计算实际电压):

cat /sys/bus/iio/devices/iio:device0/in_voltage_scale

读取 IN6 通道的 ADC 原始采样值:

cat /sys/bus/iio/devices/iio:device0/in_voltage6_raw

Shell 脚本

通过脚本读取 IN6 通道电压,运行脚本后每秒输出 ADC 原始采样值,电压比例系数以及电压值。

#!/bin/bash

echo "Press Ctrl+C to quit"

VOL_RAW="/sys/bus/iio/devices/iio:device0/in_voltage6_raw"
VOL_SCALE="/sys/bus/iio/devices/iio:device0/in_voltage_scale"

# Check required files accessibility
for file in "$VOL_RAW" "$VOL_SCALE"; do
    [ ! -f "$file" ] || [ ! -r "$file" ] && { echo "Error: Cannot access $file" >&2; exit 1; }
done

while true; do
    raw=$(cat "$VOL_RAW" | tr -d '\n\r ')
    scale=$(cat "$VOL_SCALE" | tr -d '\n\r ')
    voltage=$(awk -v r="$raw" -v s="$scale" 'BEGIN { printf "%.4f", (r * s) / 1000 }')
    echo "vol_raw:$raw, vol_scale:$scale, vol:$voltage V"
    sleep 1
done

执行方式:

chmod +x adc_read.sh
./adc_read.sh

C 程序

通过 C 程序读取 IN6 通道电压:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

#define VOL_RAW "/sys/bus/iio/devices/iio:device0/in_voltage6_raw"
#define VOL_SCALE "/sys/bus/iio/devices/iio:device0/in_voltage_scale"

// Handle Ctrl+C exit
void sigint_handler(int sig) {
    (void)sig;
    printf("\nExiting...\n");
    exit(EXIT_SUCCESS);
}

// Read int from file
static int read_int(const char *path) {
    FILE *fp = fopen(path, "r");
    int val;
    if (!fp || fscanf(fp, "%d", &val) != 1) {
        perror("Read int failed");
        exit(EXIT_FAILURE);
    }
    fclose(fp);
    return val;
}

// Read float from file
static float read_float(const char *path) {
    FILE *fp = fopen(path, "r");
    float val;
    if (!fp || fscanf(fp, "%f", &val) != 1) {
        perror("Read float failed");
        exit(EXIT_FAILURE);
    }
    fclose(fp);
    return val;
}

int main() {
    signal(SIGINT, sigint_handler);
    printf("Press Ctrl+C to quit\n");

    while (1) {
        int raw = read_int(VOL_RAW);
        float scale = read_float(VOL_SCALE);
        printf("vol_raw:%d, vol_scale:%.6f, vol:%.4f V\n", 
               raw, scale, (raw * scale) / 1000.0f);
        sleep(1);
    }
}

执行方式:

gcc adc_read.c -o adc_read
chmod +x adc_read
./adc_read