Skip to content

ADC

This chapter describes how to use the ADC (Analog‑to‑Digital Converter) functionality on the board.

Warning

Rockchip SARADC maximum input voltage is 1.8V – do not exceed this limit!
Allwinner GPADC maximum input voltage is 1.8V, LRADC maximum is 1.266V – do not exceed these limits!

The ADC pin information on the expansion pins for each platform is as follows:

Motherboard SoC Platform Kernel Expansion Pins
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 None
K2C H618 Allwinner 5.4 None
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 None
K8 RK3588 Rockchip 5.10 SARADC X1
K8D RK3588S2 Rockchip 5.10 / 6.1 SARADC X2
K9 T527 Allwinner 5.15 None
K10B A733 Allwinner 5.15 GPADC X1
K11C RK3566 Rockchip 5.10 / 6.1 SARADC X1

Terminology

Term Description
ADC Analog‑to‑Digital Converter
SARADC Successive Approximation ADC
GPADC General Purpose ADC
LRADC Low‑Rate ADC

Specifications

ADC Resolution Max Sample Rate Input Voltage Range
SARADC 12‑bit 1 MHz 0 ~ 1.8 V
GPADC 12‑bit 1 MHz 0 ~ 1.8 V
LRADC 6‑bit 2 kHz 0 ~ 1.266 V

ADC Pin Location

  • ADC pins

Note

The △ symbol on the board expansion pin header marks pin 1. Use the pin number silkscreen to locate the actual pin number.

K7 pinout example: The K7 board provides 3 ADC channels, mapped to pins 36 (SARADC_VIN4), 38 (SARADC_VIN5), and 40 (SARADC_VIN6).

image-20251112185736716

DTS Configuration

DTS configuration differs across platforms; refer to the appropriate section for your board's platform.

Rockchip SARADC

Example SARADC node configuration for Rockchip platforms:

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

Example GPADC node configuration for Allwinner platforms with Kernel 4.9:

/*
 * channel_num: Maximum number of channels supported on the platform.
 * channel_select: Channel enable selection. 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 detection: channel0:0x01 channel1:0x02 channel2:0x04 channel3:0x08.
 * channel_chd_select: Compare function high data enable detection: channel0:0x01 channel1:0x02 channel2:0x04 channel3:0x08.
 */
gpadc:gpadc{
    compatible = "allwinner,sunxi-gpadc"; // Identifies the device for driver binding
    reg = <0x0 0x05070000 0x0 0x400>; // Register address
    interrupts = <GIC_SPI 0 IRQ_TYPE_NONE>; // Interrupt configuration
    clocks = <&clk_gpadc>; // Clock configuration
    channel_num = <2>; // Channels used
    channel_select = <0x05>; // Channel selection
    channel_data_select = <0>; // Enable channel data
    channel_compare_select = <0x05>; // Enable channel compare function
    channel_cld_select = <0x05>; // Enable low‑data compare
    channel_chd_select = <0>; // Enable high‑data compare
    channel0_compare_lowdata = <1700000>; // Interrupt when data below this value
    channel0_compare_higdata = <1200000>; // Interrupt when data above this value
    channel1_compare_lowdata = <460000>;
    channel1_compare_higdata = <1200000>;
    channel0_compare_lowdata = <1500000>; // Interrupt when data below this value
    channel0_compare_higdata = <1200000>; // Interrupt when data above this value
    key_cnt = <5>; // Number of keys (only used when GPADC0 is used for buttons)
    key0_vol = <210>; // Key voltage
    key0_val = <115>; // Key value reported
    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";
};

Example GPADC node configuration for Allwinner platforms with Kernel 5.15:

/*
 * channel_num: Maximum number of channels supported on the platform.
 * channel_select: Channel enable selection. 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 detection: channel0:0x01
 * channel1:0x02 channel2:0x04 channel3:0x08.
 * channel_chd_select: Compare function high data enable detection: channel0:0x01
 * channel1:0x02 channel2:0x04 channel3:0x08.
 */
    gpadc0:gpadc{
        channel_num = <10>; // Maximum number of channels (i.e., max keypad count)
        channel_select = <0x3>; // Channel selection (channels 0 and 1)
        channel_data_select = <0x3>; // Enable channel data
        channel_compare_select = <0x3>; // Enable compare function
        channel_cld_select = <0x3>; // Enable low‑data compare
        channel_chd_select = <0x3>; // Enable high‑data compare
        channel0_compare_lowdata = <1700000>; // Interrupt when channel0 data below this value
        channel0_compare_higdata = <200000>; // Interrupt when channel0 data above this value
        channel1_compare_lowdata = <1700000>; // Interrupt when channel1 data below this value
        channel1_compare_higdata = <200000>; // Interrupt when channel1 data above this value
        status = "okay";
        // Multiple ADC channels can be used as buttons; configuration example below:
        keyadc0 {
            key_cnt = <5>; // Number of buttons
            key0_vol = <115>; // Voltage when button pressed (in millivolts)
            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

Example LRADC node configuration for Allwinner platforms:

sunxi_keyboard:keyboard {
    compatible = "allwinner,keyboard";
    reg = <0x0 0x01c21800 0x0 0x400>; /* Register address */
    interrupts = <GIC_SPI 30 IRQ_TYPE_NONE>; /* Interrupt */
    status = "okay"; /* Enable the node */
    key_cnt = <5>;
    key0 = <115 115>; /* First value: voltage in mV, second: key code */
    key1 = <235 114>;
    key2 = <330 139>;
    key3 = <420 28>;
    key4 = <520 102>;
};

Driver Paths

Driver paths for each platform (relative to SDK root):

// 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 Testing

List the input device event nodes:

cat /proc/bus/input/devices

Read raw event data using hexdump:

hexdump /dev/input/event0

getevent is an Android command to view input device events:

getevent -l

evtest is an open‑source input event test tool for Linux:

evtest /dev/input/event0

SARADC Testing

On Rockchip platforms, SARADC is registered as an IIO (Industrial I/O) subsystem device. You can read ADC data as follows.

IIO Reading

List registered IIO devices:

ls /sys/bus/iio/devices/

List available interfaces for a specific IIO device (e.g., device 0):

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

Note

Key files under the interface:
in_voltageX_raw – X is the ADC channel number (e.g., 0, 6). Stores the raw ADC sample value.
in_voltage_scale – Voltage scale factor (V/LSB) used to convert raw value to actual voltage.

Voltage calculation formula:

Actual voltage (V) = raw_value × scale_factor

Read the scale factor:

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

Read the raw value for channel 6:

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

Shell Script

The following script reads the voltage on channel 6. It outputs the raw value, scale factor, and computed voltage every second.

#!/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

Run it:

chmod +x adc_read.sh
./adc_read.sh

C Program

The following C program reads the voltage on channel 6:

#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);
    }
}

Compile and run:

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