介绍

架构

ADC 驱动遵循 Linux 的工业 I/O (IIO)子系统。IIO 为用户空间提供 ADC 接口。ADC 软件架构如下面的图所示。

../../rst_linux/8_adc/figures/adc_software_arch.svg

ADC 软件架构包含以下部分:

  • IIO 驱动程序: ADC 驱动程序。

    • ADC: ADC 驱动程序。

    • Comparator: 比较器驱动程序,仅在 ADC 处于比较器辅助模式时使用。

    • IIO 定时器触发器:仅在 ADC 或比较器处于定时器触发模式时使用。

  • IIO 框架:IIO 子系统核心驱动程序。

  • IIO 用户(内核):供内核使用。

  • 应用:用户空间使用。

    • libiio:Libiio 是一个用于访问 IIO 设备的开源库。它封装了对 /sys/bus/IIO/devices(配置 IIO)和 /dev/IIO/deviceX(读/写 IIO)的访问,并提供了易于测试的 IIO 命令行工具(iio_info / iio_readdev)和 iiod 服务器。有关 libiio 的源代码,请参阅 github libiio

    • Demo: 一个展示如何使用 ADC 的简单示例。

参考 kernel industrial v5.4kernel industrial v6.6 获取有关 IIO 的更多细节。

实现

ADC 驱动在以下文件中实现。

文件

描述

<linux>/drivers/rtkdrivers/adc/Kconfig

ADC 驱动程序 Kconfig

<linux>/drivers/rtkdrivers/adc/Makefile

ADC 驱动程序 Makefile

<linux>/drivers/rtkdrivers/adc/realtek-adc.c

ADC 函数

<linux>/drivers/rtkdrivers/adc/realtek-adc.h

ADC 相关的函数声明、宏定义、结构体定义以及引用的其他头文件。

<linux>/drivers/rtkdrivers/adc/realtek-comparator.c

ADC 比较器函数。它在 ADC 处于比较器辅助模式时使用。

<linux>/drivers/rtkdrivers/adc/realtek-comparator.h

比较器相关的函数声明、宏定义、结构体定义以及引用的其他头文件。

配置

设备树配置

ADC 设备树节点:

adc: adc@42012000 {
   compatible = "realtek,ameba-adc";
   #address-cells = <1>;
   #size-cells = <1>;
   #io-channel-cells = <1>;
   reg = <0x42012000 0x100>,
      <0x42012800 0x100>;
   interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
   clocks = <&rcc RTK_CKE_CTC>, <&rcc RTK_CKE_ADC>;
   clock-names = "rtk_ctc_clk", "rtk_adc_clk";
   rtk,adc-mode = <0>; // 0: Software-trigger mode, 1: Automatic mode, 2: Timer-trigger mode
   rtk,adc-timer-period = <200000000>; // Useful only in timer-trigger mode. Unit: ns. Range: 100ms~2s
   //rtk,adc-channels = <0>, <1>, <2>, <6>;
   //rtk,adc-diff-channels = <4 5>;
   nvmem-cells = <&adc_normal_cal>, <&adc_vbat_cal>;
   nvmem-cell-names = "normal_cal", "vbat_cal";
   status = "disabled";
   comparator: comparator@0 {
      compatible = "realtek,ameba-comparator";
      interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
      rtk,cmp-ref0 = <10>;
      rtk,cmp-ref1 = <30>;
   };
};

ADC 的设备树配置在下表中列出。

属性

描述

默认值

可配置

compatible

ADC描述符

“realtek,ameba-adc”

reg

ADC的硬件地址和大小

<0x42012000 0x100>

reg

比较器的硬件地址和大小

<0x42012800 0x100>

interrupts

ADC的GIC编号

<GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>

interrupts

比较强的GIC编号

<GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>

clocks

ADC的时钟

<&rcc RTK_CKE_CTC> and <&rcc RTK_CKE_ADC>

rtk,adc-mode

ADC比较模式

  • 0: 软件触发模式

  • 1: 自动模式

  • 2: 定时器触发模式

  • 3: 比较器辅助模式

0/1/2/3

rtk,adc-timer-period

ADC定时器周期

只在比较器辅助模式时使用。 单位:纳秒。 范围: 100ms~2s

nvmem-cells

ADC的nvmem单元

nvmem-cell-names

ADC的nvmem单元的名称

status

是否启用该设备

  • disabled

  • okay

rtk,cmp-ref0

比较器内部参考电压 0

0~31

rtk,cmp-ref1

比较器内部参考电压 1

0~31

备注

  • 当选择 ADC 定时器触发模式时,必须进行以下配置。

    rtk,adc-mode = <2>;
    
  • realtek-adc.c 中的参数 realtek_adc_cfg 中选择的定时器索引,其对应的定时器设备树节点状态必须设置为 okay

  • 只有当 rtk,adc-mode = <3> 时,比较器子节点才会被填充。

  • 当选择比较器定时器触发模式时,必须进行以下配置。

    rtk,adc-mode = <3>;
    
  • realtek-comparator.c 中的参数 realtek_comp_priv_info 中选择的定时器索引,其对应的定时器设备树节点状态必须设置为 okay

编译配置

按顺序选择 Device Drivers > Drivers for Realtek > ADC driver

../../rst_linux/8_adc/figures/adc_driver.png

APIs

官方文件: kernel API guide v5.4kernel API guide v6.6

用户空间 API

Sysfs 接口

接口

介绍

/sys/bus/iio/devices/iio:deviceX

配置并启用 IIO 设备。

/sys/bus/iio/devices/triggerX

配置并启用 IIO 触发器。

更多有关 API 的细节请参考 <linux>/Documentation/ABI/testing/sysfs-bus-iio

用户空间 ADC 的演示在 <test>/adc

ADC 示例

该演示是一个用于读取单个 ADC 样本数据的简单示例。

  1. 打开 ADC 单通道原始读取功能

    sprintf(dev_name, "/sys/bus/iio/devices/iio:device0/in_voltage%d_raw", adc_ch);
    fd = open(dev_name, O_RDONLY);
    
  2. 单次读取 ADC 样本数据

    read(fd, buffer, 4);
    
  3. 将读取的数据从字符转换为整型(int)

    value = atoi(buffer);
    

    该值是 ADC 单次读取的数据。

ADC 单次读取示例

  1. 获取单个原始样本数据

    cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw
    
  2. 获取 ADC 偏置

    cat /sys/bus/iio/devices/iio:device0/in_voltage_offset
    
  3. 获取 ADC 量程

    cat /sys/bus/iio/devices/iio:device0/in_voltage_scale
    
  4. 获取 ADC 差分偏置

    cat /sys/bus/iio/devices/iio:device0/in_voltage-voltage_offset
    
  5. 获取 ADC 差分量程

    cat /sys/bus/iio/devices/iio:device0/in_voltage-voltage_scale
    

ADC 缓存读取示例

读取 ADC 缓冲区的步骤如下:

  1. 创建触发器

    echo 0 > /sys/devices/iio_sysfs_trigger/add_trigger
    

    备注

    0 是我们需要分配给触发器的索引。

  2. 将触发器分配给设备

    echo sysfstrig0 > /sys/bus/iio/devices/iio:device0/trigger/ current_trigger
    

    备注

    由于我们使用 0 作为索引,因此触发器将被命名为 sysfstrig0。

  3. 启用扫描元素:选择其数据值将被推入缓冲区的通道

    echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage0_en
    echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage1_en
    echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage2_en
    echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage6_en
    
  4. 设置缓存大小

    echo 100 > /sys/bus/iio/devices/iio:device0/buffer/length
    
  5. 启用缓存

    echo 1 > /sys/bus/iio/devices/iio:device0/buffer/enable
    
  6. 启用触发器:开始采集

    echo 1 > /sys/bus/iio/devices/trigger0/trigger_now
    
  7. 关闭缓存

    echo 0 > /sys/bus/iio/devices/iio:device0/buffer/enable
    

字符设备

接口

介绍

/dev/iio:deviceX

访问配置的事件和数据。

内核空间 API

用途

接口

介绍

iio_read_channel_raw

从指定的通道读取。

iio_convert_raw_to_processed

将原始值转换为处理后的值。

iio_read_channel_attribute

从设备属性中读取值。

iio_read_channel_offset

读取通道的偏置。

iio_read_channel_scale

读取通道的缩放值。

iio_read_channel_processed

从指定通道读取处理后的值。

iio_get_channel_type

获取通道的类型。

配置文件系统

接口

介绍

iio_sw_trigger_create

创建新触发器类型。

iio_sw_trigger_destroy

终止触发器类型。

iio_register_sw_trigger_type

注册新触发器类型。

iio_unregister_sw_trigger_type

注销触发器类型。

更多有关 API 的细节请参考:

  • <linux>/Documentation/ABI/testing/configfs-iio

  • <linux>/Documentation/iio/iio_configfs.rst

调试文件系统

接口

介绍

iio_debugfs_read_reg

读取寄存器

iio_debugfs_write_reg

写寄存器

simple_open

打开