Linux SPI从机驱动开发要点

在 Linux 系统中,SPI 从机(Slave)驱动的开发主要围绕 spi_driver 结构体展开,通过设备树进行硬件资源配置,并使用 spi_transferspi_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_transferspi_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;
}

四、关键配置与调试

  1. 内核配置 :确保内核已启用 SPI 子系统及对应控制器驱动。

    bash 复制代码
    Device Drivers  --->
        [*] SPI support  --->
            <*>   Your SoC SPI controller driver (e.g., ARM SoC SPI)
  2. 用户空间测试 :使用 spidev_test 工具(内核源码 tools/spi/ 目录下)进行快速验证 。

    bash 复制代码
    # 编译
    makeC /path/to/kernel/source tools/spi
    # 测试,假设 /dev/spidev0.0 为你的设备
    ./spidev_test -D /dev/spidev0.0 -v
  3. 常见问题排查

    • 时钟不稳/无响应 :检查设备树中 spi-max-frequency 是否超出从机支持范围,确认 spi-cpolspi-cpha 模式配置是否正确 。
    • 大数据误码 :考虑启用 DMA 传输(在控制器支持且设备树中配置 dmas 属性)以减轻 CPU 负载,提升稳定性 。
    • 驱动未加载 :使用 dmesg | grep spi 查看内核日志,确认驱动 probe 函数是否被调用,以及设备树节点是否被正确解析 。

参考来源

相关推荐
w2005122412 小时前
Pod管理
linux·服务器·云原生·容器·k8s·podman
chen<>13 小时前
C++ 六种 memory_order:从原子性到线程间可见性.md
java·linux·开发语言·c++
一直C13 小时前
Linux系统编程|进程间通信IPC全套详解(1)(管道、信号)
linux·c语言·开发语言·网络·青少年编程·visual studio code
库玛西13 小时前
Linux网络编程:HTTP/HTTPS协议核心技术全解析
linux·运维·服务器·网络·c++·http·https
sxd200114 小时前
Vmware和multicast
linux·windows·vmware·无线桥接·multicast
暴力求解14 小时前
Linux网络---NAT代理服务、内网穿透
linux·网络·智能路由器
一直C14 小时前
Linux系统编程|信号进阶 + SystemV IPC(消息队列、共享内存)
linux·c语言·开发语言·算法·青少年编程·vim
_F_y14 小时前
Linux网络常用指令
linux·运维·网络
老当益壮梁奶奶16 小时前
Linux软件编程学习笔记(九):消息队列、共享内存与信号灯详解
linux·c语言·笔记·学习
小雪崩16 小时前
嵌入式学习 day35:进程间通信-消息队列、共享空间及有名信号量
linux·c语言·学习