当前位置:首页>Linux>Linux SPI调试技巧

Linux SPI调试技巧

  • 2026-09-09 11:47:07
Linux SPI调试技巧
大家好,我是王鸽,之前文章有说过I2C 外设的调试技巧,这篇文章是SPI调试技巧,应遵循 “硬件→设备树→内核→用户态→波形→稳定性” 的分层闭环流程,结合内核动态调试、用户态工具与逻辑分析仪,可高效定位 90% 以上的通信与驱动问题。
硬件快速自检(无示波器时优先)
检查项
操作方法
正常结果
引脚连接
对照原理图,核对 SCLK/MOSI/MISO/CS
无虚焊、短接,CS 与从设备对应
电源复位
测量从设备供电与复位引脚
电压正常,复位时序符合手册
引脚复用
cat /sys/kernel/debug/pinctrl/*/pinmux
SPI 引脚未被复用为 GPIO
片选冲突
grep -r "cs-gpios" /sys/firmware/devicetree/base
无重复 CS 配置
设备树配置确认
&spi0 {         status = "okay";         pinctrl-name = "default";         pinctrl-0 = <&spi0_pins>;         ti,pindir-d0-out-d1-in;        wk2124A {          compatible = "wk2124A";    //  匹配字符串            reg = <0>;              //哪一个片选第0个片选              spi-cpha = <1>;              // 配置 spi  的模式                   #spi-tx-bus-width = <1>;   // 这是是 spi-tx 的总线宽度               #spi-rx-bus-width = <1>;                         spi-max-frequency = <10000000>;     // spi 最大速率配置                        };            };

首先判断加载SPI Device 驱动有没有进入probe函数中,后面就要考虑一下属性配置这块。

这些SPI Device必选的属性如下:

compatible:根据它找到SPI Device驱动reg:用来表示它使用哪个片选引脚spi-max-frequency:必选,该SPI设备支持的最大SPI时钟

可选属性如下:

spi-cpol:这是一个空属性(没有值),表示CPOL为1,即平时SPI时钟为低电平spi-cpha:这是一个空属性(没有值),表示CPHA为1,即在时钟的第2个边沿采样数据spi-cs-high:这是一个空属性(没有值),表示片选引脚高电平有效spi-3wire:这是一个空属性(没有值),表示使用SPI 三线模式spi-lsb-first:这是一个空属性(没有值),表示使用SPI传输数据时先传输最低为(LSB)spi-tx-bus-width:表示有几条MOSI引脚,没有这个属性时默认只有1条MOSI引脚spi-rx-bus-width:表示有几条MISO引脚,没有这个属性时默认只有1条MISO引脚spi-rx-delay-us:单位是毫秒,表示每次读传输后要延时多久spi-tx-delay-us:单位是毫秒,表示每次写传输后要延时多久
DMA优化:
大传输(>4KB)时启用 DMA:设备树中添加dma-names = "tx", "rx";,驱动中设置spi->dma_tx/spi->dma_rx。
# 确认SPI总线与设备节点存在ls
 /sys/bus/spi/devices/            # 应显示spiX.Y(如spi0.0)/sys/bus/spi/devices/spi0.0

中断调试

用cat /proc/interrupts | grep spi检查中断次数,若中断未触发,排查中断控制器配置是不是正确的?

内核调试

内核日志与驱动加载

dmesg | grep -i spi                 # 检查是否有“probe success”或错误 lsmod | grep spi                    # 确认控制器与设备驱动已加载
常见错误:chipselect already used(CS 冲突)、timeout(时钟 / 引脚错误)。
驱动代码跟踪传输过程
在驱动中添加dev_dbg()打印关键数据:
static int my_spi_probe(struct spi_device *spi) {    dev_dbg(&spi->dev, "probe: mode=%d, speed=%d, bits=%d\n",            spi->mode, spi->max_speed_hz, spi->bits_per_word);    // 传输前后打印tx/rx缓冲区    struct spi_transfer t = {        .tx_buf = tx_buf, .rx_buf = rx_buf, .len = 4,    };    struct spi_message msg;    spi_message_init(&msg);    spi_message_add_tail(&t, &msg);    dev_dbg(&spi->dev, "tx: %02x%02x%02x%02x\n", tx_buf[0], tx_buf[1], tx_buf[2], tx_buf[3]);    ret = spi_sync(spi, &msg);    dev_dbg(&spi->dev, "rx: %02x%02x%02x%02x, ret=%d\n", rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3], ret);    return ret;}
用户态快速验证(隔离驱动问题)
将从设备临时改为spidev(设备树中compatible = "spidev";),生成/dev/spidevX.Y,用工具做基础通信测试:
测试场景
命令示例
目的
读设备 ID
./spidev_test -D /dev/spidev0.0 -s 1000000 -p "\x9F\x00\x00\x00" -v
验证基本通信(如 Flash 的 0x9F 指令)
环回测试
./spidev_test -D /dev/spidev0.0 -s 500000 -l -v
硬件环回(短接 MOSI/MISO),排查控制器
模式切换
./spidev_test -D /dev/spidev0.0 -s 1000000 -O -H -v
验证 CPOL/CPHA(模式 1)是否匹配
位宽测试
./spidev_test -D /dev/spidev0.0 -s 1000000 -b 16 -p "\x1234" -v
适配 16 位字长设备
工具补充:spi-config -d /dev/spidev0.0 -q(查询当前配置)、printf "\x01\x02" | spi-pipe -d /dev/spidev0.0 | hexdump -C(自定义数据传输)。
波形分析(终极手段,解决协议不匹配)
使用逻辑分析仪(如 Saleae、PulseView)抓取 SCLK/MOSI/MISO/CS,重点核对:
  • SPI 模式:CPOL(空闲时钟电平)、CPHA(采样沿)是否与从设备手册一致。
  • 片选信号:传输期间 CS 是否持续拉低,无提前释放或抖动。
  • 数据位序:确认 MSB 优先(默认)或 LSB 优先(需在设备树设置spi-lsb-first)。
  • 时钟速率:实际频率是否接近配置值(控制器可能自动降频)。
  • 字节间隙:部分设备要求字节间有延时,用spidev_test -d 10(10μs)测试。
常见问题与解决方案(速查)
现象
核心原因
解决方法
传输超时(timeout)
时钟未产生、CS 错误、从设备未应答
1. 检查引脚复用;
2. 逻辑分析仪看 SCLK 是否输出;
3. 核对 CS 极性
数据乱码 / ID 错误
模式不匹配、位序错误、速率过高
1. 切换 CPOL/CPHA(0-3 模式逐一测试);
2. 启用 LSB 优先;
3. 降低速率至 1MHz 以下
只能发不能收
MOSI/MISO 接反、从设备未输出
1. 核对引脚;
2. 短接 MOSI/MISO 做环回测试;
3. 检查从设备供电
片选冲突
多个设备使用同一 CS
设备树中分配不同 CS,或使用 GPIO 模拟 CS
驱动 probe 失败
设备树 compatible 不匹配
确认compatible与驱动中of_match_table一致
总结
调试 SPI 的核心是先隔离硬件与协议问题,再定位驱动逻辑。优先通过spidev验证硬件与基本通信,再用动态调试与波形分析解决驱动细节。记住:逻辑分析仪是解决 SPI 问题的终极工具,90% 的协议不匹配问题可通过波形一眼定位。
谢谢阅读点赞收藏!

最新文章

随机文章