SPI是嵌入式开发中最常见的高速通信协议,广泛应用于Flash存储、显示屏、传感器等外设。本文系统讲解SPI协议基础、子系统架构、驱动开发实战和调试技巧,帮你快速掌握SPI驱动开发。
一、SPI协议基础
🖥️ SPI四线制
💡 全双工 vs I2C:SPI支持全双工通信(同时发送和接收),而I2C是半双工。这是SPI速度更高的原因之一。
🔄 SPI四种模式
二、SPI子系统架构
🏗️ 核心架构
| | | | 🟠 spi_device spi_driver 从设备+驱动 |
📦 核心数据结构
// SPI主机
struct spi_master {
struct device dev;
u16 bus_num; // 总线编号
u16 num_chipselect; // 片选数量
u32 max_speed_hz; // 最大时钟
int (*transfer_one)(struct spi_master*, struct spi_device*, struct spi_transfer*);
};
// SPI设备
struct spi_device {
struct spi_master *master;
u32 max_speed_hz;
u8 chip_select;
u16 mode;
};
// SPI传输
struct spi_transfer {
const void *tx_buf; // 发送缓冲
void *rx_buf; // 接收缓冲
unsigned len;
u32 speed_hz;
};
三、设备树配置
&spi0 {
status = "okay";
/* SPI Flash */
spi_flash:flash@0 {
compatible = "jedec,spi-nor";
reg = <0>; // 片选0
spi-max-frequency = <50000000>; // 50MHz
};
/* OLED显示屏 */
oled@1 {
compatible = "solomon,ssd1306";
reg = <1>;
spi-max-frequency = <10000000>;
};
};
四、SPI传输API
⚡ 常用API速查
| |
|---|
spi_write(spi, buf, len) | |
spi_read(spi, buf, len) | |
spi_sync(spi, message) | |
spi_async(spi, message) | |
五、SPI驱动开发实战
🔧 SPI Flash驱动框架
/* 读取Flash ID */
static int spi_flash_read_id(struct spi_device *spi)
{
u8 tx_buf[1] = { 0x9F };
u8 rx_buf[3];
return spi_write_then_read(spi, tx_buf, 1, rx_buf, 3);
}
/* probe函数 */
static int spi_flash_probe(struct spi_device *spi)
{
data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
data->spi = spi;
spi_set_drvdata(spi, data);
spi_flash_read_id(data);
return0;
}
/* 驱动注册 */
static struct spi_driver spi_flash_driver = {
.probe = spi_flash_probe,
.remove = spi_flash_remove,
.driver = {
.name = "spi_flash",
.of_match_table = spi_flash_of_match,
},
};
module_spi_driver(spi_flash_driver);
六、调试技巧
🛠️ 用户空间调试
# 安装工具
apt install spidev-tools
# 查看SPI设备
ls /dev/spidev*
# 传输测试
spidev_test -D /dev/spidev0.0 -v
🔍 内核调试
# 查看SPI设备
ls /sys/bus/spi/devices/
# 查看SPI驱动
ls /sys/bus/spi/drivers/
# 查看内核日志
dmesg | grep -i spi
七、SPI vs I2C对比
八、核心要点总结
📌 SPI核心要点:
- 核心API:spi_write/spi_read/spi_sync/spi_async
- 设备树:spi-max-frequency设置时钟频率