SPI通信简介
SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线。
四根通信线:SCK、MOSI、MISO、SS。
SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select)。
SCK又称SCLK、CLK、CK。MOSI和MISO又称DO和DI。SS(片选)又称NSS、CS。
同步,全双工 。同步时序肯定就有时钟线,所以SCK这个引脚是来提供时钟信号的,数据位的输出和输入都是在SCK的上升沿或下降沿进行的。 全双工是指数据发送和数据接收单独各占一条线,发送用发送的线路,接收用接收的线路,两者互不影响。
MOSI线:主机输出,从机输入。如果主机接在这条线上,就是MO,主机输出。如果是从机接在这条线上,就是SI,从机输入。
MISO线:主机输入,从机接收。如果主机接在这条线上,就是MI,主机输出。如果是从机接在这条线上,就是SO,从机输入。
SS线:从机选择线,有几个从机就开几条SS线,所有从机,一人一根。
总线挂载多设备(一主多从)。
SPI没有应答机制的设计,发送数据就发送,接收数据就接收,至于对面是不是存在,SPI是不管的。

SPI硬件电路
所有SPI设备的SCK、MOSI、MISO分别连在一起。
主机另外引出多条SS控制线,分别接到各从机的SS引脚。
输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入。

主机的SS线都是输出,从机的SS线都是输入。SS线是低电平有效,主机想指定谁,就把对应的SS输出线置低电平有效就行了。
移位示意图

我们看图可以知道,SPI的主机和从机的移位寄存器都有一个时钟输入端。
SPI一般是高位先行,每来一个时钟,移位寄存器就会向左移动。
移位器的时钟源,是由主机提供的,这里叫做波特率发生器。它产生的时钟驱动主机的移位寄存器进行移位,同时,这个时钟也通过SCK引脚进行输出,接到从机的移位寄存器里 。
这两个移位寄存器就可以实现主机和从机的一个字节的数据交换,SPI运行的过程这样,SPI的数据收发,都是基于字节交换这个基本单元来进行的,当主机需要发送一个字节,并且同时需要接收一个和字节时,就可以执行字节交换的时序。
那如果只想要发送,不想要接收怎么办呢?
很简单,如果你只想要发送,不想要接收,也是按照这个逻辑,只不过从机发送来的数据你不用看就行了;
同理,如果你只想要接收,不想要发送,那就给从机随便发送个数据,把移位寄存器的数据替换过来就行了,同样,从机也不会看你随便发送的这个数据(一般是0X00或者0XFF)。
SPI时序基本单元
起始条件:SS从高电平切换到低电平。
终止条件:SS从低电平切换到高电平。

数据传输的基本单元:基本单元是建立在刚才的移位示意图上。
并且这个基本单元,什么时候开始移位?是上升沿移位还是下降沿移位?SPI并没有限定死,给了我们可以配置的选择,这样我们就可以兼容更多的芯片。
SPI有两个可以配置的位,分别是:CPOL(Clock Polarity)时钟极性、CPHA(Clock Phase)时钟相位。每一位可以配置为1或0,总共组合起来就有4种模式,分别是模式0、1、2、3这四种模式。模式虽然多,但是功能都是一样的。在实际使用的时候,我们学习一种就可以了。
模式1
模式1是和我们的移位示意图是对应的,这个时序的基本功能是交换一个字节。
CPOL=0:空闲状态时,SCK为低电平;
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据。
MISO是主机输入,从机输出;因为有多个从机输出是连在了同一条线上,如果同时开启输出,会造成冲突,为了防止冲突,在SS未被选中时,从机的MISO引脚必须关断输出,即配置输出为高阻态。

模式0(?)
模式0和模式1的区别,就是模式0的数据移出移入的时机会提前半个时钟,也就是相位提前了。
CPOL=0:空闲状态时,SCK为低电平。
CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据。
相较于模式1,模式0在第一个边沿就要移入数据,但数据总得先移出再移入,所以提前了半个时钟用来移出数据。
在传输一个字节的过程中,SCK最终会在第8个上升沿时,B0位(最低位)移入完成,整个字节交换完成。之后SCK还有一个下降沿,如果主机只需要交换一个字节就结束,那在这个下降沿时,MOSI可以置回默认电平,或者不去管它,MISO也会变化一次,这变化的一次实际上就是下一个字节的B7位(最高位),因为相位提前了,所以下一个字节的B7会露头,如果不需要的话,SS上升沿之后,从机MISO置回高阻态,这时交换一个字节就结束。
模式2
模式2和模式0的区别就是,模式2的SCK的极性取反一下。
CPOL=1:空闲状态时,SCK为高电平。
CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据。

模式3
模式3和模式1的区别就是,模式3的SCK的极性取反一下。
CPOL=1:空闲状态时,SCK为高电平。
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据。

SPI指令
在SPI中,通常采用的是指令码加读写数据的模型:
SPI起始后,第一个交换发送给从机的数据,一般叫做指令码,在从机中,对应的会定义一个指令集,当我们需要发送什么指令时,就可以在起始后第一个字节,发送指令集里面的数据,这样就能指导从机完成相应的功能了。不同的指令,可以有不同的数据个数,有的指令只需要一个字节的指令码就可以完成,比如W25Q64的写使能、写失能等指令;而有的指令,后面就需要再跟要读写的数据,比如W25Q64的写数据、读数据等。
下面使用W25Q64进行举例:
发送指令
这里使用的是模式0。
向SS指定的设备,发送指令(0x06)写使能。

指定地址写指令
向SS指定的设备,发送写指令(0x02), 随后在指定地址(Address[23:0])下,写入指定数据(Data)。

因为W25Q64芯片有8M字节的存储空间,一个字节的8位地址肯定不够,所以这里的地址是24位的,分3个字节传输。
指定地址读指令
向SS指定的设备,发送读指令(0x03), 随后在指定地址(Address[23:0])下,读取从机数据(Data)。
