1 SPI通信
SPI(Serial Peripheral Interface,串行外设接口)是由Motorola公司开发的一种通用数据总线
四根通信线:SCK(Serial Clock,串行时钟)、MOSI(Master Output Slave Input,主机输出从机输入)、MISO(Master Input Slave Output,主机输入从机输出)、SS(Slave Select,从机选择)
同步,全双工
MOSI接到主机上就是输出,接到从机上就是输入;
MISO接到主机上就是输入,接到从机上就是输出。
支持总线挂载多设备(仅支持一主多从)
逻辑是:在起始条件后,主机必须先发送一个字节进行寻址,用来指定我要跟哪个从机进行通信(I2C这里涉及分配地址和寻址的问题),SPI直接使用一条通信线选择和哪个从机进行通信(SS,从机选择,不止一条)
SPI没有应答机制
W25Q64(Flash存储器)、OLED、2.4G无线通信模块(NRF2401)、SD卡
1.1 硬件电路
所有SPI设备的SCK、MOSI、MISO分别连在一起
主机另外引出多条SS控制线,分别接到各从机的SS引脚
输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入
推挽输出的高低电平均有很强的驱动能力,这将使得SPI引脚信号的下降沿非常迅速,上升沿也非常迅速。当从机的SS引脚为高电平时,也就是从机没有被选中时,它的MISO引脚,必须切换为高阻态(相当于断开,不输出任何电平),防止一条线有多个输出,产生冲突。
图中清晰明了
细节:
(1)主机的时钟线SCK是输出,从机的SCK时钟线是输入,主机与从机时钟同步;
(2)SS高电平不选择从机,低电平才选择从机。同一时刻主机只能选择一个从机。
1.1.1 移位示意图
左边是SPI主机,里面有8位的移位寄存器,右边是SPI从机,里面也有8位移位寄存器。这里移位寄存器有一个时钟输入端,因为SPI一般都是高位先行,所以每来一个时钟,移位寄存器就会向左进行移位,从机中的移位寄存器也是如此。移位寄存器的时钟源是由主机提供的,这里叫做波特率发生器,它产生的时钟驱动主机的移位寄存器进行移位,同时这个时钟也通过SCK时钟线进行输出接到从机的移位寄存器里。之后上面移位寄存器的接法是主机移位寄存器左边移出去的数据,通过MOSI引脚输入到从机移位寄存器的右边,从机移位寄存器左边移出去的数据通过MISO引脚输入到主机移位寄存器的右边。
工作流程:规定波特率时钟的上升沿,所有移位寄存器向左移动一位,移出去的位放在引脚上;波特率发生器时钟的下降沿引脚上的位采样输入到移位寄存器的最低位。
假设主机有1010 1010数据需要发送到从机,同时从机有0101 0101数据需要发送到主机。先驱动时钟,先产生一个上升沿,这时所有位都会向左移动一位。此时MOSI的数据是1,所以MOSI的电平是高电平;MOSI的数据是0,所以MISO的电平是低电平。如图所示。
之后时钟继续运行,上升沿之后下一个边沿就是下降沿,在下降沿的时候,主机和从机都会进行数据采样输入,如图所示。这是第一个时钟结束后的现象。
之后以此类推,8次后完成数据的发送和接收。SPI通信的基础是交换一个字节。
只想接收或者发送,不用管另一方即可。
1.1.2 SPI时序基本单元
(1)起始条件:SS从高电平切换到低电平
(2)终止条件:SS从低电平切换到高电平
从机的选中过程中,SS始终保持在低电平。
(3)交换一个字节(模式1)
CPOL:clock polarity时钟极性
CPHA:clock phase,时钟相位
CPOL=0:空闲状态时,SCK为低电平
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据(数据采样)
SS从机选择,通信开始前是高电平,在通信过程中SS保持低电平,通信结束,SS恢复高电平。
在SS高电平时,MISO(主机输入,从机输出)用中间的一条线表示高阻态,SS下降沿之后,从机的MISO被允许开始输出;SS上升沿之后,从机的MISO必须置会高组态。
SCK的第一个边沿是上升沿,主机和从机同时移出数据,主机通过MOSI移出最高位,此时MOSI的电平就表示主机要发送的数据B7;从机通过MISO移出最高位,此时MISO表示从机要发送数据的B7;然后时钟运行,产生下降沿,此时主机和从机同时移入数据,也就是进行数据采样。这里主机移出的B7进入从机移位寄存器的最低位;从机移出的B7进入主机移位寄存器的最低位,这样一个脉冲产生完毕,一个数据位传输完毕。接下来以此类推。
(4)交换一个字节(模式0)
CPOL=0:空闲状态时,SCK为低电平
CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据
相比模式1相位提前了, SCK第一个边沿之前就要开始移出数据了,或者是第0个边沿移出,第1个边沿移入。首先SS下降沿开始通信,现在SCK还没有变化,但是SCK一旦开始变化,就要移入数据了,所以此时趁SCK还没有变化,SS下降沿时,就要立刻触发移位输出,所以这里MOSI和MISO的输出是对齐到SS下降沿的,或者说这里把SS的下降沿也作为时钟的一部分了,SS下降沿触发了输出,SCK上升沿就可以进行数据输入采样了,这样B7就传输完毕,之后SCK下降沿,移出B6,SCK上升沿移入B6,以此类推,SCK下降沿移出数据,上升沿移入数据。
模式0是最常见的模式,很多SPI设备都支持这种模式,因此兼容性较好。
模式0可以实现较高的传输速率,因为数据在时钟的上升沿就被采样,不需要等待下降沿。
(5)交换一个字节(模式2)
CPOL=1:空闲状态时,SCK为高电平
CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据
模式2和模式0波形相反。
(6)交换一个字节(模式3)
CPOL=1:空闲状态时,SCK为高电平
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据
模型3和模式1的波形相反。
1.1.3 SPI时序
以W25Q64为例。SPI是指令码+数据
(1)发送指令
向SS指定的设备,发送指令(0x06,W25Q64写使能)
SS下降沿时刻,时序开始,此时MOSI和MISO就要开始变化数据了。MOSI由于指令码最高位仍然是0,所以这里保持低电平不变;MISO从机没有数据发送给主机,引脚电平没有变换,STM32的MISO是上拉输入,所以这里呈现高电平。之后SCK第一个上升沿,进行数据采样,从机采样输入,得到0,主机采样输入,得到1。之后继续,第二个时钟,主机数据仍然是0,所以波形没有变化,然后一位一位的发送接收发送接收,到主机发送1时才发生变化,下降沿,数据移出,主机将1移出到MOSI,MOSI变为高电平;然后SCK上升沿,数据采样输入,在最后一位下降沿,数据变化,MOSI变为0;上升沿数据采样,从机接收数据0,SCK低电平是变化的时期,高电平是读取的时期。时序SCK最后一个上升沿结束,一个字节就交换完成了。主机用0x06换来了从机的0xFF。
(2)指定地址写
向SS指定的设备,发送写指令(0x02),随后在指定地址(Address[23:0])下,写入指定数据(Data)
写指令之后的字节,定义为地址高位(0x12,23~16),0x34(15~8),0x56(7~0),即0x123456,继续交换,写入0x55
(3)指定地址读
向SS指定的设备,发送读指令(0x03),随后在指定地址(Address[23:0])下,读取从机数据(Data)
主机交换从机地址0x123456下的数据。即指定地址读,读的是0x55