09、SPI内核配置及驱动使用
一、RK3568功能特点
以下是RK3568芯片SPI驱动的主要功能说明,用更通俗的语言描述:
这个SPI接口默认使用摩托罗拉协议标准,支持8位和16位数据传输。用户可以通过软件灵活设置时钟频率,最高传输速度可达50MHz。它提供四种可配置的工作模式,能适配不同设备需求。每个SPI控制器可以连接1到2个外设(通过片选信号区分)。除了常见的主控模式,还支持作为从设备工作的模式。
二、内核软件
2.1、代码路径
C
drivers/spi/spi.c spi驱动框架
drivers/spi/spi-rockchip.c rk spi各接口实现
drivers/spi/spidev.c 创建spi设备节点,用户态使用。
drivers/spi/spi-rockchip-test.c spi测试驱动,需要自己手动添加到Makefile编译
Documentation/spi/spidev_test.c 用户态spi测试工具
1
2
3
4
5
2
3
4
5
2.2、SPI 设备配置 —— RK 芯片作 Master 端
内核配置
C
Device Drivers --->[*] SPI support ---><* Rockchip SPI controller driver
1
DTS
节点配置
C
&spi1 { //引用spi 控制器节点
status = "okay";//assigned-clock-rates = <200000000>; //默认不用配置,SPI 设备工作时钟值,io 时钟由工作时钟分频获取
dma-names = "tx","rx"; //使能DMA模式,通讯长度少于32字节不建议用,置空赋值去掉使能,如"dma-names;";//rx-sample-delay-ns = <10>; //默认不用配置,读采样延时
spi_test@10 {
compatible ="rockchip,spi_test_bus1_cs0"; //与驱动对应的名字
reg = <0;
spi-cpha; //设置 CPHA = 1,不配置则为 0
spi-cpol; //设置 CPOL = 1,不配置则为 0
spi-lsb-first; //IO 先传输 lsb
spi-max-frequency = <24000000; //spi clk输出的时钟频率,不超过50M
status = "okay"; //使能设备节点};};
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 基本关系 SPI的输出时钟(
spi-max-frequency
)是通过内部对工作时钟(spiclk assigned-clock-rates
)进行分频后得到的。 关键规则:工作时钟必须至少是SPI输出时钟的2倍(因为内部至少会分频2次)。 例如:若要让SPI输出50MHz,工作时钟至少要设置为100MHz。 - 配置示例 如果需要50MHz的SPI速率:
- 设置工作时钟(
spiclk assigned-clock-rates
)为100MHz(通过PLL分频得到接近且不超过100MHz的值)。 - 设置
spi-max-frequency
为50MHz。 最终内部会将100MHz二分频到50MHz输出。
- 最低限制 工作时钟(
spiclk assigned-clock-rates
)不能低于24MHz,否则可能引发问题。 - 特殊模式要求(如使用
**spi-cpha**
) 如果需要配置spi-cpha
(一种SPI时序模式):
- 工作时钟(
spiclk assigned-clock-rates
)必须≤6MHz; - SPI输出时钟(
spi-max-frequency
)需在1MHz到3MHz之间。
::: 先确定所需的SPI输出速率(如50MHz)。
将工作时钟设置为它的2倍(如100MHz)。
确保工作时钟≥24MHz,且在特殊模式下满足更严格的限制。 :::
2.3 、SPI 设备配置 —— RK 芯片作 Slave 端
SPI
做 slave
使用的接口和 master
模式一样,都是 spi_read
和 spi_write
。 内核配置
C
Device Drivers --->[*] SPI support --->[*] SPI slave protocol handlers
1
DTS
节点配置
C
&spi1 {
status = "okay";
dma-names = "tx","rx";
spi-slave; //使能 slave 模式
slave { //按照框架要求,SPI slave子节点的命名需以 "slave" 开始
compatible ="rockchip,spi_test_bus1_cs0";
reg = <0;
id = <0;
};
};
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2.4、SPI 设备驱动介绍
设备驱动使用spi
需要调用spi_register_driver
注册spi
设备:
C++
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
static int spi_test_probe(struct spi_device *spi)
{
int ret;
if(!spi)
return -ENOMEM;
spi->bits_per_word= 8;
ret= spi_setup(spi);
if(ret < 0) {
dev_err(&spi->dev,"ERR: fail to setup spi\n");
return-1;
}
return ret;
}
static int spi_test_remove(struct spi_device *spi)
{
printk("%s\n",__func__);
return 0;
}
static const struct of_device_id spi_test_dt_match[]= {
{.compatible = "rockchip,spi_test_bus1_cs0", },
{.compatible = "rockchip,spi_test_bus1_cs1", },
{},
};
MODULE_DEVICE_TABLE(of, spi_test_dt_match);
static struct spi_driver spi_test_driver = {
.driver = {
.name = "spi_test",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(spi_test_dt_match),
},
.probe = spi_test_probe,
.remove = spi_test_remove,
};
static int __init spi_test_init(void)
{
int ret = 0;
ret = spi_register_driver(&spi_test_driver);
return ret;
}
module_init(spi_test_init);
static void __exit spi_test_exit(void)
{
return spi_unregister_driver(&spi_test_driver);
}
module_exit(spi_test_exit);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
对 SPI
读写操作请参考 include/linux/spi/spi.h
,以下简单列出几个
C
static inline int spi_write(struct spi_device *spi,const void *buf, size_t len)static inline int spi_read(struct spi_device *spi,void *buf, size_t len)static inline int spi_write_and_read(structspi_device *spi, const void *tx_buf, void *rx_buf,size_t len)
1
三、常见问题
3.1、SPI 无信号
调试前先确认驱动已启动运行
检查SPI的4个引脚(MOSI/MISO/SCLK/CS)信号设置是否正确
发送数据时:
- 用示波器观察TX数据线是否有正常信号
- 确认时钟线有稳定时钟信号
- 检查片选信号是否能有效拉低
若时钟频率过高,可尝试增强信号强度改善传输质量
判断DMA是否开启:
- 查看串口日志
- 若没有出现"DMA disable"或类似提示,则DMA已成功启用
C
[ 0.457137] Failed to request TX DMA channel
[ 0.457237] Failed to request RX DMA channel
1
2
2
3.2、延迟采样时钟配置方案
在高速SPI通信中,当外设输出信号与控制器采样时钟不同步时,可能导致数据读取失败。此时需要启用RK SPI的"rsd采样延迟"功能来调整采样时机:
延迟配置:
可选参数:0、1、2、3四个档位
每个档位对应1个SPI时钟周期的延迟
例如:200MHz时钟(周期5ns)时:
- 0档 → 0ns延迟
- 1档 → 5ns延迟
- 2档 → 10ns延迟
- 3档 → 15ns延迟
配置规则: 当设置目标延迟值(如12ns)时,系统会自动选择最接近的有效档位:
- 12ns最接近10ns(2档)而非15ns(3档)
- 最终实际采用的延迟值为最近的有效档位对应值
简单来说:通过这个功能,可以在4个固定时间点中选择最适合的采样时机,确保高速通信时能准确捕获数据。