SPI 驱动开发
1. 概述
1.1 功能简介
SPI(Serial Peripheral Interface)是一种高速同步串行通信接口,采用全双工、主从架构。RK3576 内置多路 SPI 控制器,支持主模式和从模式,适用于连接 Flash、LCD、ADC 等高速外设。M4-R2 底板 40PIN 引脚提供 SPI 接口(Pin19 MOSI、Pin21 MISO、Pin23 SCLK、Pin24 CE0、Pin26 CE1)。
1.2 应用场景
- Flash 存储:连接 SPI NOR Flash / SPI NAND Flash
- LCD 显示:SPI 接口的 TFT LCD 屏
- ADC/DAC:高速 ADC 采样数据读取
- 传感器:SPI 接口的加速度计、磁力计等
- 无线模块:SPI 接口的 LoRa、ZigBee 模块
1.3 工作原理
SPI 采用四线制:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。RK3576 的 SPI 控制器支持以下模式:
| 模式 | CPOL | CPHA | 说明 |
|---|---|---|---|
| Mode 0 | 0 | 0 | 时钟空闲低,第一个沿采样 |
| Mode 1 | 0 | 1 | 时钟空闲低,第二个沿采样 |
| Mode 2 | 1 | 0 | 时钟空闲高,第一个沿采样 |
| Mode 3 | 1 | 1 | 时钟空闲高,第二个沿采样 |
详见 RK 官方文档:[《Rockchip_Developer_Guide_Linux_Software_CN.pdf》]
2. 硬件准备
2.1 硬件清单
| 组件 | 型号/规格 | 数量 | 备注 |
|---|---|---|---|
| 主控板 | C-3576BQ 核心板 + M4-R2 底板 | 1 | |
| 调试串口线 | USB 转 TTL(3.3V) | 1 | 波特率 1500000 |
| SPI Flash | W25Q128(16MB) | 1 | 或其他 SPI NOR Flash |
| 杜邦线 | 母对母 | 若干 |
2.2 引脚连接
以 M4-R2 底板 40PIN 的 SPI 接口为例:
| 主控板引脚 | 外设引脚 | 功能说明 |
|---|---|---|
| MOSI(40PIN Pin19,GPIO3_A1) | Flash DI | 主出从入 |
| MISO(40PIN Pin21,GPIO3_A2) | Flash DO | 主入从出 |
| SCLK(40PIN Pin23,GPIO3_A0) | Flash CLK | SPI 时钟 |
| CE0(40PIN Pin24,GPIO3_A3) | Flash CS | 片选(低有效) |
| CE1(40PIN Pin26,GPIO2_D7) | Flash CS | 片选(低有效) |
| 3.3V | Flash VCC | 电源 |
| GND(40PIN Pin9) | Flash GND | 共地 |
40PIN 的 SPI 引脚定义(S-01):Pin19 MOSI=GPIO3_A1、Pin21 MISO=GPIO3_A2、Pin23 SCLK=GPIO3_A0、Pin24 CE0=GPIO3_A3、Pin26 CE1=GPIO2_D7。实际操作时应选择未被其他功能占用的 SPI 总线,详细引脚位置见 40PIN 引脚定义。
2.3 硬件确认
# 确认 SPI 总线是否存在
ls /dev/spidev*
# 输出示例:/dev/spidev0.0
# 查看 SPI 控制器信息
cat /sys/class/spi_master/spi0/name
# 输出:rk3x-spi3. 软件准备
3.1 内核配置
确认以下内核配置已启用:
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_ROCKCHIP=y
CONFIG_SPI_SPIDEV=y
CONFIG_OF=y
CONFIG_OF_SPI=y
CONFIG_SPI_ROCKCHIP是 Rockchip SPI 控制器驱动。CONFIG_SPI_SPIDEV提供用户空间访问接口。
3.2 设备树
RK3576 的 SPI 控制器在设备树中定义(以下为 RK 平台通用结构示例):
spi1: spi@fe610000 {
compatible = "rockchip,rk3576-spi", "rockchip,rk3066-spi";
reg = <0x0 0xfe610000 0x0 0x1000>;
clocks = <&cru CLK_SPI1>, <&cru PCLK_SPI1>;
clock-names = "spiclk", "apb_pclk";
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&spi1m1_cs0 &spi1m1_pins>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};以上寄存器基地址、中断号与时钟标识为 RK 平台通用结构示例,具体数值以实际发布的 RK3576 SDK 设备树为准(待板上确认)。
4. 操作步骤
4.1 使用 spidev 测试 SPI
4.1.1 设备树配置 spidev
&spi1 {
status = "okay";
max-freq = <10000000>; // 10MHz
spi-dev@0 {
compatible = "spidev";
reg = <0>;
spi-max-frequency = <10000000>;
};
};4.1.2 读写 SPI 设备
# 查看 SPI 设备
ls /dev/spidev1.*
# 输出:/dev/spidev1.0
# 使用 spi-tools 测试(需安装)
apt-get install spi-tools
# 读取 SPI Flash ID(发送 0x9F 命令)
spi-pipe -d /dev/spidev1.0 -b 8 -r 3 -s 1000000 < /dev/null | xxd4.2 SPI Flash 操作
# 使用 flashrom 读取 SPI Flash
flashrom -p linux_spi:dev=/dev/spidev1.0 -r backup.bin
# 使用 flashrom 写入固件
flashrom -p linux_spi:dev=/dev/spidev1.0 -w firmware.bin
# 使用 mtd-utils 操作 MTD 设备
flash_erase /dev/mtd0 0 0
nandwrite -p /dev/mtd0 firmware.bin4.3 设备树中挂载 SPI 设备
&spi1 {
status = "okay";
max-freq = <50000000>; // 50MHz
spi_flash: flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <50000000>;
m25p,fast-read;
};
};5. 代码详解
5.1 内核中 SPI 驱动的注册
// RK3576 SPI 控制器驱动(简化)
// drivers/spi/spi-rk3x.c
static struct platform_driver rk3x_spi_driver = {
.probe = rk3x_spi_probe,
.remove = rk3x_spi_remove,
.driver = {
.name = "rk3x-spi",
.of_match_table = rk3x_spi_match,
},
};
static const struct of_device_id rk3x_spi_match[] = {
{ .compatible = "rockchip,rk3576-spi" },
{ /* sentinel */ }
};5.2 用户空间 SPI 操作的内核调用链
用户空间 open(/dev/spidev1.0)
→ spidev_open()
→ spi_setup()
→ rk3x_spi_setup()
→ 配置 SPI 模式、时钟、字长
用户空间 write()
→ spidev_write()
→ spi_sync_transfer()
→ rk3x_spi_transfer_one()
→ 设置 SPI 寄存器,发起传输6. 常见问题
6.1 SPI 设备无响应
现象: 读取 SPI Flash ID 返回 0xFF
解决方案:
# 检查 SPI 时钟是否正确配置
cat /sys/kernel/debug/clk/clk_spi1/clk_rate
# 检查 CS 引脚是否正确拉低
cat /sys/kernel/debug/gpio | grep spi检查硬件连接(MOSI/MISO 是否交叉)、CS 片选是否正确、SPI 模式是否匹配。
6.2 SPI 传输数据错误
现象: 读取的数据与预期不符
解决方案:
# 使用逻辑分析仪抓取 SPI 波形
# 确认 CPOL、CPHA 模式是否正确
# 检查字节序(MSB/LSB first)调整 SPI 模式(Mode 0~3),确认字节序设置正确。
6.3 SPI 时钟频率不正确
现象: SPI 实际时钟频率与配置不符
解决方案:
# 查看 SPI 实际时钟频率
cat /sys/kernel/debug/clk/clk_spi1/clk_rateSPI 时钟由 APB 时钟分频得到,检查分频寄存器配置。
