Linux SPI从机驱动开发要点

在 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;
}

四、关键配置与调试

  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-cpol 和 spi-cpha 模式配置是否正确 。
    • 大数据误码 :考虑启用 DMA 传输(在控制器支持且设备树中配置 dmas 属性)以减轻 CPU 负载,提升稳定性 。
    • 驱动未加载 :使用 dmesg | grep spi 查看内核日志,确认驱动 probe 函数是否被调用,以及设备树节点是否被正确解析 。

参考来源

相关推荐
feng_you_ying_li1 小时前
linux之网络层
linux·运维·网络
未来之窗软件服务1 小时前
Linux 运维日志删除的多种方式—东方仙盟
linux·运维·服务器·仙盟创梦ide·东方仙盟
小雉系统1 小时前
BcoreOS实战:用一个升级包,让Rocky Linux跑进Debian服务器
linux·运维·服务器·debian
thethefighter1 小时前
快速预览Word、WPS秒开,支持空格弹窗
linux·word·wps·快速预览·空格弹窗·nhdeepview
用户8351414049492 小时前
把日志和寄存器值喂给AI做故障定位,我的实际问法
linux·ubuntu
Ruiery2 小时前
Linux 6.6内核内存管理深度解析(十七):vmalloc — 内核要“虚拟连续“就够:物理页逐个凑,页表来连
linux·运维·服务器
Escalating_xu2 小时前
【Linux 网络编程】ARP 的具体过程与 ARP 欺骗:一条 IP → MAC 映射,怎样改变数据的去向?
linux·网络·tcp/ip
坚定的共产主义生产设备永不宕机3 小时前
服务器从裸机开始搭建ESXI虚拟机
linux·服务器·网络
刚入门的大一新生3 小时前
Linux-线程封装
linux·运维·服务器
god_cvz3 小时前
实践:Linux环境构建CTB工具(cesium-terrain-builder)
linux·gis·ctb