fireflyAIO-3399J主板SPI使用简介

spi 使用
spi是一种高速的,全双工,同步串行通信接口,用于连接微控制器、传感器、存储设备等。 由于aio-3399j spi没有引出来,而且已经被用到其他功能上,所以这章以firefly-rk3399作为例子。 firefly-rk3399 开发板提供了 spi1 (单片选)接口,具体位置如下图:
spi工作方式
spi以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,分别是:
cs 片选信号 sclk 时钟信号 mosi 主设备数据输出、从设备数据输入 miso 主设备数据输入,从设备数据输出
linux内核用cpol和cpha的组合来表示当前spi的四种工作模式:
cpol=0,cpha=0 spi_mode_0 cpol=0,cpha=1 spi_mode_1 cpol=1,cpha=0 spi_mode_2 cpol=1,cpha=1 spi_mode_3
cpol:表示时钟信号的初始电平的状态,0为低电平,1为高电平。cpha:表示在哪个时钟沿采样,0为第一个时钟沿采样,1为第二个时钟沿采样。spi的四种工作模式波形图如下:
驱动编写
下面以 w25q128fv flash模块为例简单介绍spi驱动的编写。
硬件连接
firefly-rk3399 与 w25q128fv 硬件连接如下表:
编写makefile/kconfig
在kernel/drivers/spi/kconfig中添加对应的驱动文件配置:
config spi_firefly tristate firefly spi demo support default y help select this option if your firefly board needs to run spi demo.
在kernel/drivers/spi/makefile中添加对应的驱动文件名:
obj-$(config_spi_firefly) += spi-firefly-demo.o
config中选中所添加的驱动文件,如:
│ symbol: spi_firefly [=y] │ type : tristate │ prompt: firefly spi demo support │ location: │ -> device drivers │ -> spi support (spi [=y]) │ defined at drivers/spi/kconfig:704 │ depends on: spi [=y] && spi_master [=y]
配置dts节点
在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi中添加spi驱动结点描述,如下所示:
/* firefly spi demo */ &spi1 { spi_demo: spi-demo@00{ status = okay; compatible = firefly,rk3399-spi; reg = ; spi-max-frequency = ; /* rk3399 driver support spi_cpol | spi_cpha | spi_cs_high */ //spi-cpha; /* spi mode: cpha=1 */ //spi-cpol; /* spi mode: cpol=1 */ //spi-cs-high; }; }; &spidev0 { status = disabled; };
status:如果要启用spi,则设为okay,如不启用,设为disable。
spi-demo@00:由于本例子使用cs0,故此处设为00,如果使用cs1,则设为01。
compatible:这里的属性必须与驱动中的结构体:of_device_id 中的成员compatible 保持一致。
reg:此处与spi-demo@00保持一致,本例设为:0x00。
spi-max-frequency:此处设置spi使用的最高频率。firefly-rk3399最高支持48000000。
spi-cpha,spi-cpol:spi的工作模式在此设置,本例所用的模块spi工作模式为spi_mode_0或者spi_mode_3,这里我们选用spi_mode_0,如果使用spi_mode_3,spi_demo中打开spi-cpha和spi-cpol即可。
spidev0: 由于spi_demo与spidev0使用一样的硬件资源,需要把spidev0关掉才能打开spi_demo
定义spi驱动
在内核源码目录kernel/drivers/spi/中创建新的驱动文件,如:spi-firefly-demo.c 在定义 spi 驱动之前,用户首先要定义变量 of_device_id 。 of_device_id 用于在驱动中调用dts文件中定义的设备信息,其定义如下所示:
static struct of_device_id firefly_match_table[] = {{ .compatible = firefly,rk3399-spi,},{},};
此处的compatible与dts文件中的保持一致。
spi_driver定义如下所示:
static struct spi_driver firefly_spi_driver = { .driver = { .name = firefly-spi, .owner = this_module, .of_match_table = firefly_match_table,}, .probe = firefly_spi_probe, };
注册spi设备
在初始化函数static int __init spidev_init(void)中向内核注册spi驱动: spi_register_driver(&firefly_spi_driver);
如果内核启动时匹配成功,则spi核心会配置spi的参数(mode、speed等),并调用firefly_spi_probe。
读写 spi 数据
firefly_spi_probe中使用了两种接口操作读取w25q128fv的id: firefly_spi_read_w25x_id_0接口直接使用了spi_transfer和spi_message来传送数据。 firefly_spi_read_w25x_id_1接口则使用spi接口spi_write_then_read来读写数据。
成功后会打印:
root@rk3399_firefly_box:/ # dmesg | grep firefly-spi [ 1.006235] firefly-spi spi0.0: firefly spi demo program [ 1.006246] firefly-spi spi0.0: firefly_spi_probe: setup mode 0, 8 bits/w, 48000000 hz max [ 1.006298] firefly-spi spi0.0: firefly_spi_read_w25x_id_0: id = ef 40 18 00 00 [ 1.006361] firefly-spi spi0.0: firefly_spi_read_w25x_id_1: id = ef 40 18 00 00
打开spi demo
spi-firefly-demo默认没有打开,如果需要的话可以使用以下补丁打开demo驱动:
--- a/kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi +++ b/kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi @@ -64,7 +64,7 @@ /* firefly spi demo */ &spi1 {spi_demo: spi-demo@00{ - status = disabled; + status = okay; compatible = firefly,rk3399-spi; reg = ; spi-max-frequency = ; @@ -76,6 +76,6 @@ }; &spidev0 { - status = okay; + status = disabled; };
常用spi接口
下面是常用的 spi api 定义:
void spi_message_init(struct spi_message *m); void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m); int spi_sync(struct spi_device *spi, struct spi_message *message) ; int spi_write(struct spi_device *spi, const void *buf, size_t len); int spi_read(struct spi_device *spi, void *buf, size_t len); ssize_t spi_w8r8(struct spi_device *spi, u8 cmd); ssize_t spi_w8r16(struct spi_device *spi, u8 cmd); ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd); int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, void *rxbuf, unsigned n_rx);
接口使用
linux提供了一个功能有限的spi用户接口,如果不需要用到irq或者其他内核驱动接口,可以考虑使用接口spidev编写用户层程序控制spi设备。 在 firefly-rk3399 开发板中对应的路径为: /dev/spidev0.0
spidev对应的驱动代码: kernel/drivers/spi/spidev.c
内核config需要选上spi_spidev:
│ symbol: spi_spidev [=y] │ type : tristate │ prompt: user mode spi device driver support │ location: │ -> device drivers │ -> spi support (spi [=y]) │ defined at drivers/spi/kconfig:684 │ depends on: spi [=y] && spi_master [=y]
dts配置如下:
&spi1 { status = okay; max-freq = ; spidev@00 { compatible = linux,spidev; reg = ; spi-max-frequency = ; }; };
详细使用说明请参考文档 spidev 。
faqs
q1: spi数据传送异常
a1: 确保 spi 4个引脚的 iomux 配置正确, 确认 tx 送数据时,tx 引脚有正常的波形,clk 频率正确,cs 信号有拉低,mode 与设备匹配。

STM32:SPI总线、W25Q64(FLASH)的详细介绍
物联网卡在物联网应用中有着什么样的作用?
通过无线传感贴片能够追踪早产儿的状态
德国车企一直在沉睡,必将付出血的代价
享受音乐的每个细节 森海塞尔全新IE 300入耳式耳机
fireflyAIO-3399J主板SPI使用简介
小米6X评测 接棒性价比线上的性价比杀入线下
贞光科技 | 一文了解内存芯片的发展史
如何解决CAN总线中报文传输受限
Apache Flink 进阶(八):详解 Metrics 原理与实战
电力电子业突破技术瓶颈任重道远
区块链游戏工作室正在推动区块链游戏领域的创新
IC芯片型号的那些后缀怎么看?
联想数博会展示:显示了其对大数据应用的前瞻性布局
小米“米家”VS海尔U+ 谁将称霸智能家居市场?
明星展会首次入驻 Automotive World China 预展8月30日盛大开幕
基于STM32单片机的水稻自动灌溉系统设计案例
基于741运放的12W放大器电路图
AOI和AMR成为制造业发展的推动力
哪款蓝牙耳机的音质好?音质好的蓝牙耳机排行榜