STM32 SPI(一)通信协议

STM32 SPI(一)通信协议

SPI通信

SPI传输速度更快,SPI协议并没有严格规定最大传输速度

  • SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线,用于主控和外挂芯片之间的通信

  • 四根通信线:SCK(Serial Clock 串行时钟线 别称:SCLK CLK CK)、MOSI(Master Output Slave Input 主机输出从机输入 别称:DO Data Output)、MISO(Master Input Slave Output 主机输入从机输出 DI Data Input)、SS(Slave Select 从机选择 别称:NSS Not Slave Select 、 CS Chip Select)

  • 同步,全双工

    • SCK引脚,用来提供时钟信号,数据位的输出和输入,都是在SCK的上升沿和下降沿进行的,这样,数据位的收发时可就可以明确的确定。
    • 全双工,就是数据发送和数据接收单独各占一条线,发送用发送的线路,接收用接收的线路,两者互不影响。MOSI和MISO,就是分别用于发送和接收的两条线路,MOSI,是主机输出从机输入,如果是主机接在这条线上,那就是MO,主机输出,如果是从机接在这条线上,就是SI,从机输入,意思就是一条通信线,如果主机接在上面配置为输出,那从机肯定得配置为输入,才能接收主机的数据,主机和从机不能同时配置为输出或输入,要不然就没法通信了,所以这条MOSI,就是主机向从机发送数据的线路,同理下面这条MISO,就是主机从从机接收数据的线路。
  • 支持总线挂载多设备(一主多从)

硬件电路

SPI 所有通信线都是单端信号,它们的高低电平都是相对于GND的电压差,所以单端信号,所有的设备还需要共地。

  • 所有SPI设备的SCK、MOSI、MISO分别连在一起

    • SCK 时钟线,完全由主机掌控,所以对于主机来说,时钟线为输出,对于所有从机来说,时钟线都为输入,这样主机的同步时钟,就能送到各个从机了。
    • MOSI 主机输出从机输入,主机对应MO,主机输出,从机对应SI,从机输入,数据传输方向是,主机通过MOSI输出,所有从机通过MOSI输入。
    • MISO 主机输入从机输出,主机对应MI,主机输入,从机对应SO,从机输出,数据传输方向是,三个从机通过MISO输出,主机通过MISO输入。
  • 主机另外引出多条SS控制线,分别接到各从机的SS引脚

    • 下图中有三个从机,我们就需要在主机另外引出3跟SS选择线,分别接到每个从机的SS输入端,主机的SS线都是输出,从机的SS线都是输入,SS线是低电平有效,主机想指定与哪个从机通信,就把对应的SS输出线置低电平就行了。例如,主机初始化后,所有的SS都输出高电平,这样就是谁也不指定,当主机需要和从机1通信时,主机就把SS1线输出低电平,这样从机1就知道,主机在找我,然后主机在数据引脚进行的传输,就只有从机1会响应,其他从机的SS线是高电平,所以它们都会保持沉默。当主机和从机1通信完成后,就会把SS1置回高电平,这样从机1就知道,主机结束了和我的通信。之后,主机需要和从机2和从机3通信时,也是同理,需要找谁通信,就置谁的SS为低电平。当然,同一时间,主机只能置一个SS为低电平,只能选中一个从机,否则如果主机同时选中多个从机,就会导致数据冲突。
  • 输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入

    • 对于输出,我们配置为推挽输出,推挽输出,高低电平均有很强的驱动能力,这将使得SPI引脚信号的下降沿,非常迅速,上升沿也非常迅速。得益于推挽输出的驱动能力,SPI信号变化的快,自然它就能达到更高的传输速度。一般SPI信号都能轻松达到MHz的速度级别。

MISO 引脚主机一个是输入,但是三个从机全部是输出,如果三个从机都始终是推挽输出,势必会导致冲突,所以在SPI协议里,有一条规定,当从机的SS引脚为高电平,也就是从机未被选中时,它的MOSI引脚,必须切换为高阻态,高阻态就相当于引脚断开,不输出任何电平,这样就可以防止,一条线有多个输出,而导致的电平冲突的问题了。在SS为低电平时,MISO才允许变为推挽输出。但这个切换过程都是在从机中,一般不需要关注这个问题。

在这里插入图片描述

移位示意图

SPI通信的基础是交换一个字节,有了交换一个字节,就可以实现发送一个字节、接收一个字节,和发送同时接收一个字节,这三种功能。SPI在只执行发送或只执行接收的时候,会存在一定的资源浪费现象,但这也是全双工通信所不可避免的。

  • SPI的基本收发电路,就是使用了这样一个移位的模型。左边是SPI主机,里面有一个8位的移位寄存器。右边是SPI从机,里面也有一个8位的移位寄存器。这里的移位寄存器有一个时钟的输入端,因为SPI一般都是高位先行的,所以每来一个时钟,移位寄存器都会向左进行移位,从机中的移位寄存器也是同理。移位寄存器的时钟源,是由主机提供的,这里叫做波特率发生器,它产生的时钟驱动主机的移位寄存器进行移位,同时这个时钟也通过SCK引脚进行输出,接到从机的移位寄存器里。
  • 主机移位寄存器左边移出去的数据通过MOSI引脚,输入到从机移位寄存器的右边,从机移位寄存器左边移出去的数据,通过MISO引脚,输入到主机移位寄存器的右边。

电路工作原理

  • 我们规定,波特率发生器时钟的上升沿,所有移位寄存器向左移动一位,移出去的位放到引脚上,波特率发生器时钟的下降沿,引脚上的位,采样输入到移位寄存器的最低位。
  • 假设主机有个数据10101010要发送到从机,同时从机有个数据01010101要发送到主机,那我们就可以驱动时钟,先产生一个上升沿,这时所有的位,就会往左移动一次,那从最高位移出去的数据,就会放到通信线上,数据放到通信线上,实际上是放到了输出数据寄存器,可以看到,此时MOSI数据是1,所以MOSI的电平就是高电平,MISO数据是0,所以MISO的电平就是低电平。这就是第一个时钟上升沿执行的结果,就是把主机和从机中,移位寄存器的最高位,分别放到MOSI和MISO的通信线上,这就是数据的输出。
  • 之后时钟继续运行,上升沿之后,下一个边沿就是下降沿,在下降沿时,主机和从机内,都会进行数据采样输入,也就是MOSI的1,会采样输入到从机这里的最低位,MISO的0会采样输入到从机这里的最低位。
  • 时钟继续运行,下一个上升沿,同样的操作,移位输出,随后,下降沿数据采样输入,一直到第8个时钟,都是同样的过程。
  • 最终,8个时钟之后,我们看到,原来主机里的10101010,转移到了从机中,原来从机里的01010101,转移到了主机中,这就实现了主机和从机一个字节的数据交换。
  • SPI的数据收发,都是基于字节交换这个基本单元来进行的。当主机需要发送一个字节,并且同时需要接收一个字节时,就可以执行字节交换的时序。这样主机要发送的数据,转移到了从机中,主机要从从机接收的数据,转移到了主机。这就完成了发送同时接收的目的。
  • 如果只想发送,不想接收,我们可以仍然调用交换字节的时序,发送,同时接收,只是这个接收到的数据我们忽略即可。
  • 如果只想接收,不想发送,同理,我们还是调用交换字节的时序,发送,同时接收,只是,我们会随便发送一个数据,只要能把从机的数据置换过来就行了,我们读取置换过来的数据,就可以完成接收。这里我们随便发过去的数据,从机也会忽略。一般在只接收的时候,我们会统一发送0x00或0xFF,去跟从机换数据。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

SPI时序基本单元

  • 起始条件:SS从高电平切换到低电平,选中某个从机,通信开始

  • 终止条件:SS从低电平切换到高电平,结束从机的选中状态,通信结束

  • 在从机的整个选中状态中,SS要始终保持为低电平,SS低电平选中,高电平未选中,那低电平期间就代表正在通信,下降沿是通信的开始,上升沿是通信的结束。

在这里插入图片描述

数据传输的基本单元

这个基本单元是建立在移位模型的基础上的,并且这个基本单元,什么时候开始移位,是上升沿移位还是下降沿移位,SPI并没有限定死,给了我们可以配置的选择,这样,SPI就可以兼容更多的芯片。

SPI共有2个可以配置的位,每一位可以配置为1或0,总共组合起来,就有模式0、模式1、模式2、模式3这四种模式。

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

下面主要分析模式1


CHPA决定是第几个边沿采样,并不能决定是上升沿采样还是下降沿采样。

在这四种模式中,模式0和模式3都是SCK上升沿采样,模式1和模式2都是SCK下降沿采样。

  • 交换一个字节(模式0)

  • CPOL=0:空闲状态时,SCK为低电平

  • CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据

在这里插入图片描述

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


时序图

  • 首先,SS下降沿开始通信,现在SCK还没有变化,但是SCK一旦开始变化,就要移入数据了,所以此时趁SCK还没有变化,SS下降沿时,就要立刻触发移位输出,所以这里MOSI和MISO的输出,是对齐到SS的下降沿的,或者说,这里把SS的下降沿,也当做是时钟的一部分了,那SS下降沿触发了输出,SCK上升沿,就可以采样输入数据了。这样B7(Bit 7)就传输完毕。之后,SCK下降沿,移出B6(BIt 6),SCK上升沿,移入B6,然后继续,下降沿移出数据,上升沿移入数据,最终在第8个上升沿时,B0(Bit 0)移入完成,整个字节交换完成。
  • 之后SCK还有一个下降沿,如果主机只需要交换一个字节就结束,那在这个下降沿,MOSI可以置回默认电平,或者不管,MISO也会变化一次,这一位,实际上是下一个字节的B7(Bit 7),因为这个相位提前了,所以下一个字节的B7(Bit 7)会露个头。如果不需要的话,SS上升沿之后,从机MISO置回高阻态,这是交换一个字节就结束。
  • 如果主机想交换多个字节的话,那就继续调用前面的时序,在最后一个下降沿,主机放下一个字节的B7(Bit 7),从机也放下一个字节的B7(Bit 7),SCK上升沿,正好接着采样第二个字节的B7,这样时序才能拼接的上。

  • 交换一个字节(模式1)

  • CPOL=0:空闲状态时,SCK为低电平

  • CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据(另外的描述方式1.第二个边沿进行数据采样2.SCK的偶数边沿进行数据采样)

在这里插入图片描述

时序图

  • SS 从机选择,在通信开始前,SS为高电平,在通信过程中SS时钟保持低电平,通信结束,SS恢复高电平。

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

  • 因为CPHA=1,SCK第一个边沿移出数据,SCK第一个边沿就是上升沿,主机和从机同时移出数据,主机通过MOSI移出最高位,此时MOSI的电平就表示了主机要发送的数据B7(Bit 7),从机通过MISO移出最高位,此时MISO表示从机要发送的数据B7,然后时钟运行,产生下降沿,此时主机和从机同时移入数据,也就是进行数据采样,这里主机移出的B7,进入从机移位寄存器的最低位,从机移出的B7,进入主机移位寄存器的最低位,这样,一个时钟脉冲产生完毕,一个数据位传输完毕。

  • 接下来就是同样的过程,上升沿,主机和从机同时输出当前移位寄存器的最高位,第二次的最高位,就是原始数据的B6(Bit 6),然后下降沿,主机和从机移入数据,B6传输完成。之后时钟继续运行,数据依次移出、移入、移出、移入,最后一个下降沿,数据B0(Bit 0)传输完成,至此,主机和从机就完成了一个字节的数据交换。

  • 如果主机只想交换一个字节,那这时就可以置SS为高电平,结束通信了。在SS的上升沿,MOSI还可以再变化一次,将MOSI置到一个默认的高电平或者低电平,当然也可以不去管,因为SPI也没有硬性规定MOSI的默认电平,然后MISO,从机必须得置回高阻态,此时如果主机的MISO为上拉输入的话,那MISO引脚的电平就是默认的高电平。如果主机MISO为浮空输入,那MISO引脚的电平不确定,这是交换一个字节就结束的流程。

  • 如果主机还想继续交换字节,一个字节交换完成时,主机就不必把SS置回高电平了,直接再重复一下交换字节的时序,这样就可以交换多个字节了。

  • 交换一个字节(模式2)

  • CPOL=1:空闲状态时,SCK为高电平

  • CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据

在这里插入图片描述

  • 交换一个字节(模式3)

  • CPOL=1:空闲状态时,SCK为高电平

  • CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据

在这里插入图片描述

SPI时序

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

在这里插入图片描述

  • SPI模式0,在空闲状态时,SS为高电平,SCK为低电平,MOSI和MISO的默认电平没有严格规定,然后SS产生下降沿,时序开始。
  • 在SS的下降沿时刻,MOSI和MISO就要开始变换数据了,MOSI由于指令码最高位仍然是0,所以这里保持低电平不变,MISO,从机现在没有数据发给主机,引脚电平没有变换。实际上W25Q64不需要回传数据时,手册里规定的时MISO仍然是高阻态,从机并没有开启输出。由于STM32的MISO是上拉输入,所以MISO呈现高电平。
  • 之后,SCK第一个上升沿,进行数据采样,主机采样输入,得到1,从机采样输入,得到0。之后继续第二个时钟,主机数据仍然是0,所以波形仍然没有变化,然后像这样一位一位地发送、接收、发送、接收,到主机发送1的时候,数据才开始变化,主机要发送数据1,下降沿数据移出,主机将1移出到MOSI,MOSI变为高电平,这里因为是软件模拟的时序,所以MOSI的数据变化有些延迟,没有紧贴SCK的下降沿。不过因为时钟是主机控制的,我们只要在下一个SCK上升沿之前完成变化就行了。然后SCK上升沿,数据采样输入。在最后一位,下降沿,数据变化,MISO变为0,上升沿,数据采样,从机接收数据0。
  • SCK低电平是变换的时期,高电平是读取的时期。时序SCK最后一个上升沿结束,一个字节就交换完毕了,因为写使能是单独的指令,不需要跟随数据,SPI只需要交换一个字节就完事了。所以最后,在SCK下降沿之后,SS置回高电平,结束通信。
  • 主机用0x06换来了从机的0xFF,从机用0xFF换来了主机的0x06。这个0xFF是默认的高电平。那这整个时序的功能,就是发送指令,指令码是0x06,从机一比对事先定义好的指令集,发现0x06是写使能的指令,那从机就会控制硬件,进行写使能。
  • 指定地址写

  • 向SS指定的设备,发送写指令(0x02),

  • 随后在指定地址(Address[23:0])下,写入指定数据(Data)

在这里插入图片描述

  • W25Q64芯片有8M字节的存储空间,一个字节的8位地址肯定不够,所以这里地址是24位的,分3个字节传输。
  • 首先SS下降沿,开始时序,这里MOSI空闲时是高电平,所以SS下降沿之后,SCK第一个时钟之前,可以看到,MOSI变换数据,由高电平变为低电平。然后SCK上升沿,数据采样输入,后面还是一样,下降沿变换数据,上升沿采样数据。8个时钟之后,一个字节交换完成,我们用0x02换来了0xFF,其中发送的0x02,是一条指令,代表这是一个写数据的时序。
  • 既然是写数据的时序,后面必然还要跟着写的地址和数据了,所以在最后一个下降沿时刻,因为我们后续还要继续交换字节,所以在这个下降沿,我们要把下一个字节的最高位放到MOSI上,当然下一个字节的最高位仍然是0,所以数据没有变化,之后还是同样的流程,交换一个字节,第二个字节,我们用0x12换来了0xFF。根据W25Q64芯片的规定,写指令之后的字节,定义为地址高位,所以这个0x12就表示发送地址的23~16位。之后继续,交换一个字节,发送的是0x34,这个就表示发送字节的15~8位,之后还是交换一个字节,发送的是0x56,这个表示发送地址的7~0位,通过3个字节的交换,24位地址就发送完毕了。从机收到的24位地址是0x123456
  • 那3位地址结束后,就要发送写入指定地址的内容了,我们继续调用交换一个字节,发送数据,这里的波形是0x55,这就表示我要在0x123456地址下,写入0x55这个数据,最后,如果只想写入一个数据的话,就可以SS置高电平,结束通信了。
  • SPI也会有和I2C一样的地址指针,每读写一个字节,地址指针自动加1,如果发送一个字节之后,不终止,继续发送的字节就会依次写入后续的存储空间里,这样就可以实现从指定地址开始,写入多个字节了。
  • 由于SPI没有应答机制,所以交换一个字节后,就立刻交换下一个字节就行了。由于整个流程,我们只需要发送的功能,并没有接收的需求,所以MISO这条接收的线路,就始终处于“挂机”的状态,我们并没有用到。
  • 指定地址读

  • 向SS指定的设备,发送读指令(0x03),

  • 随后在指定地址(Address[23:0])下,读取从机数据(Data)

在这里插入图片描述

  • 起始之后第一个字节,主机发送指令0x03,代表我们要读取数据了,之后还是一样,主机再一次交换3个字节,分别是0x12,0x34,0x56,组合到一起就是0x123456,代表24位地址。

  • 最后这个地方,就是关键点了,因为我们是读取数据,指定地址之后,显然我们要开始接收数据,所以这里,3个字节地址交换完之后,我们要把从机的数据转移过来。所以,我们还是交换一个数据,我们随便给主机一个数据,一般是0xFF,这时从机就会把0x123456地址下的数据通过MISO发给主机。可以看到指定地址下的数据为0x55。这样主机就实现了指定地址读一个字节的目的。如果我们给主机一个0xFF,那么从机内部的地址指针自动加1,从机就会继续把指定地址下一个位置的数据发过来。这样依次进行,就可以实现指定地址接收多个字节的目的了。

  • 然后最后,数据传输完毕,SS置回高电平,时序结束。

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

  • 然后最后,数据传输完毕,SS置回高电平,时序结束。

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YRr YRr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值