STM32—SPI通讯协议

前言

由于I2C开漏外加上拉电阻的电路结构,使得通信线高电平的驱动能力比较弱,这就会号致,通信线由候电平变到高电平的时候,这个上升沿耗时比较长,这会限制I2C的最大通信速度,

所以,I2C的标准模式,只有100KHz的时钟频率,I2C的快速模式,也只有400KHZ,虽然I2C协议之后又通过改进电路的方式,设计出了高速模式,可以达到3.4MHZ,但是高速模式目前普及程度不是很高,所以一般情况下,我们认为I2C的时钟速度最多就是400KHZ,这个速度,相比较SPI而言,还是慢了很多的

1.SPI通信

  • SPl(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线
  • 四根通信线:SCK(SerialClock)、MOSl(Master Output SlaveInput)、MISO(Master Input Slave Output)、SS(Slave Select),
    • SPl的主机表示,有几个从机,就开几条SS,所有从机,一人一根,都别抢,给你低电平,就说明我要找你了
  • 同步,全双工
  • 支持总线挂载多设备(一主多从)
  • 传输速率块,SPl协议并没有严格规定最大传输速度,这个最大传输速度取决于芯片厂商的设计需求
  • SPl的硬件开销比较大,通信线的个数比较多,并且通信过程中,经常会有资源浪赛的现象

SPI没有应答机制的设计,发送数据就发送,接收数据就接收,至于对面是不是存在,SPl是不管的

第一个图型号是W25Q64,是一个Flash存储器,这个模块的引脚,可以看到和刚才说的并不一样,这里CLK,就是SCK,DI和DO,就是MOSI和MISO,那D到底是MOSl还是MISO呢,我们要看一下这个芯片的身份,显然,这个芯片接在STM32上,应该是从机的身份,所以这里的Dl,数据输入,就是从机的数据输入Sl,对应需要接在主机的MO上,所以,这里的Dl就是MOSI,那另一个DO,就是MISO了,一般在这种始终作为从机的设备上,可能会用DI和DO的简写,像STM32这种,可以进行身份转换的设备,般都会把MOSI、MISO的全程写完整,那最后一个CS片选,其实就是SS从机选择了

第三个是一个2.4G元线通信模块,芯片型号是NRF24L01,这个芯片使用的就是SPI通信协议,要想使用这个芯片来进行无线通信,那就需要利用SPI,来读写这个芯片

最后一个就是常见的Micro SD卡了,这个SD卡,官方的通信协议是SDIO,但是它也是支持SPl协议的,我们可以利用SPI,对这个SD卡进行读写操作

2.硬件电路

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

左边这里,是SPI主机,主号整个SP总线,主机,一般都是控制器来作,比如STM32,下面这里,SPI从机1、2、3,就是挂载在主机上的从设备了,比如存储器、显示屏、通信模块、传感器等等,左边SPI主机实际上引出了6根通信线,因为有3个从机,所以SS线需要3根,再加SCK、MOSI、MISO,就是6根通信线,当然SPI所有通信线都是单端信号,它们的高低电平都是相对GND的电压差,所以,单端信号,所有的设备还需要共地,这里GND的线没画出来,但是是必须要接的,然后如果从机没有独立供电的话,主机还需要再额外引出电源正极VCC,给从机供电

然后我们看一下这几根通信线,首先,SCK时钟线,时钟线完全由主机掌控,所以对于主机来说,时钟线为输出,对于所有从机来说,时钟线都为输入,这样主机的同步时钟,就能送到各个从机了,然后下一个,MOSI,主机输出从机输入,这里左边是主机,所以就对应MO,主机输出,下面三个都是从机,所以就对应S1,从机输入,数据传输方向是,主机通过MOSI输出,所有从机通过MOSI输入,接着下一个,MISO,主机输入从机输出,左边是主机,对应MI,下面三个是从机,对应SO,数据传输方向是,三个从机通过MISO输出,主机通过MISO输入

12C并不是不想使用更快的推挽输出,而是12C要实现半双工,经常要切换输入输出,另外I2C又要实现多主机的时钟同步和总线体裁,这些功能,都不允许12C使用推挽输出,要不然一不小心,就电源短路了,所以,12C选择了更多的功能,自然就要放弃更强的性能了

对SPI来说,首先SPI不支持多主机,然后SPI又是全双工,SPI的输出引脚始终是输出,输入引脚始终是输入,基本不会出现冲突,所以SPI可以大胆地使用推挽输出,不过当然,SPl实还是有一个冲突点的,就是图上的MISO引脚,主机一个是输入,但是三个从机全都是输出,如果三个从机都始终是推挽输出,势必会导致冲突,所以在SPIl协议里,有一条规定,就是,当从机的SS引l脚为高电平,也就是从机未被选中时,它的MISO引脚,必须切换为高阻态,高阻态就相当于引脚断开,不输出任何电平,这样就可以防止,一条线有多个输出,而导致的电平冲突的问题了,在SS为低电平时,MISO才允许变为推挽输出,这就是SPl对这个可能的冲突做出的规定,一般是写在从机里,所以我们主机的程序中,并不需要关注这个问题

3.移位示意图

这个移位示意图是SPI硬件电路设计的核心,只要你把这个移位示意图搞懂了,那无论是上面的硬件电路,还是我们等会学习的软件时序,理解起来都会更加轻松,SPl的基本收发电路,就是使用了这样一个移位的模型,左边是SPI主机,里面有一个8位的移位寄存器,右边是SP从机,里面也有一个8位的移位寄存器,左侧的移位寄存器有一个时钟输入端,因为SPI一般都是高位先行的,所以,每来一个时钟,移位寄存器都会向左进行移位,从机中的移位寄存器也是同理,然后呢,移位寄存器的时钟源,是由主机提供的,这里叫作波特率发生器,它产生的时钟驱动主机的移位寄存器进行移位,同时,这个时钟也通过SCK引脚进行输出,接到从机的移位寄存器里

之后,上面移位寄存器的接法是主机移位寄存器左边移出去的数据,通过MOSO引脚,输入到从机移位寄存器的右边,从机移位寄存器左边移出去的数据,通过MISO引脚,输入到主机移位寄存器的右边

工作流程:首先,我们规定波特率发生器时钟的上升沿,所有移位寄存器向左移动一位,移出去的位放到引脚上,波特率发生器时钟的下降沿,引脚上的位,采样输入到移位寄存器的最低位,接下来,假设主机有个数据10101010要发送到从机,同时,从机有个数据01010101要发送到主机,那我们就可以驱动时钟先产生一个上升沿,这时,所有的位,就会像这样,往左移动一次,那从最高位移出去的数据就会放到通讯线上,数据放到通信线上,实际上是放到了输出数据寄存器,此时MOSI数据是1,所以MOSl的电平就是高电平,这就是第一个时钟上升沿执行的结果 之后,时钟继续运行,上升沿之后,下一个边沿就是下降沿,在下降沿时,主机和从机内,都会进行数据采样输入,也就是,MOSI的1,会采样输入到从机这里的最低位,MISO的0,会采样输入到主机这里的最低位,这就是第一个时钟结束后的现象

下一个上升沿,同样的操作,移位输出,SPl的运行过程就是这样,SPl的数据收发,都是基于字节交换,这个基本单元来进行的,当主机需要发送一个字节,并且同时需要接收一个字节时,就可以执行一下字节交换的时序,这就完成了发送同时接收的目的

如果我只想发送,不想接收,怎么办呢,其实很简单,我们仍然调用交换字节的时序,发送,同时接收,只是,这个接收到的数据,我们不看它就行了,那如果我只想接收,不想发送,怎么办呢,同理,我们还是调用交换字节的时序,发送,同时接收,只是,我们会随便发送一个数据,只要能把从机的数据置换过来就行了,我们读取置换过来的数据,不就是接收了嘛,这里我们随便发过去的数据,从机也不会去看它,当然这个随便发送的数据并不是真的随便发,般在接收的时候,我们会统一发送0x00或OxFF去跟从机换数据

4.SPI时序基本单元

期间一直都是低电平

CPOL(Clock Polarity)时钟极性、和CPHA(Clock Phase)时钟相位

模式0和1的区别:模式0把这个数据变化的时机给提前了,在实际应用中,模式0的应用是最多的

4.1 模式0

与模式一区别CPHA=1,就是这个模武0的数据移出移入的时机,会提取半个时钟,也就是相位提前了,模式0在SCK第一个边沿就要移入数据,但是数据总得先移出,才能移入,对吧,所以在模式0的配置下,SCK第一个边沿之前,就要提前开始移出数据了,或者把它称作是在第0个边沿移出,第1个边沿移入

时序:首先,SS下降沿开始通信,现在SCK还没有变化,但是SCK一旦开始变化,就要移入数据了,所以此时趁SCK还没有变化,SS下降沿时,就要立刻触发移位输出,所以这里MOSI和MISO的输出,是对齐到SS的下降沿的,或者说,这里把SS的下降沿,也当作时钟的一部分了,那SS下降沿触发了输出,SCK上升沿,就可以采样输入数据了,这样B7就传输完毕,之后,SCK下降沿,移出B6,上升沿移入数据,最终在第8个上升沿时最终在第8个上升沿时,整个字节交换完成,之后,SCK还有一个下降沿,如果主机只需要交换一个字节就结束,那在这个下降沿时,MOSI可以置回默认电平,或者不去管它,MISO也会变化一次,这一位,实际上是下一个字节的B7

因为这个相位提前了,所以下一个字节的B7会露个头,如果不需要的话,SS上升沿之后,从机MISO置回高阻态,这是交换一个字节就结束,如果主机想交换多个字节的话,那就继续调用,从这里到这里的时序,在随后一个下降沿,主机放下一个字节的B7,从机也放下一个字节的B7,SCK上升沿,正好接着采样第二个字节的B7.这样时序才能拼接的上,对吧

4.2 模式1

在SS未被选中时,SCK默认是低电平的,然后CPHA=1,表示SCK第一个边沿移出数据,第二个边沿移入数据(采样),

第一个SS,从机选择在通信开始前,SS为高电平,在通信过程中,SS始终保持低电平,通信结束,SS恢复高电平

然后最下面一个MISO这是主机输入,从机输出,因为有多个从机输出连在了一起,如果同时开启输出,会造成冲突,所以,我们的解决方法是,在SS未被选中的状态,从机的MISO引脚必须关断输出,即配置输出为高阻状态,SS高电平时,MISO用一条中间的线,表示高阻态,SS下降沿之后,从机的MISO被允许开启输出,SS上升沿之后,从机的MISO必须置回高阻态

然后,我们看一下移位传输的操作,因为CPHA=1,SCK第一个边沿移出数据,所以这里可以看出,SCK第一个边沿,就是上升沿,主机和从机同时移出数据,主机通过MOSI移出最高位,此时MOSl的电型就表示了主机要发送数据的B7,从机通过MISO移出最高位,此时MISO表示从机要发送数据的B7,然后时钟运行,产生下降沿,此时主机和从机同时移入数据,也就是进行数据采样,这里主机移出的B7,进入从机移位寄存器的最低位,从机移出的B7,进入主机移位寄存器的最低位,这样,一个时钟脉冲产生完毕,一个数据位传输完毕,接下来就是同样的过程,最后一个下降沿,数据B0传输完成,至此,主机和从机就完成了一个字节的数据交换如果主机只想交换一个字节,那这时就可以置SS为高电平,结束通信了,在SS的上升沿,MOSl还还可以再变化一次,将MOSI置到一个默认的高电平或低电平,当然也可以不去管,因为SPI也没有硬性规定MOSI的默认电平,然后MISO,从机必须得置回高阻态,此时如果主机的MISO为上拉输入的话,那MISO引脚的电平就是默认的高电平,如果主机MISO为浮空输入那MISO引脚的电平不确定,这是交换一个字节就结束的流程

那如果主机还想继续交换字节呢,在此时,主机就不必把SS置回高电平了,直接重复一下,从这里到这里,交换一个字节的时序,这样就可以交换多个字节了

4.3 模式2

模式0和2的区别:就是SCK的极性取反一下,剩下的流程上的东西,完全一致

4.4 模式3

模式1和3的区别:也是模武1的CPOL=0,模式3的CPOL=1,两者的波形,也是SCK的极性取反一下

这个CPHA表示的是时钟相位,决定是第一个时钟采样移入还是第二个时钟采样移入,并不是规定上升沿采样还是下降沿采样的,当然,在CPOL确定的情况下,CPHA确实会改变采样时刻的上升沿和下降沿,比如,模式0的时候,是SCK上升沿采样移入,模式1的时候,是SCK下降沿采样移入,这个了解一下,CPHA决定是第几个边沿采样,并不能单独决定是上升沿还是下降沿

然后在这4种模式里模式0和模式3,都是SCK上升沿采样,模式1和模式2,都是SCK下降沿采样

5.SPI时序(W26Q86)

当然每个芯片对SPI时序字节流功能的定义不一样,在这里,我是以我们本课程使用的芯片W25Q64,SPIl对字节流功能的规定,不像12C那样,12C的规定一般是,有效数据流第一个字节是寄存器地址,之后依次是读写的数据,使用的是读写寄存器的模型

而在SPI中,通常采用的是指令码加读写数据的模型,这个过程就是,SPl起始后,第一个交换发送给从机的数据,一般叫作指令码,在从机中,对应的会定义一个指令集,当我们需要发送什么指令时,就可以在起始后第一个字节,发送指令集里面的数据,这样就能指导从机完成相应的功能了,不同的指令,可以有不同的数据个数,有的指定,只需要一个字节的指令码就可以完成,比如W25Q64的写使能、写失能等指令,而有的指令,后面就需要再跟要读写的数据,比如W25Q64的写数据、读数据等,写数据,指令后面就得跟上,我要在哪里写,我要写什么,对吧,读数据,指令后面就得跟上,我要在那里读,我读到的是什么,对吧,这就是指令码加读写数据的模型,在SPI从机的芯片手册里,都会定义好指令集,什么指令对应什么功能,什么指令,后面得跟上什么数据

5.1 发送指令

首先是SPI发送指令,这个指令的功能是向SS指定的设备,发送指令(0x06),指令0x06,到底代表什么意思,可以由芯片厂商自己规定,在W25Q64芯片里,这个0x06代表的是写使能

在这里,我们使用的是SPI模式0,在空闲状态时,SS为高电平,SCK为低电平,MOSI和MISO的默认电平没有严格规定,然后,SS产生下降沿,时序开始,在这个下降沿时刻,MOSI和MISO就要开始变换数据了,MOSl,由于指令码最高位仍然是0,所以这里保持低电平不变,MISO,从机现在没有数据发给主机,引脚电平没有变换,实际上W25Q64不需要回传数据时,手册里规定的是MISO仍然是高阻态,从机并没有开启输出,不过这也没问题,反正这个数据我们也不要看,那这里因为STM32的MISO是上拉输入,所以这里MISO呈现高电平,之后,SCK第一个上升沿,进行数据采样,我这里画了一条绿线,从机采样输入,得到0,主机采样输入,得到1,之后继续,第二个时钟,主机数据位仍然是0所以波形仍然没有变化,然后这样一位一位地发送、接收、发送、接收,

到这一位,数据才开始变化,主机要发送数据1,下降沿,数据移出,主机将1移出到MOSl,MOSI变为高电平,这里因为是软件模拟的时序,所以MOSl的数据变化有些延迟,没有紧贴SCK的下降沿,不过这也没关系,时钟是主机控制的,我们只要在下一个SCK上升沿之前完成变化就行了,然后,SCK上升沿,数据采样输入,在最后一位呢,下降沿,数据变化,MOSI变为0,上升沿,数据采样,从机接收数据,SCK低电平是变化的时期,高电平是读取的时期

时序SCK最后一个上升沿结束,一个字节就交换完毕了,因为写使能是单独的指令,不需要跟随数据,SPI只需要交换一个字节就完事了,所以最后,在SCK下降沿之后,SS置回高电平,结束通信,总结一下,就是主机用0x06换来了从机的0xFF,当然实际上从机并没有输出,这个0xFF是默认的高电平,不过,这个0xFF,没有意义,我们不用管,那整个时序的功能,就是发送指令,指令码是0x06,从机一比对事先定义好的指令集,发现0x06是写使能的指令,那从机就会控制硬件,进行写使能,这样一个指令从发送到执行,就完成了,这就是发送单字节指令的时序

5.2 指定地址写

因为我们这个W25Q64芯片有8M字节的存储空间,一个字节的8位地址肯定不够,所以这里地址是24位的,分3个字节传输

首先,SS下降沿,开始时序,这里,MOS|空闲时是高电平,所以在下降沿之后,SCK第一个时钟之前,可以看到,MOSI变换数据,由高电平变为低电平,然后SCK上升沿,数据采样输入,后面还是一样,下降沿变换数据,上升沿采样数据,8个时钟之后,一个字节交换完成,我们用0x02,换来了0xFF,其中发送的0x02,是一条指令,代表这是一个写数据的时序,接收的0xFF,不需要看,那既然是写数据的时序,后面必然还要跟着写的地址和数据了,所以在最后一个下降沿时刻,因为我们后续还要继续交换字节,所以在这个下降沿,我们要把下一个字节的最高位放到MOSI上,当然下一个字节的最高位仍然是0,所以这里数据没有变化,之后还是同样的流程,交换一个字节,第二个字节,我们用0x12,换来了0xFF,根据W25Q64芯片的规定,写指令之后的字节,定义为地址高位,所以这个0x12,就表示发送地址的23~16位,

之后继续,看一下,交换1个字节,发送的是0x34,这个就表示发送地址的15~8位,之后还是交换一个字节,发送的是0x56,这个表示发送地址的7~0位,24位地址就发送完毕了,从机收到的24位地址是0x123456,

那3位地址结束后就要发送写入指定地址的内容了,我们继续调用交换一个字节,发送数据,这里的波形是0x55,这就表示,我要在0x123456地址下,写入0x55这个数据,最后,如果只想写入一个数据的话,就可以SS置高电平,结束通信了,当然,这里也可以继续发送数据,SPI里,也会有和I2C一样的地址指针,每读写一个字节,地址指针自动加1,如果发送一个字节之后,不终止,继续发送的字节就会依次写入到后续的存储空间里,这样就可以实现从指定地址开始,写入多个字了,这就是SPI写入的时序

由于SPI没有应答机制,所以交换一个字节后,就立刻交换下一个字节就行了,然后这条指令,我们还可以看出,由于整个流程,我们只需要发送的功能,并没有接收的需求,所以MISO这条接收的线路,就始终处于"挂机"的状态,我们并没有用到,这就是SPI指定地址写的逻辑,当然不同的芯片肯定有不同的规定了,我们这个存储器的容量大,所以需要连续指定3个字节的地址,如果容量小的话,可能1个字节的地址就够了,或者有的芯片会直接把地址给融合到指令码里去

5.3 指定地址读

所以这里,3个字节地址交换完之后,我们要把从机的数据搞过来,我们还是交换一个数据,来个抛砖引玉,我们随便给从机一个数据,当然一般给FF就行了,然后从机,此时不传,更待何时啊,这时从机就会乖乖地把0x123456地址下的数据通过MISO发给主机,可以看到,这样的波形,就表示指定地址下的数据是0x55,这样主机就实现了指定地址读一个字节的目的,然后如果我们继续抛砖引玉,那么从机内部的地址指针自动加1,从机就会继续把指定地址下一个位置的数据发过来,这样依次进行,就可以实现指定地址接收多个字节的目的了,然后最后,数据传输完毕,

SS置回高电平,时序结束

当然,时序这里也会有一些细节,比如,由于MISO是硬件控制的波形,所以它的数据变化,都可以紧贴时钟下降沿,另外,我们可以看到,MISO数据的最高位实际上是在上一个字节,最后一个下降沿,提前发生的,因为这是SPI模式0,所以数据变化都要提前半个周期

相关推荐
7yewh17 分钟前
嵌入式硬件杂谈(六)充电器原理 线性电源 开关电源 反激电源原理
单片机·嵌入式硬件·mcu·物联网·硬件架构·硬件工程·pcb工艺
秋风&萧瑟34 分钟前
【freertos】FreeRTOS消息队列的介绍与使用
单片机
FlechazoCLF1 小时前
小柴冲刺软考中级嵌入式系统设计师系列三、嵌入式硬件设计(1)嵌入式系统电源管理
嵌入式硬件
drinow9 小时前
【纸飞机串口调试工具】预设曲线名称
arm开发·驱动开发·单片机·mcu·dsp开发·fpga·iot
时光の尘10 小时前
C语言菜鸟入门·关键字·int的用法
c语言·开发语言·数据结构·c++·单片机·链表·c
深圳市青牛科技实业有限公司 小芋圆11 小时前
【青牛科技】 GC2803:白色家电与安防领域的卓越驱动芯片可替代ULN2803
科技·单片机·嵌入式硬件·电脑·白色家电·电动卷帘门·工业设备
Arciab13 小时前
51单片机入门:LED灯控制(01)
单片机·led·51
LaoZhangGong12314 小时前
Linux第95步_Linux内核中的INPUT子系统
linux·运维·数据库·经验分享·stm32·input·stm32mp127
BreezeJuvenile15 小时前
STM32总体架构简单介绍
stm32·单片机·嵌入式硬件
scgg16 小时前
STM32抢占优先级不生效
stm32·疑问