SPI通信
SPI通信概述
SPI(Serial Peripheral Interface)由摩托摩拉公司开发的通用数据总线。支持总线挂在多设备(一主多从),同步全双工。
IIC和SPI的优劣势:
IIC开漏外加上拉电阻的电路结构,使得通信线高电平的驱动能力比较弱,就会导致通信线由低电平向高电平跳变的时候,这个上升沿耗时比较长,会限制IIC的最大通信速度。但消耗硬件资源少。
SPI的硬件开销比较大,通信线的个数比较多,并且通信过程中,经常会有资源浪费的现象。但通信速度快。
SCK | 串行时钟线 | SCLK、CLK、CK |
MOSI | 主机输出从机输入 | DO Data Output |
MISO | 主机输入从机输出 | DI Data Input |
SS 从机选择 | NSS Not SlaveSelect | CS Chip Select |
同步时序好处:数据位的输出和输入,都是在SCK的上升沿和下降沿进行的,数据位的收发时刻可以明确确定,并且,同步时序,时钟快一点慢一点,或者中途暂停一会儿,都没有问题。
主机和从机不能同时配置为输出或输入。数据流的方向不会改变,不用担心发送和接收没协调好冲突了,不支持多主多从,SPI是专门用一条通信线用来指定要和哪个从机进行通信,SS从机选择线,有几个从机,就可开几条SS线。
所有SPI设备的SCK、MOSI、MISO分别接到一起。输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入。
时钟线由主机控制,SS是低电平有效。
基本收发电路
SPI通信的基础是交换一个字节:移位示意图是SPI硬件电路设计的核心,只要把移位示意图搞懂了,那无论是上面的硬件电路,还是我们等会学习的软件时序。
SPI的基本收发电路:移位模型,左边是SPI主机,里面有一个8为的移位寄存器,右边是SPI从机,里面也有一个8位移位寄存器,这里移位寄存器有一个时钟输入端,因为SPI一般是高位先行的,所以,每来一个时钟,移位寄存器都会向左进行移位,从机中的移位寄存器也是同理。
波特率发生器时钟的上升沿,所有移位寄存器向左移动一位,移出去的位放到引脚上,波特率发生器时钟的下降沿,引脚上的位,采样输入到移位寄存器的最低位。主机移位寄存器左边移出的数据,通过MOSI引脚,输入到从机移位寄存器的右边,从机移位寄存器左边一出去的数据,通过MISO,输入到主机移位寄存器的右边。
举例(按模式1分析):假设主机有数据10101010要发送到从机,同时,从机有数据01010101要发送到主机。先产生一个上升沿,那从最高位移出去的数据,向左移动一次,那最高位移出去的数据,就会放到通信线上,实际上是放到了输出数据寄存器,此时MOSI数据是1,所以MOSI的电平就是高电平,MISO的电平就是低电平,这就是第一个时钟上升沿执行的结果。上升沿之后,下一个边沿就是下降沿,在下降沿时,主机和从机内,都会进入数据采样输入,也就是MOSI的1,会采样输入到从机这里的最低位,MISO的0会采样输入到主机这里的最低位,这就是第一个时钟结束后的现象。一直到第8个时钟,都是同样的过程,实现了主机和从机一个字节的数据交换,实际上,SPI的运行过程就是这样,SPI数据的收发,都是基于字节交换,这个基本单元来进行的,当主机需要发送一个字节,并且同时需要接收一个字节时,这样,主机要发送的数据跑动从机,主机要从从机接收的数据,跑到主机。
只想发送,不想接收:接收到的数据,我们不去看它。
只想接收,不想发送:理论上随便发,实际上统一发送0x00或0xFF,去跟从机交换数据。
起始条件和终止条件
SPI有两个可以配置的位:CPOL(Clock Polarity)时钟极性和CPHA(Clock Phase)时钟相位。
模式0 CPOL=0 CPHA=0 | 空闲状态时,SCK为低电平; SCK第一个边沿移入数据,第二个边沿移出数据 |
模式1 CPOL=0 CPHA=1 | 空闲状态时,SCK为低电平; SCK第一个边沿移出数据,第二个边沿移入数据 |
模式2 CPOL=1 CPHA=0 | 空闲状态时,SCK为高电平; SCK第一个边沿移入数据,第二个边沿移出数据 |
模式3 CPOL=1 CPHA=1 | 空闲状态时,SCK为高电平; SCK第一个边沿移出数据,第二个边沿移入数据 |
模式0的数据移入的时机,会提取半个时钟,在SS下降沿时,立刻出发移位输出,所以这里MOSI和MISO的输出是对齐到SS的下降沿的,或者说把SS的下降沿当作时钟的一部分了。模式1虽然感觉更合理,但实际应用中模式0的应用是最多的。
SS高电平时,MISO用一条中间的线,表示高阻态。SS下降沿之后,从机的MISO被允许开启输出,SS上升沿之后,从机的MISO必须置回高阻态。
SPI时序
发送指令
向SS指定的设备,发送指令(0x06)。IIC一般规定,有效数据流第一个字节是寄存器地址,之后是读写的数据,而在SPI通信中,通常采用的是指令码加读写数据的模型,这个过程就是,SPI起始后,第一个交换发送给从机的数据,在从机中,对应会定义一个指令集,就可以在起始后第一个字节,发送指令集里面的数据,这样就能指导从机完成相对应的功能了,不同的指令,可以有不同的数据个数,有的指定只需要一个字节的指令码就可以完成,有的就需要再跟要读写的数据,都会定义好指令集,什么指令对应什么功能,后面跟上什么数据。这些可以由芯片厂商自己规定。
指定地址写
向SS指定的设备,发送写指令(0x02)。随后在指定地址下(Address[23:0]),写入指定数据。
指定地址读
向SS指定的设备,发送读指令(0x03)。随后在指定地址下(Address[23:0]),读取从机数据。
W25Q64
双重SPI和四重SPI的意思:一个SCK时钟,可同时发送或接收2位数据,这就是双重SPI,相比较一位一位的普通SPI,所以这里写的是,在双重SPI模式下,等效的时钟频率就是80MHz的二倍,就是160MHz,等效的时钟频率就是80MHz的二倍,就是160MHz,但实际的SCK频率,最大还是80MHz,只是一个时钟发两位,然后四重SPI模式,就是一个时钟发送或接收4位了。
硬件电路
这个芯片除了SPI通信引脚,WP写保护和HOLD。如果不需要按照数据手册设置为常规态。
WP(Write Protect)写保护低电平有效,保护住,不让写。
HOLD低电平有效,如果进行正常读写时,突然产生中断,然后想用SPI通信线去操控其他器件,这时如果把CS置回高电平,那时序就终止了,但如果又不想终止总线,又想操作其他器件,这就可以HOLD引脚置低电平,这样芯片就HOLD住了,芯片释放总线,但是芯片时序也不会终止,它会记住当前的状态,当你操作完其他器件时,可以回过来,HOLD置回高电平,然后继续HOLD之前的时序,相当于SPI总线进了一次中断,并且在中断里,还可以用SPI干别的事情,这就是HOLD的功能。
W25Q64框图
W25Q64,容量是8MB,如果不进行划分,而只按照一整块来使用的话,那一整块的容量就太大了,不利于管理,而且后续涉及到Flash擦除或者写入的时候,都会有个基本单元,我们得以这个基本单元为单位进行,所以这里一整块大蛋糕,8MB的存储空间,就有必要进行一些合理的划分,那常见的划分方式:一整块存储空间,先划分为若干的块Block,其中每一块都再划分为若干的扇区Sector,对于每个扇区,内部又可以分成很多页Page,
W25Q64的划分,在这一整个矩形空间里,是所有的存储器,存储器以字为单位,每个字节都有唯一的地址,之前说W25Q64的地址宽度是24位,3个字节,所以可以看到左下角第一个字节,它的地址是 0000 00h ,h代表16进制,直到最后一个字节,地址是7FFF FF h,那最后一个字节为什么是7F开头,不是FF开头呢,因为24位地址,最大寻址范围是16MB,我们这个芯片只有8MB,所以地址空间,我们只用了一半,8MB的空间,排到最后一个字节,就是7FFF FF,那这整个地址空间,从0000 00到7FFF FF,然后在这个整个空间里,我们以64KB为一个基本单元,把它划分成若干的块Block,从前往后,依次是块0,块1,块2,等等等等,一直分到最后一块,那整块蛋糕是8MB,以64KB为一块进行划分。最后分得的块数就是8MB/64KB,得128块。
观察一下地址变化规律,比如块0起始地址是0000 00,结束地址是 00FF FF,在每一块内,它的地址变化范围就是低位的2个字节,每个块的起始是 xx 0000,结束是 xx FFFF ,这时块内地址的变化规律,了解一下,还要对每一块进行更细的划分,分为多个扇区Sector,在每一块里,再以4KB为一个单元,进行切分,观察一下地址规律,可以发现,每个扇区内地址范围是 xx x000- xx xFFF,这就是对每一块,再细分为16个扇区的分配方式,当然地址划分,到扇区就结束了,但是当我们写入数据时,还会有个更细的划分,就是这个页Page,当然你也可以把它看作,在扇区里,再进行划分,都是一样,那页的大小,就是256个字节,能分成16页,页的地址规律, 地址变化 xx xx00-xx xxFF ,在一页内的地址变化,仅限于地址的最低一个字节。
一个存储器,首先划分为若干块,对于每个块,又划分为若干扇区,然后对于整个空间,会划分为很多页,每页256个字节。
存在一个高电压生成器,这个是配合Flash进行编程的,因为Flash是掉电不丢失的,要让芯片有掉电也不丢失的状态,一般都需要一个比较高的电压去刺激它,所以这种掉电不丢失的存储器,一般都需要一个高压源,一般芯片内部集成了高电压发生器。
然后下面有一个字节地址锁存/计数器,这两个地址锁存和计数器,就是用来指定地址的,因为一页是256个字节,所以一页内的字节地址,就取决于最低的一个字节,而高位的2个字节,就对应的是页地址,所以在这里发的3个字节地址,前两个字节,会进到这个页地址锁存计数器里,最后一个字节,会进到这个地址锁存计数器里,然后页地址,通过这这个写保护和行解码,来选择我要操作哪一页,字节地址,通过这个列解码和256字节页缓存,来进行指定字节的读写操作,那又因为我们这个地址锁存,都是有一个计数器的,所以这个地址指针,在读写之后,可以自动加1,这样就很容易实现从指定地址开始,连续读写多个字节的目的了,那最后这里,由256字节的页缓存区,它其实是一个256字节的RAM存储器,就是通过这个RAM缓存区来进行的,我们写入数据,会先当道缓存区里,芯片再将缓存区的数据复制到对应的Flash里,为啥要弄一个缓存区呢,直接往Flash里写不好吗,那是因为,我们的SPI写入的频率是非常高的,而Flash的写入,由于需要掉电不丢失,留下刻骨铭心的印象,他就比较慢,你写入的数据,我先放在页缓存区里存着,因为缓存区是RAM,所以它的速度非常快,可以跟上SPI总线的速度,但是这里有个小问题,就是缓存区只有256个字节,,写入的时序有个限制条件,就是写一个时序,连续写入的数据量,不能超过256字节,,然后等你写完了,我芯片再慢慢把数据从缓存区转移到Flash存储器里,那我数据从缓存区转到Flash里,需要一定时间,,所以再写入时序结束后,芯片会进入一段忙的状态,通往状态寄存器,给状态寄存器的BUSY位置1,表示芯片当前正在搬砖,很忙,那在忙的时候,芯片就不会响应新的读写时序了,这就是写入的执行流程。
然后我们读取数据呢,虽然这里画的,应该也会通过缓存区来读取,但是由于读取,只要看一下电路的状态就可以了,基本不花时间,所以读取的限制就很少了,速度也非常快。
这个框图,有几个重点部分:第一个是,整个Flash的空间划分,会划分为块,扇区和页,第二个是SPI控制逻辑,他就是整个芯片的管理员,执行指令,读写数据都靠它,第三个是状态寄存器,它和忙状态,写使能、写保护等功能有关,第四个是,256字节的页缓存,它会对一次性写入的数据量,产生限制,。
看一下Flash操作的注意事项,不就是个存储器吗,指定地址写和指定地址读,然后它直接给我把数据存在对应的存储单元里不就行了吗,为啥还要搞这么多的注意事项呢,其实因为Flash,作为一种掉电不丢失的存储器,为了保证这个特性,同时还要保证存储容量足够大,成本足够低,所以,Flash存储器会在其他地方,比如操作的便携性等,做出一些妥协和让步,Flash的写入和读取并不像RAM那样简单直接,RAM是指哪打哪,想在哪写就在哪写,想写多少就写多少,并且RAM是可以覆盖写入的,比如原来RAM里有个数据0xAA,之后再写入一个新的数据0x55,那RAM的数据就变成0x55,这个特性是非常好的,总之,Flash的读写有很多要求,其中写入的要求是非常多的,需要我们掌握,读取的要求就比较少了,还是那个原因,因为读取只是看一下电路的状态,不对电路做出实质性的改变,所以读取一般都比较快,而且没有什么限制。
1.写使能是一种保护措施,防止误操作的,就像使用手机一样,先解锁再操作,这样可以防止手机在裤兜里到处点点点,写使能的话,我们就用SPI发送一个写使能的指令,
2.这个意思就是说,Flash并没有像RAM那样的直接完全覆盖改写的能力,比如,在某一个字节的存储单元里,存贮了0xAA 这个数据,对应的二进制位就是 1010 1010,如果我直接再次在这个存储单元写入一个新的数据,比如再写一个0x55 ,那写完之后,这个存储单元还并不是0x55 ,当这个 0101 0101要覆盖原来的 1010 1010时,就会受到第2条的规定的限制,那只是说成本原因,或者技术原因了,所以这里写入0101 0101之后,以此来看,最高位,由原来的1,改写位0是可以的,所以写入之后,新的最高位就是0,但是第二位,原来是0,现在想改写为1,这是不行的,所以写入之后,新的第二位,仍然是0,这样子0xAA 写入0x55之后,存储单元最终的数据全是0,这就出问题了。所以为了弥补这个只能1改0,不能0改1的缺陷,就是写入数据前必须先擦除,擦除后,所有数据位变为1,在这里,Flash是有一个擦除的概念的,我们只要给他擦除的指令就行了,通过擦除电路擦除之后,所有数据位都变成1,这样就不受第二条限制的缺陷了。
总结一下:Flash中数据位位1的数据,拥有单向改成0的权利,一旦改写为0之后,就不能反悔再改写成1了,要想反悔,就必须得先擦除,所有位先统一变成1,然后再重新来过。
在Flash中,FF代表空白,而不是00。
擦除必须按最小擦除单元进行,这个应该是为了成本而做出的妥协,就是说,你写入前要进行擦除嘛,所以,如果我想在00这个地址写下数据,那我就先把00地址擦除,再写入数据到00地址,但是这个方案有问题,Flash的擦除是有最小擦除单元的限制,不能指定某一个字节去擦除,要擦就得一大片,可以选择整个芯片擦除,也可以选择块擦除,或者扇区擦除,再小就没了,所以最小的擦除单元,就是一个扇区,刚才我们看一个扇区是4KB,就是4096个字节,所以你擦除,最少,就得4096个字节一起擦,那只想擦除某一个字节怎么办呢,这没办法,你只能把那个字节所在扇区的4096个字节全都擦掉,那扇区其他的地方还有数据怎么办呢,这也没办法,要想不丢失数据,只能把字节都读出来,再把4096个字节的扇区擦掉,改写完读出来的数据后,再把4096个字节全都写回去。如果确实就想单独改写某一个字节,,那只能这样操作。
实际情况,我们还有别的方法优化这个流程,比如上电后,先把Flash的数据读出来,放到RAM里,当有数据变动时,再统一把数据备份到Flash里,或者,把使用频繁的扇区,放在RAM里,当使用频率降低时,再把整个扇区备份到Flash里,或者你数据量确实非常少,只想存几个字节的参数就行了,那直接一个字节占一个扇区也可以。
总结:为了弥补擦除存在最小单元的缺点,我么需要在逻辑上做出一些设计,连续写入多个字节时,最多写入一页的数据,超过页尾位置的数据,会回到页首覆盖写入,一次性不能写太多了,一个写入时序,最多只能写一页的数据,也就是256字节。为什么有这个限制呢,是因为一个页缓存区,它只有256字节。因为Flash的写入太慢了,所以写入的数据,会先放在RAM里暂存,等时序结束后,芯片再慢慢地把数据写入到Flash里,每个时序,最多写入一页的数据。你再写多,缓存区存不了了,如果非要写,那超过页尾位置的数据,会回到页首覆盖写入,另外,这个页缓存区是和Flash的页对应的,你必须得从页起始位置开始,才能最大写入256字节,如果你从页中间的地址开始写,那写到页尾时,这个地址就会跳回到页首,这会导致地址错乱,,所以我们再进行多字节写入时,,一定要注意这个地址范围,不能跨越页的边沿,否则会地址错乱,
4.写入操作后,由于都是对缓存区进行的,等时序结束后,芯片还要搬砖一段时间,所以每次写入操作后,都有一段时间的忙状态,在这个忙状态下,我们不要进行新的读写操作,否则,芯片是不会响应我们的,要想知道芯片什么时候结束忙状态了,我们可以使用读取状态寄存器的指令,看一下状态寄存器的BUSY位是否位1,,BUSY位位0时,芯片就不忙了,我们再进行操作。另外注意,这个写入操作,包括上面的擦除,在发出擦除指令后,芯片也会进入忙状态,我们也得等待忙状态结束后,才能进行后续操作。
读的时候,不用担心地址错位或者覆盖的问题,读取操作结束后不会进入忙状态,但不能在忙状态时读取,就是读取之后,芯片不会忙,可以立刻开始下一条指令,但是不能在忙状态时读取,因为写入操作,进入忙状态后,不会影响新的读写操作,所以,我们在读取之前,也要注意一下,芯片是否处于忙状态,等不忙的时候,再读,就可以了,
Flash这种非易失性存储器,目前的市场竞争力还是非常大的,,尽管它有这么多不方便,但是这些不方便可以用软件来弥补,而他的优点是其他存储器比不了的,,比如容量大,价格低,速度相比RAM是慢,但是再非易失性存储器中,就像它的名字一样,Flash闪存,如闪电一般的快,。
接下来看器件手册:
手册中的指令集、写使能等,
软件SPI用代码手动翻转电平,来实现时序,硬件SPI就是使用STM32内部的SPI外设,来实现时序,两种实现方法各有优势,软件实现主打的是方便灵活,,硬件实现的是高性能,节省软件资源,。
硬件自动生成时序,不用我们手动翻转电平,是STM32内部SPI外设的一些功能和技术参数,其实手册里介绍这些功能还是非常繁杂的,这是因为硬件电路不像软件那么灵活,硬件电路一旦设计出来,它的功能就基本就定死了,之后只能通过一些开关电路,数据选择器等等,来微调电路的运行。不像软件那样,我们缺少功能,只需要copy代码就行了,所以STM32设计时,就要考虑最全面的应用场景,把各种可能的结构都设计出来,放在那,以免用的时候找不到,那这样会导致外设电路的结构和知识点非常多,而且有很多功能,我们基本上很少用到,,所以STM32我们要使用主线加分支的学习方法,先把最常用,最简单的主线知识点给贯通,给它学会了,然后再逐渐细化,在实践中去慢慢探索这些分支,这样学起来才是比较容易的,所以大家在看手册学习时,有一些感觉非常偏有非常难的知识点,可以先不必深究,先把主线任务学习好,其他的可以之后再研究。
1.这里,我们SPI最常用的配置就是8位数据帧,高位先行,那16位数据帧是什么意思呢,
I2S的应用领域,这个数据其实就是一个点一个点的电压数值,是数字信号,就得外挂一个音频解码器,这个音频解码器,实际上就是DAC,数模转换器,它负责把数字信号转换成模拟信号,然后输出到扬声器,把音乐放出来,那我们把数字信号发送到DAC的这条线路,数据怎么发,每位数据定义什么,时序该怎么产生,传输速度是多快,这些配置都可以制定一个标准,这个标准就是数字音频传输协议,那I2S就是其中一种,主要用来传输数字音频信号,那因为I2S和SPicy话有些共同的特征,所以STM32就把SPI和I2S做到了一起,有些电路可以共用,最大化利用资源。手册里SPI一半的内容都在介绍IIS,这个其实知道是什么东西就可以了,暂时用不到。
下面发送缓冲区,就是发送数据寄存器TDR,上面接收缓冲区,就是接收数据寄存器RDR,和串口那里一样,TDR和RDR占用同一个地址,统一叫做DR,写入DR的时候,数据从这里写道到TDR,读取DR的时候,数据从这里从PDR读出,数据寄存器和移位寄存器打配合,可以实现连续的数据流,比如我们需要连续发送一批数据,第一个数据,写入到TDR,当移位寄存器没有数据移位时,TDR的数据会立刻转入移位寄存器,开始移位,这个转入时刻,会置状态寄存器的TXE为1,表示发送寄存器空,当我们检查TXE置1后,紧跟着下一个数据就可以提前写入到TDR里候着了,实现不间断的连续传输,从移位寄存器转入到接收缓冲区RDR,这就是移位寄存器配合数据寄存器实现连续数据流的过程,再转到移位寄存器发送,
IIC是半双工,发送和接收不会同时进行,发送和接收都可以是共用的,
串口是全双工,并且发送和接收是可以异步进行,所以这里要求,它的数据寄存器,发送和接收是分离的,
这就是三个通信协议,在这一块的设计,,
左上角是SPI通信的核心部分,体现了发送和接收的执行流程,也是我们写程序的依据,所以需要重点掌握,
右下角的一些内容就是一些控制逻辑了,首先是波特率发生器,主要用来产生SCK时钟的,它的内部主要是一个分频器,输入时钟是PCLK,72M或者36M,经过分频器之后,输出到SCK引脚,当着这里生成的时钟肯定是和移位寄存器同步的了,每产生一个时钟的周期,移入移出一个bit,然后右边,CR1寄存器的三个位BR0、BR1、BR2用来控制分频系数,手册里可以看一下。
然后这里SR状态寄存器是最后两个,
TXE 发送寄存器空,RXNE接收寄存器非空,我们发送接收数据的时候,需要关注这两位,
之后CR2寄存器,就是一些使能位了,,比如中断使能,DMA使能等,剩下的自行研究。
最后NSS引脚,SS就是从机选择,低电平有效,所以这里前面加了个N,这个NSS,和我们想象的从机选择可能不太一样,NSS可能更偏向于实现多主机模型,NSS我们并不会用到,SS引脚直接用一个GPIO口模拟就好了,NSS如何实现多主机切换功能,假如有3个STM32设备,把NSS全接在一起,NSS配置成输入或输出,可以输出电平告诉别的设备要变为主机,其他设备都变成从机,不要来捣乱。可以接收别的设备的信号。
当有设备是主机拉低NSS后,我们就变不成主机,当SSOE=1时,NSS作为输出引脚,并在当前设备变为主设备时,给NSS输出低电平。当主机结束后,SSOE清零,NSS变为输入。
这时,输入信号跑到右边哪里,有个数据选择器,SSM位决定选择哪一路,选择上面那一路是硬件NSS模式,也就是说,这时外部如果输入了低电平,那当前设备就进不了主模式了,NSS进入下一路就是软件管理NSS输入,NSS是1还是0,由SSI来决定,这就是多主机模型。
这种模式要考虑的还有很多,所以用的很少,NSS暂时用不到,一般还是单片机用一主多从。
这个图需要掌握移位寄存器和数据寄存器这部分,波特率发生器和重要的寄存器也要了解。
手册中文档命名不太统一规范可能是多个人来分工写的文章,最后整合到一起,导致手册中不同章节,描述手法和词汇可能不太一样。
运行控制部分是如何产生具体时序:主模式全双工连续传输,借助缓冲去,数据前赴后继实现数据流的传输,但这个流程,稍微比较复杂,也不太方便封装,所以实际过程中如果没有对性能极致的追求(如果有的话就需要研究这个连续数据流传输),更倾向于非连续输入。
非连续传输使用4行代码即可,容易封装,好理解,好用,但是会丢失一点性能,
连续传输一旦TXE=1,就会把下一个数据写道TDR里候着,这样为了连续传输数据更紧密,但流程比较复杂。
非连续传输则在TXE=1时,着急把下一个数据写进去,而是一直等待第一个字节时序结束,这时接收RXNE置1,然后把第1个接收到的数据读出来,之后再写入下一个数据。非连续的缺点是没有及时把下一个数据写入TDR里候着,所以第一个时序结束后,第二个字节还没有送过来,数据传输就在这里候着,所以这时时钟和数据的时序再字节和字节之间,会产生间隙,拖慢整体数据传输的速度,在SCK频率较低时影响不大,SCK频率高时会严重托后腿。
软硬件波形对比:数据变换趋势和采样得到的数据一样,区别在于软件波形数据线的变化在边沿后有一些延时,可以发现IIC的SCL低电平期间数据变化,高电平期间数据采样,在SPI描述的SCK下降沿数据移出,上升沿数据移入,最终波形表现是一样的。
下降沿和低电平期间,都可以作为数据变化的时刻,只是硬件波形会紧贴边沿,软件波形一般只在电平期间。
结构框图的作用:初始化配置
时序流程的作用:用于控制数据传输
手册里SPI和IIS的内容多,23.3.4英文手册里是半双工,中文翻译成了单工。
Stm32f10x_spi.h
因为SPI和I2S共用一套电路,那就先不考虑I2S,当不存在。
SPI_I2S_DeInit 恢复缺省配置
SPI_Init 初始化
SPI_StructInit 结构体变量初始化
SPI_Cmd 外设使能
SPI_I2S_ITConfig 中断使能
SPI_I2S_DMACmd DMA使能
比较重要的是两个函数SPI_Init和SPI_Cmd
SPI_I2S_SendData 写DR数据寄存器,把传进来的Data,赋值给DR,写数据到发送数据寄存器TDR
SPI_I2S_ReceiveData 读DR数据寄存器
中间的了解即可,中间4个是old friends,获取标志位和清除标志位的函数,来获取TXE和RXNE标志位的状态,再配合写DR和读DR的函数,这样控制时序的产生。
代码1.开启SPI和GPIO时钟,2.配置相应的GPIO口。