SPI驱动调试与内核崩溃定位:设备驱动工程实践故障分析 - 第3节
3.1 设备树节点属性详解
SPI 设备树节点是驱动与硬件描述之间的桥梁。每个 SPI 从设备在设备树中对应一个子节点,挂载在 SPI 主控制器的节点之下。节点中必须包含 compatible、reg 和 spi-max-frequency 三个核心属性,同时可根据需要添加中断、DMA 和 pinctrl 描述。
3.1.1 核心属性:compatible / reg / spi-max-frequency
| 属性名 | 类型 | 必需 | 说明 |
|---|---|---|---|
| compatible | 字符串列表 | 是 | 设备驱动匹配标识,格式为 "厂商,型号" |
| reg | u32 | 是 | SPI 片选编号(0 基址) |
| spi-max-frequency | u32 | 是 | SPI 总线最大时钟频率,单位 Hz |
关键规则:compatible 属性必须与驱动中 of_match_table 定义的字符串完全一致,否则驱动无法绑定设备。reg 属性值对应硬件片选线编号,多片选设备需注意与主控制器片选 GPIO 的映射关系。
/* 典型 SPI 设备节点示例 */
&spi1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = &spi1_pins;
temperature_sensor: sensor@0 {
compatible = "ti,lm70";
reg = <0>;
spi-max-frequency = <20000000>;
spi-cpha;
spi-cpol;
};
adc_device: adc@1 {
compatible = "maxim,max1027";
reg = <1>;
spi-max-frequency = <10000000>;
interrupts = <GIC_SPI 42 IRQ_TYPE_EDGE_RISING>;
};
};
调试提示:spi-max-frequency 设置过高可能导致数据采样错误。调试时建议从较低频率(如 1MHz)开始,逐步提升至目标值,同时用示波器观察 MISO/MOSI 信号质量。
3.1.2 SPI 模式与时钟极性属性
SPI 总线支持四种工作模式,由时钟极性(CPOL)和时钟相位(CPHA)组合决定。设备树中通过以下布尔属性描述:
- spi-cpol:时钟极性为高电平空闲(CPOL=1)
- spi-cpha:数据在第二个时钟边沿采样(CPHA=1)
- spi-cs-high:片选信号高电平有效(默认低电平有效)
- spi-3wire:三线制 SPI,MISO 与 MOSI 复用
3.2 中断与 DMA 描述
3.2.1 中断属性绑定
SPI 从设备的中断描述遵循标准设备树中断绑定规范。中断控制器类型、中断号和触发类型共同构成完整的中断描述。
/* 中断描述格式 */
interrupts = <中断控制器类型 中断号 触发类型>;
/* 实际示例:GPIO 中断 */
interrupt-parent = <&gpio1>;
interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
/* 实际示例:GIC 中断 */
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
| 触发类型宏 | 数值 | 说明 |
|---|---|---|
| IRQ_TYPE_EDGE_RISING | 1 | 上升沿触发 |
| IRQ_TYPE_EDGE_FALLING | 2 | 下降沿触发 |
| IRQ_TYPE_LEVEL_HIGH | 4 | 高电平触发 |
| IRQ_TYPE_LEVEL_LOW | 8 | 低电平触发 |
常见错误:中断号与硬件连接不一致是 SPI 驱动调试中的高频问题。务必核对原理图中 SPI 从设备的 IRQ 引脚连接到了哪个 GPIO 或中断控制器,以及该引脚的中断号是否与设备树一致。使用
cat /proc/interrupts 可验证中断是否注册成功。
3.2.2 DMA 属性描述
SPI 控制器支持 DMA 传输时,需要在设备树中描述 DMA 通道和请求线。DMA 属性通常定义在主控制器节点中,从设备节点通过继承获得 DMA 能力。
/* SPI 主控制器 DMA 描述 */
spi2: spi@ff110000 {
compatible = "rockchip,rk3399-spi", "rockchip,rk3066-spi";
reg = <0x0 0xff110000 0x0 0x1000>;
interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac 1 7>, <&dmac 0 7>;
dma-names = "tx", "rx";
#address-cells = <1>;
#size-cells = <0>;
/* 从设备节点继承 DMA 能力 */
spi_device@0 {
compatible = "vendor,device";
reg = <0>;
spi-max-frequency = <50000000>;
};
};
3.3 pinctrl 配置
3.3.1 pinctrl 绑定规则
pinctrl 子系统负责 SPI 引脚的复用功能配置。设备树中通过 pinctrl-names 和 pinctrl-0 属性将引脚状态与设备状态关联。
/* pinctrl 配置结构 */
&spi1 {
pinctrl-names = "default", "sleep";
pinctrl-0 = &spi1_pins_active;
pinctrl-1 = &spi1_pins_sleep;
status = "okay";
};
/* 引脚节点定义 */
&pinctrl {
spi1 {
spi1_pins_active: spi1-active {
rockchip,pins = <1 RK_PB0 RK_FUNC_2 &pcfg_pull_up_drv_level_0>,
<1 RK_PB1 RK_FUNC_2 &pcfg_pull_up_drv_level_0>,
<1 RK_PB2 RK_FUNC_2 &pcfg_pull_up_drv_level_0>,
<1 RK_PB3 RK_FUNC_2 &pcfg_pull_up_drv_level_0>;
};
spi1_pins_sleep: spi1-sleep {
rockchip,pins = <1 RK_PB0 RK_FUNC_GPIO &pcfg_output_low>,
<1 RK_PB1 RK_FUNC_GPIO &pcfg_output_low>,
<1 RK_PB2 RK_FUNC_GPIO &pcfg_output_low>,
<1 RK_PB3 RK_FUNC_GPIO &pcfg_output_low>;
};
};
};
3.3.2 引脚配置参数解析
| 参数位置 | 含义 | 示例值 |
|---|---|---|
| bank | GPIO 组编号 | 1 (GPIO1) |
| pin | 组内引脚编号 | RK_PB0 (GPIO1_B0) |
| func | 复用功能编号 | RK_FUNC_2 (SPI 功能) |
| pull/drive | 上下拉与驱动能力 | pcfg_pull_up_drv_level_0 |
调试技巧:当 SPI 通信不稳定时,检查 pinctrl 配置是否正确。使用
cat /sys/kernel/debug/gpio 查看引脚复用状态,确认引脚是否被正确配置为 SPI 功能而非 GPIO。常见问题包括:引脚复用冲突(被其他外设占用)、上下拉配置错误导致信号电平异常。
3.4 完整设备树节点综合示例
以下是一个完整的 SPI 设备树节点,集成了所有核心属性、中断、DMA 和 pinctrl 配置:
/* 完整 SPI 设备树节点 */
&spi0 {
status = "okay";
pinctrl-names = "default", "sleep";
pinctrl-0 = &spi0_pins_active;
pinctrl-1 = &spi0_pins_sleep;
dmas = <&dmac 0 2>, <&dmac 1 2>;
dma-names = "tx", "rx";
/* SPI NOR Flash */
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <104000000>;
spi-cpol;
spi-cpha;
m25p,fast-read;
broken-flash-reset;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "bootloader";
reg = <0x0 0x100000>;
read-only;
};
partition@100000 {
label = "kernel";
reg = <0x100000 0x500000>;
};
};
};
/* SPI 温度传感器 */
sensor@1 {
compatible = "maxim,max31865";
reg = <1>;
spi-max-frequency = <5000000>;
interrupts = <&gpio2 10 IRQ_TYPE_EDGE_FALLING>;
interrupt-names = "ready";
};
};
3.5 常见绑定错误与调试方法
| 错误类型 | 现象 | 排查方法 |
|---|---|---|
| compatible 不匹配 | 驱动 probe 函数未调用 | 检查 /sys/bus/spi/devices/ 下设备名称 |
| reg 片选冲突 | 多个设备使用同一片选 | 核对原理图片选连接 |
| spi-max-frequency 过高 | 数据错位、CRC 错误 | 降低频率测试,观察信号质量 |
| 中断号错误 | 中断不触发或触发异常 | 使用 cat /proc/interrupts 验证 |
| pinctrl 配置错误 | 引脚无输出或电平异常 | 检查 /sys/kernel/debug/pinctrl/ |
调试黄金法则:当 SPI 设备无法正常工作时,首先检查设备树是否被正确解析。使用
dtc -I dtb -O dts /sys/firmware/fdt 反编译当前使用的设备树,确认节点属性与预期一致。这是定位设备树绑定问题的第一步,也是最有效的一步。