GitHub: SPI
Email: BuddyZhang1 buddy.zhang@aliyun.com
目录
-
SPI 原理
-
Uboot 中源码或工具访问 SPI
-
Kernel 中源码访问 SPI
-
用户空间中源码或工具访问 SPI
-
SPI 硬件信号测试
-
附录
SPI 原理
SPI 是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口,
是 Motorola 首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROM,
FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI 是一种
高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管
脚,同时为 PCB 的布局上节省空间,提供方便。
SPI 的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从
设备,需要 4 根线,事实上 3 根也可以。也是所有基于 SPI 的设备共有的,它们是
SDI (数据输入),SDO (数据输出),SCLK (时钟),CS (片选)
-
MOSI(SDO):主器件数据输出,从器件数据输入。
-
MISO(SDI):主器件数据输入,从器件数据输出。
-
SCLK :时钟信号,由主器件产生。
-
CS:从器件使能信号,由主器件控制。
其中 CS 是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高
电位或低电位),对此芯片的操作才有效,这就允许在同一总线上连接多个 SPI 设备成
为可能。需要注意的是,在具体的应用中,当一条 SPI 总线上连接有多个设备时,SPI
本身的 CS 有可能被其他的 GPIO 脚代替,即每个设备的 CS 脚被连接到处理器端不同的
GPIO,通过操作不同的 GPIO 口来控制具体的需要操作的 SPI 设备,减少各个 SPI 设
备间的干扰。
SPI 协议
SPI 是串行通讯协议,也就是说数据是一位一位从 MSB 或者 LSB 开始传输的,这就是
SCK 时钟线存在的原因,由 SCK 提供时钟脉冲,MISO、MOSI 则基于此脉冲完成数据传
输。 SPI 支持 4-32bits 的串行数据传输,支持 MSB 和 LSB,每次数据传输时当从设
备的大小端发生变化时需要重新设置 SPI Master 的大小端。
SPI 时钟模式
SPI 总线有四种工作模式,其中使用的最为广泛的是 SPI0 和 SPI3 方式(实线表示)
四种工作方式时序分别为:
时序详解
- CPOL:时钟极性选择,为 0 时 SPI 总线空闲为低电平,为 1 时 SPI 总线空闲为
高电平
- CPHA:时钟相位选择,为 0 时在 SCK 第一个跳变沿采样,为 1 时在 SCK 第二个
跳变沿采样
工作方式 1
当 CPHA=0、CPOL=0 时SPI总线工作在方式1。MISO引脚上的数据在第一个SPSCK沿跳变之
前已经上线了,而为了保证正确传输,MOSI引脚的MSB位必须与SPSCK的第一个边沿同步,
在SPI传输过程中,首先将数据上线,然后在同步时钟信号的上升沿时,SPI的接收方捕捉
位信号,在时钟信号的一个周期结束时(下降沿),下一位数据信号上线,再重复上述过
程,直到一个字节的8位信号传输结束。
工作方式 2
当 CPHA=0、CPOL=1 时SPI总线工作在方式2。与前者唯一不同之处只是在同步时钟信号的
下降沿时捕捉位信号,上升沿时下一位数据上线。
工作方式 3
当 CPHA=1、CPOL=0 时 SPI 总线工作在方式3。MISO引脚和MOSI引脚上的数据的MSB位必
须与SPSCK的第一个边沿同步,在SPI传输过程中,在同步时钟信号周期开始时(上升沿)
数据上线,然后在同步时钟信号的下降沿时,SPI的接收方捕捉位信号,在时钟信号的一
个周期结束时(上升沿),下一位数据信号上线,再重复上述过程,直到一个字节的8位
信号传输结束。
工作方式 4
当CPHA=1、CPOL=1时SPI总线工作在方式4。与前者唯一不同之处只是在同步时钟信号的上
升沿时捕捉位信号,下降沿时下一位数据上线。
Uboot 中访问 SPI
开发者在 Uboot 阶段可以通过两种方式访问 SPI 从设备。分别是:
-
工具访问 SPI
-
源码访问 SPI
工具访问 SPI
在 Uboot 命令行模式下,系统提供了 sf 工具来操作 SPI-Flash。通过这个工具可以进
行 SPI-Flash 的读,写,擦除,和更新操作。工具的使用方法如下:
初始化 SPI-Flash
sf probe 命令用于初始化 SPI-Flash 控制器,使用模式如下:
例如,探测并初始化系统可用的 SPI-Flash:
SPI-Flash 读
sf read 命令用于从 SPI-Flash 的特定位置上,读一定长度的数据到内存指定位置
上。使用格式如下:
例如,从 SPI-Flash 0x100 的位置上,读取 0x2000 个字节到内存的 0x40000 位置上:
SPI-Flash 写
sf write 命令用于从内存指定位置,写一定长度的数据到 SPI-Flash 的指定位置
上,使用格式如下:
例如,从内存 0x40000 处,写 0x10 字节到 SPI-Flash 0x3F00000 位置上:
SPI-Flash 擦除
sf erase 命令用于擦除 SPI-Flash 上一段内容,使用格式如下:
例如,擦除 SPI-Flash 0x3F00000 开始处,长度为 0x100000 字节的数据
SPI-Fash 更新
sf update 命令用于更新 SPI-Flash 上指定区域内的数据,对比数据在内存的指定
位置上,使用模式如下:
例如,将内核 0x400 处 0x10 个字节更新到 SPI-Flash 0x3F00000 开始的地址:
源码访问 SPI
开发者也可以通过源码在 Uboot 中访问 SPI,可以参考如下代码:
Kernel 中访问 SPI
内核中要能访问 SPI,需要准备以下几个内容
-
SPI 设备驱动
-
SPI 设备在 DTS 中描述
-
SPI 相关宏
SPI 设备驱动
SPI 设备驱动,开发者可以参考如下:
Makefile
SPI 驱动可以加载到内核也可以外部编译,编译命令如下:
SPI 设备在 DTS 中的描述
准备好驱动之后,接下来需要在 DTS 中添加 SPI 设备的描述。开发者可以参考如下:
SPI 相关的宏
为了能在系统中运行 SPI 设备驱动,请确保内核已经打开如下宏:
用户空间访问 SPI
用户空间也可以通过两种方式访问 SPI,分别如下:
-
使用工具访问 SPI
-
用户程序访问 SPI
使用工具访问 SPI
Linux 用户空间有多种 SPI 工具,这里介绍 spi-tools, 这个工具可以通过 busybox 提
供或直接源码编译使用。具体使用步骤如下:
使用格式:
例如:
详细步骤,请查看 github:
https://github.com/BiscuitOS/HardStack/blob/master/bus/spi/user/README.md
源码访问 SPI
通过源码在用户空间访问 SPI,开发者可以参考如下代码:
SPI 硬件波形测试
SPI 读写协议
SPI 读波形图
SPI 读实测波形图
SPI 写波形图
SPI 实际测试波形图
附录
Using SPI with Linux
Serial Peripheral Interface
BiscuitOS Home
BiscuitOS Driver
BiscuitOS Kernel Build
Linux Kernel
Bootlin: Elixir Cross Referencer
赞赏一下吧 🙂