单片机学习!
目录
前言
本文介绍了SPI通信,SPI通信和I2C通信差不多,两个协议的设计目的都一样,都是实现主控芯片和各种外挂芯片之间的数据交流。有了数据交流的能力,主控芯片就可以挂载并操纵各式各样的外部芯片,来实现一个功能更加强大的控制系统。
一、SPI通信
- SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线。
- 四根通信线:SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select)。
- 同步,全双工。
- 支持总线挂载多设备(一主多从)。
1.1 SPI简介
SPI它的英文全称Serial Peripheral Interface字面翻译就是串行外设接口,是Motorola公司开发的一种通用数据总线。SPI和I2C一样,都是通用数据总线。同时它们也都是用于主控和外挂芯片之间的通信,应用领域非常相似,当然,I2C和PSI两者都是各有各的优势和劣势,有的芯片更适合用I2C通信,有的芯片更适合用SPI通信。
I2C通信:
之前博文介绍的I2C通信,无论是硬件电路还是软件时序设计的都是相对比较复杂的,硬件上要配置为开漏外加上拉的模式,软件上有很多功能和要求。比如一根数据线兼顾数据收发、应答位的收发、寻址机制的设计等等,最终通过这一系列的设计就使得I2C通信的性价比非常高。I2C可以在消耗最低硬件资源的情况下实现最多的功能。
- I2C在硬件上,无论挂载多少个设备,都只需要两根通信线。
- I2C在软件上,数据双向通信、应答位都可以实现。
如果把通信协议比作是一个人的话,那I2C就属于精打细算、思维灵活这类型的人。I2C既要实现硬件上最少的通信线,又要实现软件上最多的功能,最终I2C通过精心的设计也确实实现了这么多功能。用一个词形容的话就是非常优雅,
当然在优雅之中也隐藏了一个缺点,由于I2C开漏外加上拉电阻的电路结构,使得通信线高电平的驱动能力比较弱,这就会导致,通信线由低电平变道高电平的时候上升沿耗时比较长,这会限值I2C的最大通信速度,所以I2C的标准模式只有100KHz的时钟频率,I2C的快速模式也只有400KHz的时钟频率。虽然I2C协议之后又通过改进电路的方式设计出了高速模式,可以达到3.4MHz,但是高速模式目前普及程度不是很高,所以一般情况下认为I2C的时钟速度最多就是400KHz,I2C的这个速度相比较SPI而言还是慢了很多。
以上是I2C的优势和缺点,下面来看一下SPI相对于I2C的优缺点。
SPI通信:
首先SPI传输更快,SPI协议并没有严格规定最大传输速度,最大传输速度取决于芯片厂商的设计需求。比如说W25Q64存储器芯片,手册里写的SPI时钟频率最大可达80MHz,这比STM32F1的主频还要高。其次,SPI的设计比较简单粗暴,实现的功能没有I2C那么多,所以学习起来SPI比I2C简单很多。最后,SPI的硬件开销比较大,通信线的个数比较多,并且通信过程中经常会有资源浪费的现象。
如果继续把通信协议比作是一个人的话,那SPI就属于富家子弟、有钱任性这类型的人。SPI不在乎花了多少钱,只在乎任务有没有最简单、最快速的完成。这就是SPI的风格。
1.2 SPI四根通信线
SPI有四根通信线,分别是:
- SCK全称意思是串行时钟线;
- MOSI意思是主机输出从机输入;
- MISO意思是主机输入从机输出;
- SS意思是从机选择。
以上是SPI通信典型的引脚名称,当然在实际情况下,这些名称可能会有别的表述方式。
比如:
- SCK有的地方可能叫做SCLK、CLK、CK;
- MOSI和MISO有的地方可能直接叫做DO(Data Output)和DI(Data Input);
- SS有的地方可能叫做NSS(Not Slave Select)、CS(Chip Select)。
这些不同的名称都是一个意思。本文以SPI官方文档的名称为准。
SPI的这4个引脚的意义和作用可以继续往下看,从SPI的基本特性来分析。
1.3 SPI基本特性
SPI的基本特性是,同步,全双工。
首先既然是同步时序,肯定就得有时钟线,所以SCK引脚就是用来提供时钟信号的。数据位的输出和输入都是在SCK的上升沿或下降沿进行的,这样数据位的收发时刻就可以确定。并且同步时序,时钟快点慢点或者中途暂停一会儿都是没问题的,这就是同步时序的好处。对照I2C总线,SPI的SCK就相当于I2C的SCL,两者作用相同。
SPI是全双工的协议,全双工就是数据发送和数据接收这两者单独各占一条线,发送用发送的线路,接收用接收的线路两者互不影响。所以MOSI和MISO就是分别用于发送和接收的两条线路。
MOSI线是主机输出从机输入。
- 如果是主机接在这条线上,那就是MO主机输出;
- 如果是从机接在这条线上,那就是SI从机输入。
意思就是一条通信线,如果主机接在上面配置为输出,那从机肯定得配置为输入才能接收主机的数据,主机和从机不能同时配置为输出或输入,要不然就没法通信了。
- 所以这条MOSI就是主机向从机发送数据的线路。
- 同理MISO就是主机从从机接收数据的线路。
这就是全双工通信的两根通信线。SPI的MOSI和MISO这两根通信线加在一起就相当于I2C总线的SDA,当然I2C是一根线兼具发送和接收的是半双工。SPI是一根发送一根接收是全双工,全双工的好处就是简单高效,输出线就一直输出,输入线就一直输入。数据流的方向不会改变,也不用担心发送和接收没协调好冲突了。 全双工的坏处就是多了一根线会有通信资源的浪费。
1.4 一主多从
支持总线挂载多设备,使用的是一主多从的模型。SPI仅支持一主多从不支持多主机。这一点SPI从功能上没有I2C强大。
I2C实现一主多从的方式是在起始条件之后主机必须先发送一个字节进行寻址。用来指定要跟哪个从机进行通信,所以I2C要涉及分配地址和寻址的问题。
SPI则是再开辟一条通信线专门用来指定要跟哪个从机进行通信,所以这条专门用来指定从机的通信线就是SS从机选择线。并且SS可能不止一条,SPI的主机表示有几个从机就开几条SS,所有从机一人一根,主机需要找从机的时候就控制接到这个从机的那一根SS线,给个低电平就说明要找这个从机通信;给个高电平就说明不找这个从机通信。那这样指定从机的操作就简单多了,不需要分配地址、先发一个字节寻址的操作。
SPI实现一主多从指定从机的方式好处就是方便,坏处就是得加线。
SPI没有应答机制的设计,发送数据就发送,接收数据就接收,至于对面是不是存在,SPI是不管的。
二、SPI硬件电路
- 所有SPI设备的SCK、MOSI、MISO分别连在一起。
- 主机另外引出多条SS控制线,分别接到各从机的SS引脚。
- 输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入。
硬件电路图:
上图就是SPI一个典型的应用电路:
- 左边是SPI主机,主导整个SPI总线,主机一般都是控制器来做,比如STM32。
- 图下方SPI从机1、2、3就是挂载在主机上的从设备了,比如存储器、显示屏、通信模块、传感器等等。
- 左边SPI主机实际上引出了6根通信线,因为有3个从机,所以SS线需要3根,再加SCK、MOSI、MISO就是6根通信线。
当然SPI所有通信线都是单端信号,它们的高低电平都是相对GND的电压差,所以单端信号,所有的设备还需要共地。图中GND的线没画出来,但是是必须要接的。如果从机没有独立供电的话,主机还需要再额外引出电源正极VCC给从机供电。所以两根电源线VCC和GND也要注意接好。
2.1 通信线:
SCK时钟线,时钟线完全由主机掌控,所以对于主机来说,时钟线为输出;对于所有从机来说时钟线都为输入。这样主机的同步时钟就能送到各个从机了。
MOSI主机输出从机输入,这里左边是主机,所以就对应MO主机输出,下方三个都是从机,所以就对应SI,从机输入。数据传输方向是主机通过MOSI输出,所有从机通过MOSI输入。
MISO主机输入从机输出,左边是主机对应MI,下方三个从机对应SO。数据传输方向是三个从机通过MISO输出,主机通过MISO输入,那到这里SCK、MOSI、MISO的连接方式就介绍完了。
所有SPI设备的SCK、MOSI、MISO分别连在一起。就如图中所示,所有的SCK连在一起,所有的MOSI连在一起,所有的MISO连在一起。每条线的数据传输方向在图中都用箭头标出来了。
2.2 从机选择
时钟和数据传输介绍完了接下来就是从机的选择问题了,为了确定通信的目标,主机就要另外引出多条SS控制线,分别接到各从机的SS引脚。
图中有三个从机,就需要在主机另外引出3根SS选择线,分别接到每个从机的SS输入端。
- 主机的SS线都是输出,
- 从机的SS线都是输入。
SS线是低电平有效,主机想指定谁,就把对应的SS输出线置低电平就行了。
比如,主机初始化之后,所有的SS都输出高电平,这样就是谁也不指定。
当主机需要和从机1进行通信了,主机就把SS1线输出低电平,这样从机1就知道主机在找自己,然后主机在数据引脚进行的传输就只有从机1会响应,其他从机的SS线是高电平,所以它们都会保持沉默。
当主机和从机1通信完成之后,就会把SS1置回高电平。这样从机1就知道主机结束了从机和主机的通信。
之后主机需要和从机2和从机3通信时也是同理,需要找谁通信就置谁的SS为低电平。当然同一时间主机只能置一个SS为低电平,只能选中一个从机。如果主机同时选中多个从机就会导致数据冲突。
以上就是SPI实现选择从机的方式,不需要像I2C一样进行寻址。
2.3 SPI引脚配置
SPI引脚的配置:输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入。在图中输出引脚和输入引脚都用箭头标出来了。
对于输出配置推挽输出,推挽输出高低电平均有很强的驱动能力,这将使得SPI引脚信号的下降沿非常迅速,上升沿也非常迅速。不像I2C那样,下降沿非常迅速,但是上升沿就比较缓慢了。得益于推挽输出的驱动能力,SPI信号变化的快,那自然就能达到更高的传输速度,一般SPI信号都能轻松达到MHz的速度级别。
这里I2C并不是不想使用更快的推挽输出,而是I2C要实现半双工,经常要切换输入输出,另外I2C又要实现多主机的时钟同步和总线仲裁,这些功能都不允许I2C使用推挽输出,要不然一不小心就电源短路了。所以I2C选择了更多的功能自然就要放弃更强的性能了。
对于SPI来说,首先SPI不支持多主机,SPI又是全双工,SPI的输出引脚始终是输出,输入引脚始终是输入,基本不会出现冲突,所以SPI可以大胆的使用推挽输出。不过SPI其实还是有一个冲突点的,就是图中的MISO引脚,在这个引脚上可以看到,主机一个是输入,但是三个从机全都是输出,如果三个从机都始终是推挽输出,势必会导致冲突。
所以在SPI协议里,有一条规定,当从机的SS引脚为高电平,也就是从机未被选中时,它的MISO引脚必须切换为高阻态,高阻态就相当于引脚断开,不输出任何电平,这样就可以防止一条线有多个输出而导致的电平冲突问题了。在SS为低电平时,MISO才允许变为推挽输出,这就是SPI对这个可能的冲突做出的规定。当然这个切换过程都是在从机里,一般写主机的程序并不需要关注这个问题。以上就是SPI的硬件电路。
三、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,会采样输入到主机这里的最低位。
上图就是第一个时钟结束后的现象。
时钟继续运行,下一个上升沿同样的操作,移位输出,
- 主机现在的最高位也就是原始数据的次高位输出到MOSI;
- 从机现在的最高位也是原始数据的次高位输出到MISO。
随后下降沿,数据采样输入。
- MISO数据到从机移位寄存器最低位;
- MISO数据到主机移位寄存器最低位。
之后时钟继续运行,第三个时钟开始,上升沿移位,主机输出,从机输出;
下降沿采样,主机输入,从机输入。
之后第四个时钟、
第五个时钟等等一直到第八个时钟都是同样的过程。
最终八个时钟之后,
- 原来主机里的10101010跑到从机里了;
- 原来从机里的01010101跑到主机里了。
这就实现了主机和从机一个字节的数据交换。
实际上SPI的运行过程就是这样,SPI的数据收发都是基于字节交换,这个基本单元来进行的。
当主机需要发送一个字节,并且同时需要接收一个字节时就可以执行一下字节交换的时序。
- 这样主机要发送的数据跑到从机;
- 主机要从从机接收的数据跑到主机。
这就完成了发送同时接收的目的。
如果只想发送不想接收,仍然调用交换字节的时序,发送同时接收,只是接收到的这个数据不看就可以了。
如果只想接收不想发送,还是调用交换字节的时序,发送同时接收,只是会随便发送一个数据,只要能把从机的数据置换过来就行了,读取置换过来的数据不就是接收了嘛。
这里随便发送过去的数据从机也不会去看它,当然这个随便的数据不会真的随便发,一般在接收的时候会统一发送0x00或0xFF去跟从机换数据。
SPI基本原理总结:
SPI通信的基础是交换一个字节,有了交换一个字节就可以实现,发送一个字节、接收一个字节和发送一个字节同时接收一个字节这三种功能。可以看出SPI在只执行发送或只执行接收的时候会存在一些资源浪费现象。不过全双工的通信本来就会有浪费的情况发生。
分析完移位示意图再看一下上文的硬件电路,是不是SCK、MISO、MOSI这三个引脚的功能就很容易理解了,另外再加几根SS从机选择线就是SPI通信了。
四、SPI时序基本单元
4.1 SPI的起始和终止
起始条件是SS从高电平切换到低电平,如图所示。SS是低电平有效,SS从高变到低就代表刚选中某个从机了,这就是通信的开始。
终止条件是SS从低电平切换到高电平,如图所示。SS从低电平变到高电平就是结束了从机的选中状态,就是通信的结束。
那在从机的整个选中状态中,SS要始终保持为低电平,
就是SS低电平选中,高电平未选中。
那低电平期间就代表正在通信,
下降沿是通信的开始,上升沿是通信的结束。
SPI的这一点相比较I2C还是简单很多。
4.2 数据传输的基本单元
4.2.1 模式0
- 交换一个字节(模式0).
- CPOL=0:空闲状态时,SCK为低电平。
- CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据。
数据传输的基本单元就是建立在上文所说的移位模型上的,并且这个基本单元什么时候开始移位,是上升沿移位还是下降沿移位,这些SPI并没有限定死,给了可配置的选择。这样设计的好处是SPI可以兼容更多的芯片。
在这里SPI有两个可以配置的位,分别叫做CPOL(Clock Polarity)时钟极性和CPHA(Clock Phase)时钟相位。每一位可以配置为1或0,总共组合起来就有模式0、模式1、模式2、模式3这四种模式。当然模式虽然多,但是它们的功能都是一样的,在实际使用的时候主要学习其中一种就可以了,剩下的模式,知道有这些东西可以配置,到需要用的时候再看一下即可。
先看一下模式1,这个模式和上文中的移位模型是对应的。模式1时序的基本功能是交换一个字节,也就是移位示意图中所展示的现象。
CPOL=0表示空闲状态时,SCK为低电平,时序图中可以看到在SS未被选中时,SCK默认是低电平的。
CPHA=1表示SCK第一个边沿移出数据,第二个边沿移入数据。当然这句话也有不同的描述方式,有的地方写的是CPHA=1表示SCK的第二个边沿进行数据采样,或者是SCK的偶数边沿进行数据采样,这些不同的描述意思都一样。
看一下时序图:
最上面第一个波形SS从机选择,
- 在通信开始前,SS为高电平;
- 在通信过程中,SS始终保持低电平;
- 通信结束,SS恢复高电平。
最下面MISO主机输入从机输出,在硬件电路中,因为有多个从机输出MISO连在了一起,如果同时开启输出会造成冲突,所以在SS未被选中的状态,从机的MISO引脚必须关断输出,即配置输出为高阻状态。
在时序图中里可以看到:SS高电平时MISO用一条中间的线表示高阻态。
- SS下降沿之后,从机的MISO被允许开启输出;
- SS上升沿之后,从机的MISO必须置回高阻态。
接下来看一下移位传输的操作,因为CPHA=1,SCK第一个边沿移出数据,所以在时序图可以看出,SCK第一个边沿就是上升沿,主机和从机同时移出数据,
- 主机通过MOSI移出最高位,此时MOSI的电平就表示了主机要发送数据的B7;
- 从机通过MISO移出最高位,此时MISO表示从机要发送数据的B7。
然后时钟运行,产生下降沿,此时主机和从机同时移入数据,也就是进行数据采样。
- 主机移出的B7进入从机移位寄存器的最低位;
- 从机移出的B7进入主机移位寄存器的最低位。
这样,一个时钟脉冲产生完毕,一个数据位传输完毕,接下来就是同样的过程,上升沿主机和从机同时输出当前移位寄存器的最高位。第二次的最高位就是原始数据的B6,然后下降沿,主机和从机移入数据,B6传输完成。之后时钟继续运行,数据依次移出、移入、移出、移入……,最后一个下降沿,数据B0传输完成。至此,主机和从机就完成了一个字节的数据交换。
如果主机只想交换一个字节,那这时就可以置SS为高电平,结束通信了。在SS的上升沿,MOSI还可以再变化一次,将MOSI置到一个默认的高电平或低电平,当然也可以不去管它,因为SPI也没有硬性规定MOSI的默认电平。但是MISO从机必须得置回高阻态,此时如果主机的MISO为上拉输入的话,那MISO引脚的电平就是默认的高电平。如果主机MISO为浮空输入,那MISO引脚的电平不确定。这是交换一个字节就结束的流程。
如果主机还想继续交换字节,在一个字节传输结束后主机就不必把SS置回高电平了,时序再重复一次SS下降沿到SS上升沿的内容,就又多交换了一个字节的时序,这一段时序多重复几次就可以交换多个字节,在所有字节都交换结束后再给SS置高电平。这就是SPI传输数据的流程,和上文的移位流程是对应的。
4.2.2 模式1
- 交换一个字节(模式1)
- CPOL=0:空闲状态时,SCK为低电平
- CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据
模式0和模式1的区别就是模式0的CPHA=0,模式1的CPHA=1。
对比一下时序上的区别,模式0的数据移出移入的时机会提前半个时钟,也就是相位提前了。模式0,CPHA=0,表示SCK第一个边沿移入数据,第二个边沿移出数据。模式0在SCK第一个边沿就要移入数据,但是数据总得先移出才能移入,所以在模式0的配置下,SCK第一个边沿之前,就要提前开始移出数据了。或者可以说模式0是在SCK第0个边沿移出,第1个边沿移入。
看模式0时序图:
首先SS下降沿开始通信,这时SCK还没有变化,但是SCK一旦开始变化,就要移入数据了。此时趁SCK还没有变化,SS下降沿时就要立刻触发移位输出。所以这个时刻MOSI和MISO的输出是对齐到SS的下降沿的,或者说这里把SS的下降沿也当做时钟的一部分了,
那SS下降沿出发了输出,SCK上升沿就可以采样输入数据了,这样B7就传输完毕。
之后SCK下降沿移出B6;SCK上升沿移入B6。
然后继续,下降沿移出数据;上升沿移入数据。
最终在第8个上升沿时,B0位移入完成,整个字节交换完成。
之后SCK还有一个下降沿,如果主机只需要交换一个字节就结束,那在这个下降沿时MOSI可以置回默认电平或者不去管它。MISO也会变化一次,这一位实际上是下一个字节的B7,因为这个相位提前了,所以下一个字节的B7会露个头,如果不需要的话,SS上升沿之后,从机MISO置回高阻态,这时交换一个字节就结束。
如果主机想交换多个字节的话,那就继续调用从SS下降沿到SS上升沿的时序,在最后一个下降沿,主机放下一个字节B7,从机也放下一个字节的B7,到SCK上升沿时,正好接着采样第二个字节的B7,这样时序才能拼接的上。这就是SPI交换一个字节模式0,模式0和模式1的区别在于,模式0把数据变化的时机给提前了,在实际应用中,模式0的应用是最多的,所以需要重点掌握模式0.
4.2.3 模式2
- 交换一个字节(模式2)
- CPOL=1:空闲状态时,SCK为高电平
- CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据
模式0和模式2的区别:模式0的CPOL=0;模式2的CPOL=1。两者的波形就是SCK的极性取反一下,剩下的流程上的东西完全一致。
4.2.4 模式3
- 交换一个字节(模式3)
- CPOL=1:空闲状态时,SCK为高电平
- CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据
模式1和模式3的区别:模式1的CPOL=0;模式3的CPOL=1。模式1和模式3两者的波形也是SCK的极性取反一下,其他地方没有变化。
注意:
CPHA表示的是时钟相位,决定是第一个时钟采样移入还是第二个时钟采样移入,并不是规定上升沿采样还是下降沿采样的。当然在CPOL确定的情况下,CPHA确实会改变采样时刻的上升沿和下降沿。比如:
- 模式0的时候,是SCK上升沿采样移入;
- 模式1的时候是SCK下降沿采样移入。
CPHA决定是第几个边沿采样,并不能单独决定是上升沿还是下降沿。
在SPI的4种模式里:
- 模式0和模式3都是SCK上升沿采样;
- 模式1和模式2都是SCK下降沿采样。
以上就是时序基本单元。
五、SPI时序波形图
SPI完整时序波形,每个芯片对SPI时序字节流功能的定义不一样,本文是以芯片W25Q64的时序为例进行讲解。
SPI对字节流功能的规定不像I2C那样,
- I2C的规定一般是有效数据流第一个字节是寄存器地址,之后依次是读写的数据,使用的是读写寄存器的模型。
- SPI中通常采用的是指令码加读写数据的模型,这个过程就是SPI起始后第一个交换发送给从机的数据一般叫作指令码。在从机中对应的会定义一个指令集。
SPI在需要发送指令时,就可以在起始后第一个字节发送指令集里面的数据,这样就能指导从机完成相应的功能了。不同的指令可以有不同的数据个数,
有的指令只需要一个字节的指令码就可以完成,比如W25Q64的写使能、写失能等指令。
而有的指令后面就需要再跟要读写的数据,比如W25Q64的写数据、读数据等。
- 写数据指令后面就得跟上要在哪里写,要写什么的内容;
- 读数据指令后面就得跟上要在哪里读,读到的是什么的内容。
这就是指令码加读写数据的模型。在SPI从机的芯片手册里都会定义好指令集,什么指令对应什么功能,什么指令后面得跟上什么数据。
下面是简单抓取了几个指令的波形图,来分析一下。
5.1 发送指令
- 发送指令
- 向SS指定的设备,发送指令(0x06)
首先是SPI发送指令,这个时序的功能是,向SS指定的设备发送指令0x06,指令0x06具体的意思可以由芯片厂商自己规定,在W25Q64芯片里指令0x06代表的是写使能。
看一下波形图,这里使用的是SPI模式0:
在空闲状态时,
- SS为高电平,
- SCK为低电平,
- MOSI和MISO的默认电平没有严格的规定。
当SS产生下降沿,时序开始,
在这个SS的下降沿时刻,MOSI和MISO就要开始变换数据了。MOSI由于指令码最高位仍然是0,所以这里保持低电平不变;
MISO从机现在没有数据发给主机,引脚电平没有变换,实际上W25Q64不需要回传数据时手册里规定的MISO仍然是高阻态,从机并没有开启输出,不过波形图这样也没问题,因为这个数据不需要管。这里因为STM32的MISO是上拉输入,所以这里MISO呈现高电平。
之后SCK第一个上升沿进行数据采样,图中画了一条绿色竖直线,
- 从机采样输入得到0;
- 主机采样输入得到1。
之后继续,第二个时钟主机数据位仍然是0,所以波形仍然没有变化。
然后这样一位一位地发送、接收、发送、接收,一直到中间也就是第6位的这一位数据才开始变化,
主机要发送数据1,SCK下降沿,数据移出,
主机将1移出到MOSI,MOSI变为高电平,
抓取的波形图因为是软件模拟的时序,所以MOSI的数据变化有些延迟,没有紧贴SCK的下降沿,不过在运行逻辑上也没问题,时钟是主机控制的,只要在下一个SCK上升沿之前完成变化就行了。
然后在SCK上升沿时数据采样输入。
在最后一位,
- SCK下降沿,数据变化,MOSI变为0;
- SCK上升沿,数据采样,从机接收数据0。
SCK低电平是变化的时期,高电平是读取的时期。这一点和I2C差不多。时序SCK最后一个上升沿结束,一个字节就交换完毕了。
因为写使能是单独的指令,不需要跟随数据,SPI只需要交换一个字节就完事了。所以最后,在SCK下降沿之后,SS置回高电平,结束通信。
在这个交换中统计一下MOSI和MISO的电平,总结一下就是主机用0x06换来了从机的0xFF,当然实际上从机并没有输出,0xFF是默认的高电平,这个0xFF没有意义,不用管。那整个时序的功能就是发送指令,指令码是0x06。从机一比对事先定义好的指令集,发现0x06是写使能的指令,那从机就会控制硬件进行写使能,这样一个指令从发送到执行就完成了。这就是发送单字节指令的时序。
5.2 指定地址写时序
- 指定地址写
- 向SS指定的设备,发送写指令(0x02),随后在指定地址(Address[23:0])下,写入指定数据(Data)
指定地址写指令,功能是向SS指定的设备先发送写指令,写指令在指令集中规定是0x02,随后在指定地址下写入指定数据。
因为W25Q64芯片有8M字节的存储空间,一个字节的8位地址肯定不够,所以这里地址是24位的,分3个字节传输。
看一下时序图:
首先SS下降沿,开始时序,这里MOSI空闲时是高电平,所以在SS下降沿之后,SCK第一个时钟之前可以看到,MOSI变换数据,由高电平变为低电平。
然后SCK上升沿,数据采样输入。后面还是一样,下降沿变换数据,上升沿采样数据。8个时钟之后,一个字节交换完成。用0x02换来了0xFF,
其中:
- 发送的0x02是一条指令,代表这是一个写数据的时序;
- 接收的0xFF不需要看。
因为是写数据的时序,后面必然还要跟着写的地址和数据了,后续还要继续交换字节,所以在SS最后一个下降沿时刻,要把下一个字节的最高位放到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写入的时序。
由于SPI没有应答机制,所以交换一个字节后就立刻交换下一个字节就行了。
在这条指令上还可以看出,由于整个流程只需要发送的功能,并没有接收的需求,所以MISO这条接收的线路就始终处于挂机的状态,并没有用到。这就是SPI指定地址写的逻辑,当然不同的芯片肯定有不同的规定。举例芯片存储器的容量大,所以需要连续指定3个字节的地址。如果容量小的话可能一个字节的地址就够了,或者有的芯片会直接把地址给融合到指令码里去。至于具体的操作还是要仔细分析一下手册。
5.3 指定地址读时序
- 指定地址读
- 向SS指定的设备,发送读指令(0x03), 随后在指定地址(Address[23:0])下,读取从机数据(Data)
指定地址读时序功能是向SS指定的设备,先发送读指令,这里芯片定义0x03为读指令,随后在指定地址下读取从机数据。
时序的运行逻辑和之前都一样,主要看一下交换的数据。起始之后第一个字节,主机发送0x03,代表要读取数据了。
之后还是一样,主机再依次交换3个字节,分别是0x12、0x34、0x56,组合到一起就是0x123456,代表24位地址。
读取地址之后的地方就是关键点了,因为是读取数据,指定地址之后就要开始接收数据。所以在3个字节地址交换完之后,要把从机的数据接收过来,还是交换一个数据,来个抛砖引玉。随便给从机一个数据,一般给FF,这时从机就会把0x123456地址下的数据通过MISO发送给主机。可以看到波形图中表示指定地址下的数据就是0x55。
这样主机就实现了指定地址读一个字节的目的。之后如果继续抛砖引玉,那么从机内部的地址指针自动加1,从机就会继续把指定地址下一个位置的数据发过来,这样依次进行就可以实现指定地址接收多个字节的目的了。
最后,数据传输完毕,SS置回高电平,时序结束。
当然时序也会有一些细节。比如,由于MISO是硬件控制的波形,所以它的数据变化都可以紧贴时钟下降沿。
另外可以看到,MISO数据的最高位实际上是在上一个字节最后一个下降沿时提前发生的。因为这时SPI模式0,所以数据变化都要提前半个周期。
以上就是W25Q64规定的读时序了。
总结
以上就是今天要讲的内容,本文仅仅简单介绍了SPI协议的软硬件规定。