3. SPI设备驱动开发环境搭建:交叉编译工具链配置、内核源码树准备、设备树SPI节点编写
SPI设备驱动的开发与调试,离不开一个稳固且可复现的嵌入式开发环境。本章将聚焦于搭建这一环境的三个核心环节:交叉编译工具链的配置、内核源码树的准备,以及设备树(Device Tree)SPI节点的编写。这三者构成了从代码编译到硬件描述的基础链路,任何一环的缺失或错误,都会导致驱动无法正确加载或运行。
核心原则:工具链版本必须与内核源码版本严格匹配;设备树节点中的寄存器地址、中断号、时钟频率等参数,必须与目标芯片的数据手册(Datasheet)和原理图完全一致。
3.1 交叉编译工具链配置
嵌入式Linux开发中,宿主机(通常是x86架构的PC)无法直接编译出目标机(ARM、RISC-V等架构)可执行的二进制文件,必须使用交叉编译工具链。配置过程分为选择、安装与验证三步。
3.1.1 工具链选择与安装
根据目标SoC架构选择对应的工具链。主流选择包括:
| 目标架构 | 常见工具链前缀 | 典型提供商 | 适用场景 |
|---|---|---|---|
| ARM (32-bit) | arm-linux-gnueabihf- |
Linaro, ARM | STM32MP1, i.MX6, AM335x |
| AArch64 (64-bit) | aarch64-linux-gnu- |
Linaro, ARM | RK3588, i.MX8, Jetson |
| RISC-V (64-bit) | riscv64-linux-gnu- |
SiFive, T-Head | K210, TH1520 |
安装步骤(以ARM 32-bit为例):
- 下载:从Linaro官网或芯片厂商SDK中获取预编译工具链压缩包(如
gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz)。 - 解压:
tar -xvf gcc-linaro-*.tar.xz -C /opt/ - 添加至PATH:编辑
~/.bashrc,添加export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin,然后执行source ~/.bashrc。
3.1.2 工具链验证
安装完成后,必须验证工具链是否可用且版本正确:
# 检查编译器版本
arm-linux-gnueabihf-gcc --version
# 编译一个简单的测试程序
echo 'int main(){ return 0; }' > test.c
arm-linux-gnueabihf-gcc -o test test.c
# 查看生成文件的架构信息
file test
# 预期输出: test: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), ...
常见错误:如果执行
file test 显示的是 x86-64 架构,说明宿主机自带的 gcc 被调用,而非交叉编译器。请检查 PATH 环境变量中交叉工具链的路径是否位于系统 gcc 路径之前。
3.2 内核源码树准备
编译SPI设备驱动模块(.ko文件)时,必须依赖完整的内核源码树,尤其是已配置好的 .config 文件和编译生成的 Module.symvers 文件。
3.2.1 获取与解压内核源码
从芯片厂商提供的BSP(Board Support Package)或Linux内核官方仓库获取源码:
# 以Linux 5.10.y 版本为例
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.120.tar.xz
tar -xvf linux-5.10.120.tar.xz
cd linux-5.10.120
3.2.2 配置内核
使用目标平台的默认配置文件生成 .config:
# 假设目标平台为 STM32MP157
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- stm32mp157_defconfig
# 如果需要微调SPI相关选项,使用菜单配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
# 进入 Device Drivers -> SPI support,确保 CONFIG_SPI_STM32 或对应驱动被选中为 M 或 Y
3.2.3 编译内核与模块
首次编译需要生成必要的头文件和版本信息:
# 编译内核镜像(耗时较长)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage LOADADDR=0xC2000040 -j4
# 编译内核模块
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules -j4
# 安装模块到临时目录(用于后续打包到根文件系统)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules_install INSTALL_MOD_PATH=./modules_install
提示:编译完成后,务必检查
include/generated/autoconf.h 和 Module.symvers 文件是否存在。这两个文件是外部模块编译时自动依赖的关键。
3.3 设备树(Device Tree)SPI节点编写
设备树是描述硬件资源的静态数据结构。SPI控制器及其从设备(Slave Device)的节点编写质量,直接决定了驱动能否正确探测到硬件。
3.3.1 SPI控制器节点结构
SPI控制器节点通常由SoC厂商在 .dtsi 文件中定义,开发者只需在板级 .dts 文件中使能并配置管脚复用。以下是一个典型的SPI控制器节点示例:
/* 在 stm32mp157.dtsi 中定义 */
spi2: spi@4000b000 {
compatible = "st,stm32h7-spi";
reg = <0x4000b000 0x400>;
interrupts = <36>;
clocks = <&rcc SPI2_K>;
resets = <&rcc SPI2_R>;
dmas = <&dmamux1 39 0x400 0x05>,
<&dmamux1 40 0x400 0x05>;
dma-names = "rx", "tx";
status = "disabled";
};
/* 在板级 myboard.dts 中使能并配置管脚 */
&spi2 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi2_pins_a>;
pinctrl-1 = <&spi2_pins_sleep>;
cs-gpios = <&gpioc 1 GPIO_ACTIVE_LOW>;
status = "okay";
/* SPI从设备节点 */
spidev@0 {
compatible = "rohm,dh2228fv";
reg = <0>;
spi-max-frequency = <10000000>;
};
};
3.3.2 SPI从设备节点关键属性
| 属性名 | 类型 | 说明 | 示例值 |
|---|---|---|---|
compatible |
string | 驱动匹配字符串,必须与驱动中 of_match_table 一致 |
"rohm,dh2228fv" |
reg |
u32 | 片选(CS)线编号,0对应第1条CS | <0> |
spi-max-frequency |
u32 | 该设备支持的最大SPI时钟频率,单位Hz | <10000000> |
spi-cpha |
empty | 存在时表示使用CPHA=1模式(数据采样沿) | (无值) |
spi-cpol |
empty | 存在时表示使用CPOL=1模式(时钟极性) | (无值) |
3.3.3 设备树编译与反编译
编写完成后,需要将 .dts 源文件编译为 .dtb 二进制文件,供U-Boot或内核加载:
# 编译设备树
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs
# 或者单独编译指定文件
./scripts/dtc/dtc -I dts -O dtb -o myboard.dtb myboard.dts
# 反编译验证(检查生成的dtb是否正确)
./scripts/dtc/dtc -I dtb -O dts -o myboard_reverse.dts myboard.dtb
调试技巧:如果驱动无法probe,首先使用
dtc -I dtb -O dts 反编译实际加载的dtb,检查SPI节点是否被正确包含、status 是否为 "okay"、compatible 字符串是否与驱动完全匹配(包括大小写)。
3.4 环境验证清单
完成上述配置后,建议按照以下清单逐项确认环境就绪:
| 检查项 | 验证命令/方法 | 预期结果 |
|---|---|---|
| 交叉编译器可用 | arm-linux-gnueabihf-gcc --version |
显示版本信息,无“command not found” |
| 内核 .config 存在 | ls -l .config |
文件存在且大小不为0 |
| SPI驱动被选中 | grep CONFIG_SPI .config |
显示 CONFIG_SPI=y 或 =m |
| 设备树编译无错误 | make dtbs |
无报错,生成对应的 .dtb 文件 |
| SPI节点 status 为 okay | dtc -I dtb -O dts myboard.dtb | grep spi |
SPI节点下包含 status = "okay" |
最佳实践:建议将上述环境搭建步骤写成Shell脚本(如
setup_env.sh),包含工具链路径设置、内核编译、设备树编译等命令。每次在新机器上搭建环境时,只需运行该脚本即可快速复现,避免手动遗漏。