STM32 SPI

在这里插入图片描述
SPI 串行外设接口,和IIC一样,是通用的数据总线,用于主控和外挂芯片之间的通信,
IIC和SPI的优劣势:
IIC的硬件电路和软件时序设计都相对复杂,,硬件上,要配置为开漏外加上拉的模式,
软件上的功能和要求,一根线通信兼数据收发,应答位的收发,寻址机制的设计。IIC可以在消耗最低硬件资源的情况下,实现最多的功能,在硬件上,无论需要挂载多少个设备,都只需要两根通信线
如果把通信协议比作一个人,IIC就属于精打细算,思维灵活这类型的人。既要实现硬件上最少的通信线,又要实现软件上最多的功能,IIC实现地非常优雅,但是由于IIC开漏外加上拉电阻地电路结构,使得通信线高电平的驱动能力比较弱,就会导致通信线由低电平向高电平跳变的时候,这个上升沿耗时比较长,会限制IIC的最大通信速度。所以IIC的标准模式只有100KHz的时钟频率,快速模式也只有400KH,虽然IIC协议之后又通过改进电路的方式,设计出了高速模式,可以达到3.4MHz,但是高速模式目前普及程度不高,所以一般情况下,认为IIC的时钟速度最多就是400KHz,

SPI传输更快,没有严格规定最大传输速度,这个最大传输速度取决于芯片厂商的设计需求,比如说W25Q64存储器芯片,手册里写的SPI时钟频率,最大可达80MHz,这比STM32F1的主频还要高,实现的功能没有IIC那么多,所以学习起来,SPI还是比IIC简单很多,最后SPI的硬件开销比较大,通信线的个数比较多,并且通信过程中,经常会有资源浪费的现象。
如果把通信协议比作一个人,SPI就属于富家子弟,有钱任性这类型的人,不在乎花了多少钱,只在乎我的任务有没有最简单,最快速的完成,这就是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的所有通信线都是单端信号,他们的高低电平都是相对GND的电压差,所以单端信号,有的设备还需要共地,这里GND没有画出来,但是是必须要接的,然后如果从机没有单独供电的话,主机还需要再额外引出电源正极VCC,给从机供电,
时钟线完全由主机控制,时钟线都为输入,这样主机的同步时钟,就可以送到各个从机了,
SS是低电平有效,,主机想指定谁,就把对应的SS输出线置低电平就行了

当主机需要和从机1进行通信,主机就把SS1线输出低电平,从机1就知道主机在找我,然后主机在数据引脚进行的传输,就只有从机1会响应,其他从机的SS线是高电平,就会保持沉默。当主机和从机1完成通信之后,主机会把SS1置高电平,这样从机就知道,主机结束了和我的通信。同一时间,主机只能置一个SS为低电平,只能选中一个从机,否则如果主机同时选中多个从机,就会导致数据冲突,这就是SPI实现选择从机的方式。
输出引脚配置为推挽输出,输入引脚配置成浮空或上拉输入。对于输出,我们配置推挽输出,高低电平都有很强的驱动能力,这将使得SPI引脚信号的下降沿,非常迅速,上升沿也非常迅速,,SPI信号变化的快,自然它就能达到更高的传输速度,,一般SPI信号都轻松可以达到MHz的速度级别

SS未被选中时,它的MISO引脚,必须切换为高阻态,相当于引脚断开,不输出任何电平,这样就可以防止,一条线有多个输出,而导致的电平冲突的问题了,在SS为低电平时,MISO才允许变为推挽输出,这就是SPI对这个可能的冲突做出的规定,当然这个切换过程都是在从机里。所以我们主机的程序中,并不需要关注这个问题,

在这里插入图片描述
移位示意图是SPI硬件电路设计的核心,只要把移位示意图搞懂了,那无论是上面的硬件电路,还是我们等会学习的软件时序,
SPI的基本收发电路,就是使用了这样一个移位的模型,左边是SPI主机,里面有一个8为的移位寄存器,右边是SPI从机,里面也有一个8位移位寄存器,这里移位寄存器有一个时钟输入端,因为SPI一般是高位先行的,所以,每来一个时钟,移位寄存器都会向左进行移位,从机中的移位寄存器也是同理,然后,移位寄存器的时钟源是主机提供的,这里叫波特率发生器,它产生的时钟驱动主机的移位寄存器进行移位,同时,这个时钟也通过SCK引脚进行输出,接到从机的移位寄存器里,主机移位寄存器左边移出的数据,通过MOSI引脚,输入到从机移位寄存器的右边,从机移位寄存器左边一出去的数据,通过MISO,输入到主机移位寄存器的右边
波特率发生器时钟的上升沿,所有移位寄存器向左移动一位,移出去的位放到引脚上,波特率发生器时钟的下降沿,引脚上的位,采样输入到移位寄存器的最低位,接下来,假设主机有数据10101010要发送到从机,同时,从机有数据01010101要发送到主机,先产生一个上升沿,那从最高位移出去的数据,向左移动一次,
那最高位移出去的数据,就会放到通信线上,实际上是放到了输出数据寄存器,此时MOSI数据是1,所以MOSI的电平就是高电平,MISO的电平就是低电平,这就是第一个时钟上升沿执行的结果。上升沿之后,下一个边沿就是下降沿,在下降沿时,主机和从机内,都会进入数据采样输入,也就是MOSI的1,会采样输入到从机这里的最低位,MISO的0会采样输入到主机这里的最低位,这就是第一个时钟结束后的现象。一直到第8个时钟,都是同样的过程,实现了主机和从机一个字节的数据交换,实际上,SPI的运行过程就是这样,SPI数据的收发,都是基于字节交换,这个基本单元来进行的,当主机需要发送一个字节,并且同时需要接收一个字节时,这样,主机要发送的数据跑动从机,主机要从从机接收的数据,跑到主机。
只想发送,不想接收怎么办呢? 仍然调用交换字节的时序,发送同时接收,只是接收到的数据,我们不去看它。
如果只想接收,不想发送,就还是调用交换字节的时序,,只是会随便发送一个数据,只要能把从机的数据置换过来就行了。这里随便发过去的数据,从机也不会去看它,我们不会真的随便发,一般在接收的时候,我们会统一发送0x00或0xFF,去跟从机交换数据。

以上就是SPI的基本原理,SPI通信的基础是交换一个字节,有了交换一个字节,就可以实现发送一个字节、接收一个字节和发送同时接收一个字节这三种功能,可以看出,SPI在只执行发送或只执行接收的时候,会存在一些资源浪费现象。不过,全双工的通信,本来就会有浪费的情况发生,

在这里插入图片描述
SS低电平选中,高电平未选中。低电平器件就代表正在通信,下降沿是通信的开始,上升沿是通信的结束。

在这里插入图片描述
这个基本单元是建立在我们刚才说的移位模型上的,并且这个基本单元,什么时候开始移位?是上升沿移位还是下降沿移位?SPI并没有限定死,给了我们可以配置的选择,这样的话,SPI就可以兼容更多的芯片,SPI有俩i个可以配置的位,分别是CPOL(Clock Polarity)时钟极性,和CPHA(Clock Phase)时钟相位,每一位可以配置位1或0,总共组合起来就有4种模式,但是他们的功能都是一样的,在实际使用的时候,主要学习其中一种就可以了,剩下的模式,知道有这个东西可以配置,如果真的需要用,再过来了解一下即可。

模式0的数据移入的时机,会提取半个时钟,也就是相位提前了,模式0在SCK第一个边沿就要移入数据,但是数据总得先移出,才能移入,对吧。SCK第一个边沿之前,就要提前开始移出数据了,或者把它称作是第0个边沿移出,第1个边沿移入,
首先,SS下降沿开始通信,SCK一旦开始变化,就要移入数据,所以趁此时SCK还没有变化,SS下降沿时,就要立刻出发移位输出,所以这里MOSI和MISO的输出是对齐到SS的下降沿的,或者说把SS的下降沿,当作时钟的一部分了,那SS下降沿触发了输出,SCK上升沿,就可以采样输入数据了,。最后,SCK还有一个下降沿,如果主机只需要换一个字节就结束,那在这个下降沿时,MOSI可以置回默认电平,或者不去管它,MISO也会变化一次,这一位,实际上是下一个字节的B7,因为这个相位提前了,所以下一个字节的B7就会露头,如果不需要的话,SS上升沿之后,从机MISO置回高阻态,这是交换一个字节就结束。如果主机想交换多个字节,那就继续调用,在最后一个下降沿,主机放下一个字节的B7,从机也会放下一个字节的B7,SCK上升沿,正好接着采样第二个字节的B7,这样时序才能拼接的上,

模式0和模式1的区别在于,模式0把这个数据变化的时机给提前了,在实际应用中,模式0的应用是最多的,重点掌握模式0即可。
模式1虽然感觉更合理,但是这么设计可能是SPI为了兼容现存设备。

CPHA只能决定边沿,并不能单独决定是上升沿还是下降沿,还得考虑CPOL

在这里插入图片描述
CPOL=0,表示空闲状态,SCK位低电平,在SS未被选中时,SCK默认是低电平的,
CPHA=1,表示SCK第一个边沿移出数据,第二个边沿移入数据,有的地方写的是CPHA=1表示SCK的第二个边沿进行数据采样,或者是SCK的偶数边沿进行数据采样,意思都一样,这里为了照应刚才的移位模型,就这么写

SS高电平时,MISO用一条中间的线,表示高阻态。
SS下降沿之后,从机的MISO被允许开启输出,SS上升沿之后,从机的MISO必须置回高阻态,这是这一块的设计。移位传输的操作,因为CPH1=1,SCK第一个边沿主机和从机同时移出数据,
在SS的上升沿,MOSI还可以再变化一次,将MOSI置到一个默认的高电平或者低电平,当然也可以不去管他,因为SPI没有硬性规定MOSI的默认电平,然后MISO从机必须得置回高阻态,此时如果主机的MISO为上拉输入的话,那MISO引脚的电平就是默认的高电平,如果主机MISO为浮空输入,那MISO引脚的电平不确定,这是交换一个字节就结束的流程,如果之际还想继续交换字节,在此时主机就不必把SS置回高电平了。这个模式1和之前演示的移位流程是对应的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
IIC一般规定,有效数据流第一个字节是寄存器地址,之后是读写的数据,而在SPI通信中,通常采用的是指令码加读写数据的模型,这个过程就是,SPI起始后,第一个交换发送给从机的数据,在从机中,对应会定义一个指令集,就可以在起始后第一个字节,发送指令集里面的数据,这样就能指导从机完成相对应的功能了,不同的指令,可以有不同的数据个数,有的指定只需要一个字节的指令码就可以完成,有的就需要再跟要读写的数据,都会定义好指令集,什么指令对应什么功能,后面跟上什么数据,。这些可以由芯片厂商自己规定。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
易失性存储器一般就是SRAM,DRAM等,非易失性存储器一般就是EEPROM,Flash等,它们最只要的区别,简而言之,就是存储的数据是否是掉电不丢失。
所以非易失性存储器,在断电重启后,数据仍然保持原样,既然数据是掉电不丢失的,那就可以根据这个特性来做一下应用了,想要掉电不丢失的保存,就可以把数据写入到这个芯片,可以应用到一些屏幕上,如果屏幕想显示汉字,就得把汉字的点阵数据存起来,最简单的方法是,把字库直接存在STM32内部,这样适合少量汉字显示的情况,如果汉字非常多,那直接存在STM32中,就不合适了,所以可以用这个芯片来存储汉字字库的点阵数据,在现实某个汉字前,先读取芯片查询字库,再在显示屏上显示对应的点阵数据,就能让显示屏显示任意中文了,然后固件程序存储,就相当于直接把程序文件下载到外挂芯片里,需要执行程序的时候,直接读取外挂芯片的程序文件来执行,这就是XIP(eXecute In Place),就地执行,比如我们电脑里的BIOS固件,就可以存储在这个W25Q系列的芯片里,这些就是芯片的特性和用途了。

本节使用最简单的数据存储功能,

存储介质, Nor Flash Flash就是闪存存储器,像STM32的程序存储器、U盘、电脑里的固态硬盘等,使用都是Flash闪存,闪存分为Nor Flash和Nand Flash。两者各有优势和劣势,适用领域不同。

时钟频率,这个芯片使用SPI通信,其中SPI的SCK线,就是时钟线,这个时钟线最大频率就是80MHz,所以之后写程序的时候,320MHz这个是四重SPI模式等效的频率,双重SPI和四重SPI了解一下即可,什么意思呢,就是我们之前说MOSI用于发送,MISO用于接收,是全双工通信,在只发或只收时有资源浪费,但是W25Q芯片的厂商不忍心浪费,所以对SPI做了一些改进,可以同时用MOSI和MISO发送,在收的时候,也可以同时用MOSI和MISO接收,MOSI和MISO同时兼具发送和接收的功能,一个SCK时钟,我同时发送或接收2位数据,这就是双重SPI,相比较一位一位的普通SPI,所以这里写的是,在双重SPI模式下,等效的时钟频率就是80MHz的二倍,就是160MHz,等效的时钟频率就是80MHz的二倍,就是160MHz,但实际的SCK频率,最大还是80MHz,只是一个时钟发两位,然后四重SPI模式,就是一个时钟发送或接收4位了。
在这里插入图片描述
在这个芯片里,除了SPI通信引脚,还有两个引脚,一个是WP写保护,另一个是HOLD,这两个引脚,如果不需要的话,也可以拉过来,充电数据传输引脚,加上MOSI和MISO,这就可以4个数据位同时收发了,。其实这有点并行传输的意思,串行是根据时钟,一位一位地发送,并行是一个时钟,8位同时发送,所以这个四重SPI模式,就是4位并行的模式,

3号 WP(Write Protect),配合内部的寄存器配置,可以实现硬件的写保护,写保护低电平有效,WP接低电平,保护住,不让写,WP接高电平,不保护,可以写。意思是数据保持,低电平有效,这个用的不多,了解一下。如果进行正常读写时,突然产生中断,然后想用SPI通信线去操控其他器件,这时如果把CS置回高电平,那时序就终止了,但如果又不想终止总线,又想操作其他器件,这就可以HOLD引脚置低电平,这样芯片就HOLD住了,芯片释放总线,但是芯片时序也不会终止,它会记住当前的状态,当你操作完其他器件时,可以回过来,HOLD置回高电平,然后继续HOLD之前的时序,相当于SPI总线进了一次中断,并且在中断里,还可以用SPI干别的事情,这就是HOLD的功能,
注意到DI、DO、WP和HOLD旁边都有括号,写了IO0、IO1、IO2、IO3,这个对应我们刚才说的双重SPI和四重SPI,如果时普通的SPI,括号里的都不需要看,

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个字节,

左下角是SPI控制逻辑,也就是芯片内部进行地址锁存,数据读写等操作,都可以由控制逻辑来自动完成,这个不用我们操心,控制逻辑就是整个芯片的管理员,有什么事情只要告诉这个管理员就可以了,然后控制逻辑左边,就是SPI通信引脚,,有WP、HOLD、CLK、CS、DI和DO,这些引脚就和我们的主控芯片相连,主控芯片通过SPI协议,把指令和数据发送给控制逻辑,控制逻辑就会自动去操作内部电路,来完成我们想要的功能,这个状态寄存器是比较重要的,比如芯片是否处于忙状态,是否写使能,是否写保护,都可以在这个状态寄存器里体现,可以等单独看手册再分析。

和外部的WP引脚相连,显然,这个是配合WP引脚实现硬件写保护的,接着右边是一个高电压生成器,这个是配合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口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值