ADC驱动开发:多通道采集与DMA传输配置实践 - 第4节

4.1 交叉编译工具链配置

嵌入式Linux驱动开发与桌面开发最大的区别在于交叉编译。目标板(ARM、RISC-V等架构)资源有限,无法运行完整的编译工具链,因此需要在性能强大的宿主机(x86_64)上编译出目标板可执行的二进制文件。

4.1.1 工具链选择与安装

根据目标处理器架构选择对应的交叉编译工具链。常见选择如下:

目标架构 工具链前缀 典型包名
ARM Cortex-A7/A9 arm-linux-gnueabihf- gcc-arm-linux-gnueabihf
ARM Cortex-A53/A72 (64位) aarch64-linux-gnu- gcc-aarch64-linux-gnu
RISC-V 64位 riscv64-linux-gnu- gcc-riscv64-linux-gnu

以ARM 32位目标板为例,在Ubuntu宿主机上安装:

sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf
sudo apt-get install libc6-dev-armhf-cross

4.1.2 验证工具链

安装完成后,验证工具链是否可用:

arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-objdump --version

输出应显示版本信息,无“command not found”错误。

提示: 如果目标板使用Buildroot或Yocto构建系统,工具链通常由构建系统自动生成,位于 output/host/bin/ 目录下,前缀为 arm-buildroot-linux-gnueabihf-。

4.1.3 交叉编译测试

编写一个简单的C程序测试交叉编译环境:

// test_adc.c
#include <stdio.h>

int main(void) {
    printf("ADC Driver Development - Cross Compile OK\n");
    return 0;
}

编译并检查文件类型:

arm-linux-gnueabihf-gcc -o test_adc test_adc.c
file test_adc
# 输出应包含 "ELF 32-bit LSB executable, ARM"
交叉编译流程 宿主机 (x86_64) Ubuntu + 交叉工具链 源代码 .c / .dts 文件 交叉编译 arm-linux-gcc / dtc 目标板 (ARM) 运行 .ko / 可执行文件 宿主机编译 → 目标板运行:工具链前缀必须与目标架构匹配

4.2 内核源码树准备

ADC驱动以内核模块形式存在,编译时需要依赖完整的内核源码树(Kernel Source Tree)。源码树提供了头文件、Kconfig/Makefile体系以及编译规则。

4.2.1 获取内核源码

从官方仓库或板卡厂商获取内核源码:

# 从kernel.org获取主线内核
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.tar.xz
tar -xf linux-6.1.tar.xz

# 或从板卡厂商Git仓库克隆
git clone -b vendor-branch https://github.com/vendor/linux.git

4.2.2 配置内核

进入内核源码目录,使用目标板的默认配置:

cd linux-6.1
# 使用板卡厂商提供的defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vendor_defconfig

# 或使用menuconfig手动配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

确保以下ADC相关选项被启用:

  • CONFIG_IIO — IIO子系统支持
  • CONFIG_IIO_BUFFER — IIO缓冲区支持
  • CONFIG_IIO_DMA_BUFFER — IIO DMA缓冲区支持
  • CONFIG_ADC_xxx — 具体ADC驱动(如CONFIG_ADC_STM32)

4.2.3 编译内核与模块

# 编译内核镜像
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 zImage

# 编译设备树
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

# 编译内核模块
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules
注意: 编译ADC驱动模块时,必须使用与目标板运行内核完全相同的源码树。版本不匹配会导致模块插入失败("Invalid module format"错误)。

4.3 设备树基础

设备树(Device Tree)是描述硬件资源的结构化数据,Linux内核在启动时解析设备树来发现和初始化外设。ADC驱动依赖设备树来获取寄存器地址、中断号、时钟、DMA通道等参数。

4.3.1 设备树文件结构

文件类型 扩展名 说明
设备树源文件 .dts 可读的文本格式,描述硬件
设备树包含文件 .dtsi 公共硬件描述,被.dts引用
设备树二进制 .dtb 编译后的二进制,内核加载
设备树覆盖 .dtbo 运行时叠加的硬件描述

4.3.2 ADC设备树节点示例

以下是一个典型的ADC设备树节点,包含多通道和DMA配置:

adc1: adc@40012000 {
    compatible = "st,stm32-adc";
    reg = <0x40012000 0x400>;
    interrupts = <18 0>;
    clocks = <&rcc ADC1>;
    clock-names = "adc";
    vref-supply = <&vref>;

    #address-cells = <1>;
    #size-cells = <0>;

    /* 多通道配置 */
    channel@0 {
        reg = <0>;
        label = "AIN0";
    };
    channel@1 {
        reg = <1>;
        label = "AIN1";
    };
    channel@2 {
        reg = <2>;
        label = "AIN2";
    };

    /* DMA传输配置 */
    dmas = <&dma1 0 1 0x400 0x0>;
    dma-names = "rx";

    /* 连续转换模式 */
    st,adc-continuous-conv = <1>;
};

4.3.3 设备树编译

使用设备树编译器(dtc)将.dts编译为.dtb:

# 在内核源码树中编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

# 或单独编译
dtc -I dts -O dtb -o myboard.dtb myboard.dts

# 反编译查看
dtc -I dtb -O dts -o myboard.dts myboard.dtb
设备树与ADC驱动关系 设备树源文件 myboard.dts dtc 编译器 设备树编译器 设备树二进制 myboard.dtb 内核解析 of_* API ADC驱动 probe() 回调 硬件寄存器 0x40012000 设备树是硬件描述与驱动之间的桥梁:驱动通过 compatible 匹配节点, 通过 of_property_read_* 读取 reg、interrupts、dmas 等属性

4.3.4 设备树关键属性解析

属性 作用 ADC驱动使用场景
compatible 驱动匹配标识 驱动通过此字符串找到对应硬件
reg 寄存器地址范围 ioremap映射ADC控制寄存器
interrupts 中断号与触发类型 注册ADC转换完成中断
clocks 时钟源 使能ADC工作时钟
dmas DMA控制器与通道 配置DMA传输ADC数据
vref-supply 参考电压 regulator 获取ADC参考电压值
实践要点: 在编写ADC驱动前,务必确认设备树中ADC节点的compatible值与驱动中of_match_table完全一致;DMA配置中的dmas属性需要参考芯片参考手册的DMA请求映射表。

4.4 环境验证清单

完成上述配置后,使用以下清单验证开发环境是否就绪:

  1. 交叉工具链:执行 arm-linux-gnueabihf-gcc -v 无报错
  2. 内核源码树:make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- kernelversion 输出版本号
  3. 设备树编译:make ARCH=arm dtbs 生成对应.dtb文件
  4. 模块编译:编写空模块Makefile,执行 make -C /path/to/kernel M=$(pwd) modules 成功生成.ko
推荐工作流: 将交叉编译工具链路径加入 $PATH,设置 export ARCH=arm 和 export CROSS_COMPILE=arm-linux-gnueabihf- 到 ~/.bashrc,避免每次输入。