HALF DUPLEX SPI
SPI Introdution
SPI, Serial Peripheral Interface, 即串行设备接口,微控制器和外围IC(如传感器、ADC、DAC、移位寄存器、SRAM等)之间使用最广泛的接口之一。
SPI是一种同步的主从式接口,支持全部通信制式(单工、半双工、全双工)。与I2C的 多主多从 模式不同,SPI协议为 一主多从 模式。SPI所消耗的接口数也有所提升。
接线
SPI 的物理线支持 三种类型:
- 片选线(NCS / CS / SS),某些数据手册会将
片选引脚 称为
NSS
/NCS
/SEL
(Select) /CS
(Chip Select) /STE
(Slaver Transmit Enable) - 时钟线(CLK / SCK)
- 数据线(DA 或 MOSI 和 MISO )
需要注意的是,SPI的通信线有太多的名称,需要自行对照芯片手册进行查询,避免混淆。下方为标准全双工四线SPI的通信接线示意图
SPI 通过对硬件资源的使用修改(禁用片选、禁 / 复用数据线)可以达到
全双工 或 半双工 通信的目的。标准SPI为
四线SPI (CS / CLK / MOSI / MISO);最低支持2根数据引脚(仅保留 CLK /
DA,其中DA为分时复用数据线 )来达到半双工通信的目的,可以增加一 / 多根
CS
来达到拓展SPI从设备片选的目的;也可以利用四根独立的半双工数据线,来达到
标准四线SPI 四倍通信能力 的 六线SPI(一般被称为
Quad-IO SPI
)。
分类
各芯片厂商对SPI的通信协议好像并没有一个较为正式的名称,但都可以从通信制式的类型进行区分,并不能仅从 x线SPI 的数量来判断SPI通信协议的类型。
较为推荐的称呼方式是:线数 + 有无片选 +通信制式。比如:
- 两线无片选半双工SPI,即 CLK 和 SDIO 两线,SDIO 支持分时双工。
- 三线无片选半双工SPI,即 CLK 和 两根 SDIO,两根SDIO 都是分时双工。
- 三线有片选半双工SPI,即 CLK 、SDIO 和 CS,SDIO 支持分时双工。
- 三线无片选全双工SPI,即 CLK、MOSI 和 MISO。
- 四线有片选全双工SPI,即 CLK、MOSI、MISO 和 CS。
- ......
例如,据STM32L476RG芯片手册《RM0351》第1450页所示,SPI外设可以被配置为以下三种模式,即 三线全双工,两线半双工 和 两线单工。
- Full-duplex synchronous transfers on three lines
- Half-duplex synchronous transfer on two lines (with bidirectional data line)
- Simplex synchronous transfers on two lines (with unidirectional data line)
SDR 和 DDR 模式
扩展的 SPI 协议还增加了 SDR 模式(单倍速率 Single Data Rate)和 DDR 模式(双倍 速率 Double Data Rate)。例如在标准 SPI 协议的 SDR 模式下,只在 SCK 的单边沿进行数据传输,即一个 SCK 时钟只传输一位数据;而在它的 DDR 模式下,会在 SCK 的上升沿和下降沿都进行数据传输,即一个 SCK 时钟能传输两位数据,传输速率提高一倍。
数据传输
下以四线有片选全双工SPI为例进行说明。
要开始SPI通信,主机必须发送时钟信号,并通过使能CS信号选择从机。
片选 通常 是 低电平有效(active-low) 信号。
主机须在 CS
信号上发送逻辑 0
以选择从机。主机和从机可以分别通过 MOSI 和 MISO
引脚同时发送数据。在SPI通信期间,数据的发送(串行移出到MOSI/SDO总线上)和接收(采样或读入总线(MISO/SDI)上的数据)同时进行。串行时钟沿同步数据的移位和采样。
SPI接口允许用户灵活选择时钟的 上升沿 或 下降沿 来采样和/或移位数据。
需要注意:SPI接口传输的 数据位数 仍需查阅器件数据手册。
时钟极性和时钟相位
在SPI中,主机可以选择 时钟极性(Clock Polarity,CPOL)和 时钟相位(Clock Phase,CPHA)。
在空闲状态期间,CPOL 控制 时钟极性。空闲状态是指传输开始时CS为高电平且在向低电平转变的期间,以及传输结束时CS为低电平且在向高电平转变的期间。
CPHA 控制 时钟相位。根据CPHA位的状态,使用时钟上升沿或下降沿来采样和/或移位数据。主机必须 根据从机的要求选择时钟极性和时钟相位。根据CPOL和CPHA位的选择,有四种SPI模式可用,如下表:
SPI 模式 | CPOL | CPHA | 空闲状态下的时钟极性 | 用于采样和/或移位数据的时钟相应 |
---|---|---|---|---|
0 | 0 | 0 | 逻辑低电平 | 数据在上升沿采样,在下降沿移出 |
1 | 0 | 1 | 逻辑低电平 | 数据在下降沿采样,在上升沿移出 |
2 | 1 | 1 | 逻辑低电平 | 数据在下降沿采样,在上升沿移出 |
3 | 1 | 0 | 逻辑低电平 | 数据在上升沿采样,在下降沿移出 |
下图为TI公司F280049芯片的SPI时钟模式:
下图为ADI公司ADSP21479芯片的SPI时钟模式:
后述 图2 至 图5 显示了四种SPI模式下的通信示例。
在这些示例中,数据显示在MOSI和MISO线上。传输的开始和结束用绿色虚线表示,采样边沿用橙色虚线表示,移位边沿用蓝色虚线表示。请注意,这些图形仅供参考。要成功进行SPI通信,用户须参阅产品数据手册并确保满足器件的时序规格。
图3给出了SPI模式1的时序图。在此模式下,时钟极性为0,表示时钟信号的空闲状态为低电平。此模式下的时钟相位为1,表示数据在下降沿采样(由橙色虚线显示),并且数据在时钟信号的上升沿移出(由蓝色虚线显示)。
图4给出了SPI模式2的时序图。在此模式下,时钟极性为1,表示时钟信号的空闲状态为高电平。此模式下的时钟相位为1,表示数据在下降沿采样(由橙色虚线显示),并且数据在时钟信号的上升沿移出(由蓝色虚线显示)。
图5给出了SPI模式3的时序图。在此模式下,时钟极性为1,表示时钟信号的空闲状态为高电平。此模式下的时钟相位为0,表示数据在上升沿采样(由橙色虚线显示),并且数据在时钟信号的下降沿移出(由蓝色虚线显示)。
多从机配置
多个从机可与单个SPI主机一起使用。从机可以采用常规模式连接,或采用菊花链模式连接。
常规SPI模式
在常规模式下,主机需要为每个从机提供单独的片选信号。一旦主机使能(拉低)片选信号,MOSI/MISO线上的时钟和数据便可用于所选的从机。如果使能多个片选信号,则MISO线上的数据会被破坏,因为主机无法识别哪个从机正在传输数据。
从图6可以看出,随着从机数量的增加,来自主机的片选线的数量也增加。这会快速增加主机需要提供的输入和输出数量,并限制可以使用的从机数量。可以使用其他技术来增加常规模式下的从机数量,例如使用多路复用器产生片选信号。
菊花链模式
在菊花链模式下,所有从机的片选信号连接在一起,数据从一个从机传播到下一个从机。在此配置中,所有从机同时接收同一SPI时钟。来自主机的数据直接送到第一个从机,该从机将数据提供给下一个从机,依此类推。
使用该方法时,由于数据是从一个从机传播到下一个从机,所以传输数据所需的时钟周期数与菊花链中的从机位置成比例(成比例倍增)。
例如在图7所示的8位系统中,为使第3个从机能够获得数据,需要24个时钟脉冲,而常规SPI模式下只需8个时钟脉冲。图8显示了时钟周期和通过菊花链的数据传播。并非所有SPI器件都支持菊花链模式。请参阅产品数据手册以确认菊花链是否可用。
HALF DUPLEX SPI
半双工通信可以是 两线SPI 或 三线SPI,仅仅是有无片选线的差异而已。
PIN DEFINITION
NCS: SPI控制读写使能信号;使用时需要被拉低,否则SDIO会处在 HIGH-Z 态,而SCLK信号也会被无视。也可以被用于在通信错误发生时重置SPI 通信。两线SPI不需要这根线,但个别芯片可能需要这个引脚接地(不能悬空),具体看芯片手册。
SDIO:
SPI的数据读写端口;半双工读写。只有在“从被控设备读出数据”的情况下,SDIO
才会由被控制设备控制。
SCLK: SPI接口时钟;总是由主控制器生成和控制。
TRANSMISSION PROTOCOL
跟其他通信类似,SPI 的 SDIO 需要在 时钟低电平时 进行电平跳变。
半双工SPI读写操作都包含两个字(byte),第一个字包含1 bit的 数据方向(或称 控制位) 和 7 bit的 地址,第二个字包含 数据。
关于数据方向/控制位
通常定义是,当需要写入数据时,控制位写 1
。当需要读出数据时,控制位写 0
。
但不一定所有支持半双工SPI的通信控制位都是在MSB,有可能是在 LSB 。
如,下方右侧 SL8541E 的安卓平台主控,支持半双工SPI,但是其控制位就在地址字符的LSB上。
写操作
主控制器在SCLK下降沿时改变 SDIO的电平,被控设备在SCLK上升沿时读取SDIO的电平。
读取操作
SDIO会在SCLK下降沿时修改,主控制器需要在SCLK的上升沿时读取SDIO的电平信息。
注意:发送完地址字 之后需要延长半个周期的时钟低电平。
Timing Serial
因为芯片自带的时序图有些许错误,所以就自己画了一个。
时序图绘图工具(开源):WAVEDROM
1 | {signal: [ |
DEBUG RECORDS
下面这个时序图错误的坑是真的大,调了好就才折腾明白。
某些芯片下,SDIO 的闲置状态可能不能是 Hi-Z
态。
时序图错误
内部调试时发现,SDIO在读取数据前后必须是
输出模式,最好 强制拉高,而不是
Hi-Z
态。
读写单个字符
以下这两个函数中的 for()
使用了 MSB
发送数据,最好不要自作聪明将 i
的数据类型改为
uint8_t
或其他非负型数据,以下这种循环写法会让程序陷入死循环的。
另外,SPI 和 I2C
不一样,读取和写入的时序有较大差异。比如,I2C会在时钟高电平时读取电平数据,在低电平时改写电平数据。而
CPOL = 1, CPHA = 1
的SPI 会在上升沿时读取和写入数据,而
CPOL = 1, CPHA = 0
的 SPI会在下降沿时读取和写入数据。
主从设备必须将SPI特性保持一致,才能确保读写的稳定性。
1 | /** |
STM32 SPI 配置
由外设SPI控制的 SCLK
/ SDIO
波形与手动控制的 SNCS
波形之间的矛盾。
write_register(0x09, 0xA5)
,对应应该输出数据为
0x89, 0xA5
,而 SNCS
在两处地方产生了错误的波形。
SOURCE CODE
以下是适用于 STM32 平台的 GPIO-模拟 半双工SPI 代码,利用 空指令进行延时控制,实现半双工(三线/两线)SPI 的通信。
需要软件适配以下几个功能:
- 控制精细度在 \([10^{-9}s:10^{-6}s]\) 之间的
精准延时(如果做不到,通信速率就上不去
1MHz
)。 - 控制引脚电平的宏定义(可选)。
- 设置数据接口输出 和 设置数据接口输入 的代码。
- 拉高电平 和 拉低电平
的代码,这里需要根据从设备特性来控制时钟的相位,即
CPHA = 1
或者CPHA = 0
。 - 对照着 正确的时序图 写一遍
读单字符 和 写单字符
的代码,这里需要根据从设备特性来控制时钟的相位,即
CPHA = 1
或者CPHA = 0
。 - 对照着 正确的时序图 写一遍
写寄存器 和 读寄存器
的代码,这里需要根据从设备特性来控制时钟的极性,决定时钟在闲时为高电平还是低电平,即
CPOL = 1
或者CPOL = 0
。
注意:都是按顺序来完成的,所有后面的功能都需要依托于前面的功能来实现。而且,需要用示波器(有条件)进行测量以校准通信速率,并使用正确的时序图进行编码(如果是错误的,浪费时间,尽快跟厂家确认)。
代码部分可以参考 gmi 中对 spi 的定义和使用。