stm32f103c8t6学习笔记(学习B站up江科大自化协)-SPI

SPI通信 

        

        ·SPI,(serial peripheral interface),字面翻译是串行外设接口,是一种通用的数据总线,适用于主控和外挂芯片之间的通信,与IIC应用领域非常相似。

        ·IIC无论是在硬件电路还是在软件时序设计的都是较为复杂的,硬件上需要配置成开漏外加上拉的模式,软件上需要一根数据线兼顾数据收发、应答位收发、寻址机制的设计等等,使得IIC的性价比极高,可以在消耗最低硬件资源的情况下实现最多的功能。在硬件上无论挂载多少个设备(128最多)都只需要两根通讯线,在软件上数据双向通信、应答位都可以实现。IIC既实现硬件上最少的通信线,又实现软件上最多的功能。

        但是IIC的缺点在于:IIC开漏外加上拉电阻的电路结构,使得通讯线高电平的驱动能力较弱,会导致通信线由低电平到高电平的时候上升沿会比较长,会最大限制IIC的通信速度,所以IIC的标准模式只有100KHz的时钟频率,快速模式也只有400KHz,虽然后边改进电路设计出了高速模式可达3.4MHz,但是普及程度不高,一般情况下认为IIC时钟速度最高400KHz,相比SPI慢很多。

        ·SPI传输比IIC更快,SPI协议没有严格规定最大传输速度,最大传输速度取决于芯片厂商的设计需求,比如 W25Q64 存储器芯片,手册中写最大时钟频率可达80MHz,比stm32f1的主频还高。SPI硬件通信线比较多,通信过程中常有资源浪费的现象。

        ·SPI有四根通信线,分别是SCK(serial CLOCK串行时钟线)、MOSI(master output slave input主机输出从机输入)、MISO(master input slave output主机输入从机输出)、SS(slave select从机选择)

        ·通信线名字的额外表述方式:

                SCK:SCLK、CLK、CK

                MOSI:DO( DATA OUTPUT )

                MISO:DI( DATA INPUT )

                SS:NSS( NOT SLAVE SELET )、CS( CHIP SELECT )

        ·同步:SCK引脚用于提供时钟信号,数据位的输出和输入都是在SCK的上升沿或下降沿进行,数据位的收发时刻因此得以确定。同步时序下时钟快慢或中途暂停都没问题。SCK相当于IIC通信下的SCL,作用相同。

        ·全双工:数据发送和数据接收单独各占一条线,发送用发送的线路,接收用接收的线路,互不影响。MOSI如果是主机接在上面,那就是MO主机输出,如果是从机接在这条线上就是MI从机输入。一条通信线如果主机接在上面配置为输出,从机必须配置为输入才能接收数据,主机和从机不能同时配置为输出和输入,会造成无法通信。同理MISO是主机从从机接收数据的线路。这两根通信线加在一起相当于IIC通信的SDA,不过IIC是半双工。全双工的好处是简单高效,数据流方向不会改变,无需担心发送和接收没协调好冲突,但是多了一根线造成了资源的浪费。

        ·一主多从:SPI仅支持一主多从,IIC实现一主多从的方式是在起始条件之后主机必须先发送一个字节进行寻址,用于规定要和哪个从机进行通信,要设计分配地址和寻址的问题。SPI实现一主多从的方式通过开辟多条通信线用于和从机通信,有几个从机就对应有几条SS,需要找哪个从机的时候就控制信号线为低电平,不需要时信号线为高电平。SPI没有应答机制,是否具有接收方无法得知。

硬件电路

        这个图是SPI的一个典型电路,左边是SPI主机,主导整个SPI总线,一般是用控制器做主机如stm32,由于有3个从机,所以SS有3根,加上SCK、MOSI、MISO共6根,由于SPI所有通信线都是单端信号,高低电平都是相对于GND的电压差,单端信号所有的设备需要共地,图中未画出,但是必须要接。如果从机没有独立供电的情况下,主机需引出VCC给从机供电。

        SCK时钟线完全由主机掌控,对主机来说时钟线为输出,对于所有主机来说时钟线都为输入,主机的同步时钟将送到各个从机。

        主机的SS线都是输出,从机的SS都是输入,SS线是低电平有效,主机在指定从机时只需将SS置低电平即可。主机初始化之后所有的SS都输出高电平,谁也不指定,当需要和从机1进行通信时就把SS1线输出低电平,此时主机在数据引脚进行的传输只有从机1会响应,当主机和从机1通信完成之后将会把SS1置回高电平,结束通信。

        输出引脚配置为推挽输出,因为推挽输出在高低电平均具有较强的驱动能力,这将是的SPI引脚信号的下降沿非常迅速,上升沿也非常迅速,不像IIC下降沿迅速上升沿缓慢。得益于推挽输出的驱动能力,SPI信号变化的快,能达到更高的传输速度(MHz级别)。

        IIC由于要实现半双工,经常需要切换输入输出,还要实现多主机的时钟同步和总线仲裁,这些功能都不允许IIC使用推挽输出,易造成电源短路。IIC选择了更多的功能,因此只能放弃更强的性能。

        SPI的MISO引脚中主机一个是输入,三个从机都是输出,如果三个从机始终都是推挽输出将会导致冲突,因此SPI协议中有一个规定,当从机的SS引脚为高电平,即从机未被选中时,它的MISO引脚需切换为高组态(相当于引脚断开,不输出任何电平),以防止一条线有多个输出导致电平冲突,只有当SS为低电平时MISO才允许变为推挽输出。由于这个切换过程都在从机里进行,一般我们写的是主机的程序,主机的程序中也无需关心此问题。

移位示意图(核心)

        SPI的基本收发电路使用了图示的移位模型,左边是SPI的主机,内置一个8为的移位寄存器,右边是SPI从机,同样是8位的移位寄存器。在移位寄存器下方有一个时钟输入端,SPI一般是高位先行,每来一个时钟移位寄存器都会向左进行移位,从机中的移位寄存器同理。移位寄存器的时钟源是由主机提供的,在这里叫做波特率发生器,产生的时钟驱动主机的移位寄存器进行移位,同时这个时钟通过SCK引脚进行输出,接到从机的移位寄存器里。

        移位寄存器的接法是:主机移位寄存器左边移出去的数据通过MOSI引脚输入到从机移位寄存器的右边,从机移位寄存器左边移出去的数据通过MISO引脚输入到主机移位寄存器的右边,组成一个圈。

发送同时接收

        电路的工作流程:首先规定波特率时钟的上升沿,所有移位寄存器向左移动一位,移出去的位放在引脚上;波特率时钟的下降沿时,引脚上的位采样输入到移位寄存器的最低位。

        假设主机有个数据1010 1010要发送到从机,同时从机有个数据0101 0101要发送到主机,那么可以先驱动时钟产生一个上升沿,这时所有的位将会向左移动一次,从最高位移出去的数据将会放在通信线上,实际上是放在了输出寄存器,MOSI数据是1,即MOSI的电平是高电平,MISO的数据是0,所以MISO的电平是低电平。第一个时钟沿就是把主机和从机中移位寄存器的最高位分别放到MOSI和MISO的通信线上,这是数据的输出的部分。

        之后时钟继续运行,上升沿之后下一个边沿就是下降沿,在下降沿时主机和从机内都会进行数据采样输入,也就是MOSI里的1会采样输入到从机里的最低位。       

         在下一个上升沿进行同样的操作,移位输出,主机现在的最高位,也就是原始数据的次高位输出到MOSI从机现在的最高位输出到MISO,随后下降沿数据采样输入

         MISO数据到从机寄存器的最低位,MISO数据到主机寄存器的最低位

        第三个时钟开始 一直到第八个时钟都是一样的过程,最终八个时钟过后得到如下结果,原本主机的1010 1010跑道从机里边,原来从机里的0101 0101跑到了主机里,实现了主机和从机一个字节数据的交换。

        以上就是SPI的运行过程,SPI的数据收发都是基于字节交换这个基本单元进行,当主机需要发送一个字节同时接收一个字节时,就可以执行字节交换的时序,主机要发送的数据跑到从机,主机要从从机接收的数据跑到主机,完成了发送同时接收的目的。

只发送不接收

        如果想只发送不接收,仍然可以调用交换字节的时序,发送同时接收,不过不看接收到的数据即可;指向接收不发送同理,调用交换字节的时序,发送同时接收,不过会随便发送一个数据,目的是为了将从机的数据置换过来即可,读取置换后的数据就相当于接收,随意发送的数据从机并不会进行读取,不过这个随便的数据并不是真的随便,会统一发送0x00或0xff去和从机换数据。

SPI时序基本单元

         起始条件:SS从高电平切换到低电平,是左边的图,SS是低电平有效,SS从高变到低代表着选中了某一个从机,也是通信的开始

        终止条件:SS从低电平切换到高电平,是右边的图,SS从低电平变到高电平,就是结束了从机的选中状态,通信结束。

        在从机的选中的整个过程中,SS要一直保持低电平。

模式1

         这个基本单元建立在上边的移位模型上。基本单元中在上升沿开始移位还是下降沿移位SPI并没有限制死,给予可配置的选择,以兼容更多的芯片。这里SPI有两个可以配置的位,分别是CPOL(Clock Polarity时钟极性),CPHA(Clock phase时钟相位),每一位可配置为1或0,
总共组合起来有模式0、1、2、3共四种模式,模式虽多但功能一样,模式1接近于上边的知识内容。

        时序的基本内容是交换一个字节,CPOL=0代表空闲状态时SCK为低电平,在SS未被选中时SCK默认低电平;CPHA=1表示SCK第一个边沿移出数据第二个边沿移入数据。

        时序图中SS从机选择,通信开始之前SS为高电平,通信过程中SS始终保持低电平,通信结束SS恢复高电平

        最下边的MISO主机输入从机输出,多个从机连在一起,如果同时开启输出会造成冲突,解决方法是在SS未被选中的状态下,从机的MISO引脚需关断输出,即配置为高阻态输出状态,如图位于中间电平的为高阻态,SS下降沿之后从机的MISO被允许开启输出,SS上升沿之后从机的MISO必须置回高阻态。

        移位传输:因为CPHA=1,SCK第一个边沿移出数据,图中可见SCK第一个触发沿是上升沿,主机和从机同时移出数据,主机通过MOSI移出最高位,此时MISO的电平就代表了主机要发送的数据B7,从机通过MOSI移出最高位,此时MISO表示从机要发送的数据B7。时钟运行,产生下降沿,此时主机和从机同时移入数据,即进行数据采样。主机移出的B7进入从机移位寄存器的最低位,从机移出的B7进入主机移位寄存器的最低位,当一个时钟脉冲产生完毕时一个数据传输完毕,后边的数据交换同理,直到最后一个下降沿,数据B0传输完成,主机和从机完成一个字节的数据交换,如果只想交换一个字节数据,接下来就可以将SS置高电平结束通信。

        在SS的上升沿MISO还可以再进行变化,将MOSI置默认的高电平or低电平,也可以不管,因为SPI没有规定MOSI的默认电平,MISO从机必须置回高阻态。如果此时主机的MISO位上拉输入的话,那MISO的引脚就是默认的高电平,如果主机的引脚为浮空输入,那MISO的引脚电平不确定。如果主机还想进行数据交换,则不必把SS置回高电平,直接重复交换一个字节的时序即可。

模式3(与模式1对比) 

        模式1和模式3的区别,模式1的CPOL=0,模式3的CPOL=1,两者的波形区别在于SCK的极性取反,其他地方没区别。 

模式0(应用最多)

        模式0的CPHA=0,在时序上的区别在于模式0的数据移出移入的时机,会提前半个时钟,也就是相位提前。第一个边沿移入数据,第二个边沿移出数据,但是数据是需要先移出才能移入的,所以SCK在第一个边沿之前就要提前移出数据,或者说是在第0个边沿移出第一个边沿移入。

        首先SS下降沿开始通信,SCK还没有变化,但是SCK一旦开始变化就要移入数据。趁SCK还没变化,在SS下降沿时就要立刻触发移位输出,所以图中MISO和MOSI的输出是对齐到SS的下降沿,或者说SS的下降沿也被当做时钟的一部分。

        SS下降沿触发了输出,SCK上升沿就可以采样输入数据了,这样B7传输完毕。接下来SCK下降沿移出B6,SCK上升沿移入B6,后边持续下降沿移出数据上升沿移入数据,最终在第八个上升沿时B0位移入完成,整个字节交换完成。之后SCK还有一个下降沿,如果主机只需要交换一个字节就结束,那么在下降沿时MOSI可以置回低电平或者不管,MISO也会变化一次,变化的那个地方对应的是下一个字节的B7,因为相位提前了所以下一个字节的B7会提前露头,如果不需要转换多个字节的话,SS上升沿之后从机置回高阻态,交换一个字节结束。如果需要转换多个字节的话就继续调用交换字节的时序,在最后一个下降沿主机和从机都放下一个字节的B7,SCK上升沿正好接着采样第二个字节的B7,拼接上时序。

        模式0和模式1的区别在于:模式0把数据变化的时机给提前了,实际应用中模式0应用最多,后续程序均以模式0为主。

模式2(与模式0对比)

        模式2与模式0的区别在于模式0的CPOL=0,模式2的CPOL=1,两者的波形就是SCK的极性取反,剩下的流程完全一致 

总结

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

最近更新

  1. TCP协议是安全的吗?

    2024-04-04 07:58:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-04 07:58:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-04 07:58:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-04 07:58:03       18 阅读

热门阅读

  1. 【Python整理】 Python知识点复习

    2024-04-04 07:58:03       13 阅读
  2. wordvect嵌入和bert嵌入的区别

    2024-04-04 07:58:03       13 阅读
  3. 运动伤害预防的实际案例

    2024-04-04 07:58:03       14 阅读
  4. 一次Postgres的实体表重构经历

    2024-04-04 07:58:03       14 阅读
  5. 走近Shiro--一起学习吧之架构

    2024-04-04 07:58:03       13 阅读
  6. 速盾:服务器有cdn 带宽上限建议多少

    2024-04-04 07:58:03       16 阅读
  7. Go实现MapReduce

    2024-04-04 07:58:03       14 阅读
  8. Spark面试整理-讨论DataFrame和DataSet的区别

    2024-04-04 07:58:03       14 阅读
  9. 文心一言 vs GPT-4 —— 全面横向比较

    2024-04-04 07:58:03       15 阅读