在 Linux 系统中,SPI 从机(Slave)驱动的开发主要围绕 spi_driver 结构体展开,通过设备树进行硬件资源配置,并使用 spi_transfer 和 spi_message 进行数据传输 。
一、SPI 从机驱动核心框架
一个标准的 SPI 设备驱动包含以下核心结构:
c
#include <linux/spi/spi.h>
static const struct of_device_id my_spi_of_match[] = {
{ .compatible = "vendor,my-spi-device" },
{},
};
MODULE_DEVICE_TABLE(of, my_spi_of_match);
static int my_spi_probe(struct spi_device *spi)
{
// 1. 获取设备树配置
// 2. 初始化设备私有数据结构
// 3. 配置 SPI 参数(模式、频率等)
// 4. 注册字符设备或其它内核接口
printk(KERN_INFO "My SPI device probed successfully.
");
return 0;
}
static void my_spi_remove(struct spi_device *spi)
{
// 清理资源
printk(KERN_INFO "My SPI device removed.
");
}
static struct spi_driver my_spi_driver = {
.driver = {
.name = "my_spi_device",
.of_match_table = my_spi_of_match,
.owner = THIS_MODULE,
},
.probe = my_spi_probe,
.remove = my_spi_remove,
};
module_spi_driver(my_spi_driver);
二、设备树节点配置
在硬件平台的设备树源文件(.dts)中,需要为 SPI 从机设备添加节点,该节点必须挂载在对应的 SPI 控制器(主机)节点之下 。
dts
&spi0 { /* 假设这是 SPI 控制器节点 */
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
my_spi_device@0 {
compatible = "vendor,my-spi-device"; // 必须与驱动中的匹配表一致
reg = <0>; // 片选信号编号
spi-max-frequency = <10000000>; // 最大通信频率
spi-cpol; // 可选:时钟极性高
spi-cpha; // 可选:时钟相位第二个边沿采样
// 其它 GPIO、中断等配置
interrupt-parent = <&gpio0>;
interrupts = <5 IRQ_TYPE_EDGE_RISING>;
};
};
三、SPI 数据传输模型
Linux SPI 核心层使用 spi_transfer 和 spi_message 来组织一次或多次数据传输 。
| 数据结构 | 描述 | 关键成员 |
|---|---|---|
struct spi_transfer |
描述一次单/双向数据传输 | .tx_buf, .rx_buf, .len, .delay_usecs, .speed_hz |
struct spi_message |
多个 spi_transfer 的集合,原子执行 |
.transfers (链表), .actual_length |
同步数据传输示例:
c
int spi_send_receive(struct spi_device *spi, u8 *tx_data, u8 *rx_data, int len)
{
int ret;
struct spi_transfer t = {
.tx_buf = tx_data,
.rx_buf = rx_data,
.len = len,
.delay_usecs = 10, // 传输间延时
.speed_hz = spi->max_speed_hz, // 可覆盖默认速度
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
ret = spi_sync(spi, &m); // 同步调用,阻塞等待完成
if (ret < 0) {
dev_err(&spi->dev, "SPI transfer failed: %d
", ret);
} else {
// 成功,实际传输长度在 m.actual_length
}
return ret;
}
四、关键配置与调试
-
内核配置 :确保内核已启用 SPI 子系统及对应控制器驱动。
bashDevice Drivers ---> [*] SPI support ---> <*> Your SoC SPI controller driver (e.g., ARM SoC SPI) -
用户空间测试 :使用
spidev_test工具(内核源码tools/spi/目录下)进行快速验证 。bash# 编译 makeC /path/to/kernel/source tools/spi # 测试,假设 /dev/spidev0.0 为你的设备 ./spidev_test -D /dev/spidev0.0 -v -
常见问题排查 :
- 时钟不稳/无响应 :检查设备树中
spi-max-frequency是否超出从机支持范围,确认spi-cpol和spi-cpha模式配置是否正确 。 - 大数据误码 :考虑启用 DMA 传输(在控制器支持且设备树中配置
dmas属性)以减轻 CPU 负载,提升稳定性 。 - 驱动未加载 :使用
dmesg | grep spi查看内核日志,确认驱动 probe 函数是否被调用,以及设备树节点是否被正确解析 。
- 时钟不稳/无响应 :检查设备树中