带你了解STM32:SPI通信(软件部分)
目录
0.SPI相交于I2C的优缺点
1.SPI通信
2.硬件电路
3.移位示意图(SPI硬件电路设计的核心)(下面的时序都是这个逻辑进行字节交换)
4.SPI时序基本单元
5.SPI时序(W25Q64)
6.W25Q64简介
7.硬件电路
8.W25Q64框图
9.Flash操作注意事项
10.参考资料(状态寄存器、框架图、指令集……)
11.软件SPI读写W25Q64代码
第一步:按图接线到面包板上
第二步:复制OLED显示屏代码
工程思路:
第三步:建立MySPI模块,完成通信引脚封装、初始化、时序:起始、终止、交换一个字节
模式0
模式1
模式2
模式3
第四步:MySPI头文件声明
第五步:新建立一个头文件,命名为W25Q64_Ins,封装指令码
第六步:建立W25Q64驱动模块,调用底层SPI,拼接各种指令和功能的完整时序,比如:写使能、擦除、页编程、读数据等等,模块函数功能实现参考手册,模块的建成也要看Flash操作注意事项
第七步:W25Q64头文件声明
第八步:主函数调用
0.SPI相交于I2C的优缺点
优点:1.SPI传输更快,SPI协议并没有严格规定最大传输速度,这个最大速度取决于芯片厂商的设计需求,比如:W25Q64存储器芯片,最大可达80MHz;2.设计比较简单粗暴,比I2C简单好学
缺点:1.因为设计比较简单粗暴,所以功能就没有I2C怎么多了;2.SPI的硬件资源开销多,通信线的个数比较多,并且通信过程中,经常会有资源浪费的现象
1.SPI通信
SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线
四根通信线:SCK(Serial Clock)(别名:SCLK、CLK、CK)、MOSI(Master Output Slave Input)(别名:DO)、MISO(Master Input Slave Output)(别名:DI)、SS(Slave Select)(别名:NSS、CS)
SCK:时钟信号,数据位的输出和输入,都是在SCK的上升沿和下降沿进行的,数据位的收发时刻就可以明确的确定;MOSI:主机输出从机输入,如果是主机接到这根线上,那就是MO,主机输出,如果是从机接到这条线上,就是SI,从机输入;MISO:主机从从机接收数据的线路;MOSI和MISO加在一起相当于I2C总线的SDA,但是SDA是半双工,这里是全双工;SS:从机选择线,直接连接到从机上,不用寻址,低电平呼叫从机,高电平释放从机
同步,全双工
支持总线挂载多设备(一主多从)
从左到右:W25Q64(Flash存储器芯片)、OLED、2.4G无线通信模块、Micro SD卡
2.硬件电路
所有SPI设备的SCK、MOSI、MISO分别连在一起
主机另外引出多条SS控制线,分别接到各从机的SS引脚
输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入
3.移位示意图(SPI硬件电路设计的核心)(下面的时序都是这个逻辑进行字节交换)
SPI一般是高位先行,每来一个时钟,移位寄存器会向左进行移位,移位寄存器时钟源主机提供(波特率发生器),主机移位寄存器左移数据,从左边出去通过MOSI引脚,移动到从机移位寄存器右边,从机移位寄存器左边移出去的数据,通过MISO引脚,输入到主机移位寄存器的右边
电路工程流程:波特率发生器时钟的上升沿,所以移位寄存器向左移动一位,移出去的位放在引脚上,波特率发生器时钟的下降沿,引脚上的位,采样输入到移位寄存器的最低位
假设,主机有个数据10101010要发送到从机,同时从机一个数据01010101要发送到主机,驱动时钟先产生一个上升沿,所有的位会往左移动一次(图1),移除去的数据会放在通信线上,实际是放在输出数据寄存器上,此时MOSI数据是1,所以MOSI的电平是高电平,MISO数据是0,所以MISO的电平是低电平,这就是第一个时钟上升沿执行的结果(图2);之后时钟置一个下降沿,在下降沿时,主机和从机内,都会进行数据采样输入,也就是MOSI的1,会采样输入到从机的最低位,MISO的0,会采样输入到主机的最低位。这就是一个时钟结束后的现象(上升沿和下降沿的组合)(图3);如此字节交换,最终8个时钟过后,主机的数据在从机里,从机的数据在主机里。
如果只发不收,仍然用交换字节的时序,接收的数据(一般给从机写入0x00或0xFF)不看即可;如果只收不发,同理,调用交换字节的时序,随便发一个数据,从机不会看这个随便发的数据(一般发0x00或0xFF)
4.SPI时序基本单元
起始条件:SS从高电平切换到低电平
终止条件:SS从低电平切换到高电平
交换一个字节(模式0)(最常用)
MISO因为有多个从机输出连在一起,如果同时开启输出,会造成冲突,所以解决方法是在SS未被选中的状态,从机的MISO引脚必须关断输出,即配置为高阻状态(就是图中的一根线),SS上升沿之后,从机的MISO必须置回高阻状态
CPOL(时钟极性)=0:空闲状态时,SCK为低电平
CPHA(时钟相位,决定第一个时钟采样移入还是第二个时钟采样移入)=0:SCK第一个边沿移入数据,第二个边沿移出数据,在SCK第一个边沿之前就把数据移出了(或者理解为在第0个边沿移出)。相较于模式1提前半个相位(时钟)将数据移出
交换一个字节(模式1)
MISO因为有多个从机输出连在一起,如果同时开启输出,会造成冲突,所以解决方法是在SS未被选中的状态,从机的MISO引脚必须关断输出,即配置为高阻状态(就是图中的一根线),SS上升沿之后,从机的MISO必须置回高阻状态
CPOL=0:空闲状态时,SCK为低电平
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据。
交换一个字节(模式2)
将模式0的SCK极性取反,就是模式2
CPOL=1:空闲状态时,SCK为高电平
CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据
交换一个字节(模式3)
将模式1的SCK极性取反,就是模式3
CPOL=1:空闲状态时,SCK为高电平
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据
5.SPI时序(W25Q64)
采用指令码加读写数据的模型。流程:SPI起始后,第一个交换发送给从机的数据,这个数据一般是指令码;在从机中对应的会定义一个指令集,不同指令,可以有不同的数据个数,有的指令,只需要一个字节的指令码就可以完成,如:W25Q64的写使能、写失能等指令,有的指令,后面就需要再跟要读写的数据,比如:W25Q64的写数据、读数据等
发送指令
向SS指定的设备,发送指令(0x06),0x06表示写使能,主机向从机发送写使能的指令,从机接收到指令后,控制硬件,进行写使能
指定地址写
向SS指定的设备,发送写指令(0x02),随后在指定地址(Address[23:0])(地址是24位的分为3个字节传输)下,写入指定数据(Data)
第一个字节,发送写数据的指令;第二个字节到第四个字节都是地址,0x12(23~16位)、0x34(15~8位)、0x56(7~0位);第五个字节:写入的数据,表示在0x123456地址下,写入0x55这个数据
指定地址读
向SS指定的设备,发送读指令(0x03), 随后在指定地址(Address[23:0])下,读取从机数据(Data)
第一个字节,发送读数据的指令;第二个字节到第四个字节都是地址,0x12(23~16位)、0x34(15~8位)、0x56(7~0位);第五个字节:读取的数据,表示在0x123456地址下的数据通过MISO发给主机
6.W25Q64简介
W25Qxx系列是一种低成本、小型化、使用简单的非易失性存储器,常应用于数据存储、字库存储、固件程序存储等场景
存储介质:Nor Flash(闪存)
时钟频率:80MHz / 160MHz (Dual SPI) / 320MHz (Quad SPI)
存储容量(24位地址):
W25Q40: 4Mbit / 512KByte
W25Q80: 8Mbit / 1MByte
W25Q16: 16Mbit / 2MByte
W25Q32: 32Mbit / 4MByte
W25Q64: 64Mbit / 8MByte
W25Q128: 128Mbit / 16MByte
W25Q256: 256Mbit / 32MByte
7.硬件电路
8.W25Q64框图
存储器的规划示意图
8MB的存储空间,先划分为若干的块(Block),其中每一块再划分为若干的扇区(Sector),对于每个扇区内部又可以分成很多页(Page)
SPI Command & Control Logic:SPI控制逻辑。芯片内部进行地址锁存、数据读写等操作,这个是芯片自行完成的
Status Register:状态寄存器。芯片是否处于忙状态、是否写使能、是否写保护等等都可以在这个寄存器里面体现
Write Conteol Logic:写控制逻辑。和外部的WP引脚相连,通过这个引脚实现硬件写保护
High Vollage Generators:高电压生成器。配合Flash进行编程
指定地址,通过SPI发过来3个字节的地址,所以一页内的字节地址,就取决于最低一个字节,而高位的2个字节,就对应的是页地址,所以发送的3个字节的地址,前两个字节会进入这个页地址锁存计数器里,最后一个字节会进入字节地址锁存计数器里。然后,页地址,通过写保护和行解码,选择要操作哪一页,字节地址,通过列解码和256字节页缓存区(RAM存储器),进行指定字节的读写操作
Page Address Latch/Counter:页地址锁存/计数器
Byte Address Latch/Counter:字节地址锁存/计数器
Column Decode And 256-Byte Page Buffer:256字节页缓冲区。一种RAM存储器,因为Flash的写入太慢,跟不上SPI的频率,所以写入的数据会先放在RAM里面暂存,等时序结束后,芯片在慢慢地把数据写入到Flash里
9.Flash操作注意事项
写入操作时:
写入操作前,必须先进行写使能
每个数据位只能由1改写为0,不能由0改写为1
写入数据前必须先擦除,擦除后,所有数据位变为1
擦除必须按最小擦除(一个扇区)(对于W25Q64是4096个字节)单元进行,如果不擦除,读出的数据=原始数据&写入的数据
连续写入多字节时,最多写入一页(对于W25Q64是256个字节)的数据,超过页尾位置的数据,会回到页首覆盖写入
写入操作结束后,芯片进入忙状态,不响应新的读写操作
读取操作时:
直接调用读取时序,无需使能,无需额外操作,没有页的限制,读取操作结束后不会进入忙状态,但不能在忙状态时读取
10.参考资料(状态寄存器、框架图、指令集……)
11.软件SPI读写W25Q64代码
第一步:按图接线到面包板上
第二步:复制OLED显示屏代码
工程思路:
首先建立一个MySPI模块,这个模块包含通信引脚封装、初始化、时序:起始、终止、交换一个字节
然后基于MySPI,建立一个W25Q64模块,这个模块调用底层SPI,拼接各种指令和功能的完整时序,比如:写使能、擦除、页编程、读数据等等,所以这个模块是W25Q64的硬件驱动层
最后,在主函数里,调用W25Q64的硬件驱动层的函数,完成想要实现的功能
第三步:建立MySPI模块,完成通信引脚封装、初始化、时序:起始、终止、交换一个字节
模式0
另外一种方法,但是最开始的ByteSend就没有了
模式1
模式2
在模式0的基础上,将所有的SCK,0改为1,1改为0
模式3
在模式1的基础上,将所有的SCK,0改为1,1改为0