一、SPI通信
简介
•SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线
•四根通信线:SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select)
•同步,全双工
支持总线挂载多设备(一主多从)
硬件电路
•所有SPI设备的SCK、MOSI、MISO分别连在一起
•主机另外引出多条SS控制线,分别接到各从机的SS引脚
•输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入
主机只能置一个SS为低电平,如果选择多个从机会导致数据冲突,当从机的 SS 为高(未选中)时,它的 MISO 引脚内部开关断开,进入高阻态。

移位示意图
假设规定波特率发生器时钟的上升沿,所有的移位寄存器向左移动一位,移出去的位放到引脚上
波特率发生器时钟的下降沿,引脚上的位,采样到移位寄存器的最低位
当只要获取从机的数据时,主机可以发送无关数据来替换出从机的数据,或者只看从机交换出来的数据。

SPI时序基本单元

模式0:在SS下降沿时就将位移出,最后一个SCK下降沿时,如果不需要交换数据,MOSI可以置回默认电平,或者不管,MISO在SS上升沿之后,置回高阻态。




SPI时序
指定地址写
•向SS指定的设备,发送写指令(0x02),
随后在指定地址(Address[23:0])下,写入指定数据(Data)
W25Q64芯片的规定读/写指令之后的字节,定义为地址的高位,这里的0x12表示发送地址的23~16位,0x34表示发送地址的15~8位,0x56表示发送地址的7~0位,地址发送完就可以发送数据。

指定地址读
•向SS指定的设备,发送读指令(0x03),
随后在指定地址(Address[23:0])下,读取从机数据(Data)

二、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
硬件电路

当产生中断时,要使用SPI通信线去操作其他器件,使用HOLD可以将芯片暂停记住当前状态以便恢复芯片通信。
框图

一、存储阵列结构(右侧)
总容量:64Mbit(即 8MB),地址范围为 0x000000h 到 0x7FFFFFh。
块(Block)划分:
整个存储阵列被划分为 128 个块(Block),每个块大小为 64KB。
例如:Block 0 对应地址 0x000000h 至 0x00FFFFh,Block 127 对应地址 0x7F0000h 至 0x7FFFFFh。
扇区(Sector)划分:
每个 64KB 的块又可进一步划分为 16 个扇区(Sector),每个扇区大小为 4KB。
例如:Block 0 中的 Sector 0 对应地址 0x000000h 至 0x000FFFh,Sector 1 对应 0x001000h 至 0x001FFFh,以此类推。
页(Page)划分:
每个扇区包含 16 个页,每页大小为 256 字节。这是芯片执行 “页编程” 操作的最小单位。
二、核心功能模块(左侧)
SPI Command & Control Logic(SPI 命令与控制逻辑)
这是芯片的 “大脑”,负责接收并解析来自主机的 SPI 指令(如读、写、擦除等)。
它控制着芯片内部所有其他模块的协同工作。
输入信号包括:/CS(片选)、CLK(时钟)、DI(IO0)(数据输入)、/HOLD(IO3)(数据保持)、/WP(IO2)(写保护)。
输出信号为:DO(IO1)(数据输出)。
Status Register(状态寄存器)
用于反映芯片当前的工作状态,例如是否正在进行写 / 擦除操作、是否被写保护、是否忙碌等。
主机可以通过读取状态寄存器来判断操作是否完成。
Write Control Logic(写控制逻辑)
与 /WP 引脚和状态寄存器配合,实现对存储阵列的写保护功能,防止误写入。
High Voltage Generators(高压发生器)
Flash 存储器的编程和擦除操作需要高于电源电压的高压,此模块负责产生这些高压。
Page Address Latch / Counter(页地址锁存 / 计数器)
用于在页编程操作中,跟踪当前要写入的页地址。
Byte Address Latch / Counter(字节地址锁存 / 计数器)
用于在读写操作中,跟踪当前页内的字节地址。
Column Decode And 256-Byte Page Buffer(列译码与 256 字节页缓冲)
这是页编程操作的核心。主机先将数据写入这个 256 字节的缓冲区,然后再一次性编程到存储阵列的对应页中,以提高效率。
Write Protect Logic and Row Decode(写保护逻辑与行译码)
行译码器负责根据块 / 扇区地址,选中存储阵列中对应的行。
写保护逻辑则根据配置,对特定的块或扇区进行写保护。
三、工作流程示例:页编程(Page Program)
主机通过 SPI 发送 “写使能” 指令(WREN, 0x06)。
主机发送 “页编程” 指令(0x02),随后是 24 位目标地址。
SPI 控制逻辑解析指令,将地址分解为页地址和字节地址,分别锁存到对应的计数器中。
主机发送要写入的数据,这些数据先被暂存到 256 字节页缓冲器 中。
当缓冲器满或主机结束传输时,高压发生器启动,将缓冲器中的数据一次性编程到存储阵列的对应页。
在此期间,状态寄存器的 BUSY 位会被置位,直到操作完成。
Flashing操作注意事项
写入操作时:
•写入操作前,必须先进行写使能
•每个数据位只能由1改写为0,不能由0改写为1
•写入数据前必须先擦除,擦除后,所有数据位变为1
•擦除必须按最小擦除单元进行
•连续写入多字节时,最多写入一页的数据,超过页尾位置的数据,会回到页首覆盖写入
•写入操作结束后,芯片进入忙状态,不响应新的读写操作
读取操作时:
•直接调用读取时序,无需使能,无需额外操作,没有页的限制,读取操作结束后不会进入忙状态,但不能在忙状态时读取
三、SPI外设
简介
•STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成、数据收发等功能,减轻CPU的负担
•可配置8位/16位数据帧、高位先行/低位先行
•时钟频率: fPCLK / (2, 4, 8, 16, 32, 64, 128, 256)
•支持多主机模型、主或从操作
•可精简为半双工/单工通信
•支持DMA
•兼容I2S协议
•
•STM32F103C8T6 硬件SPI资源:SPI1、SPI2
框图

1. 数据通路(核心数据流)
-
发送缓冲区 (TX Buffer):CPU 通过地址和数据总线写入待发送数据,它是 CPU 与外设之间的桥梁。
-
移位寄存器 (Shift Register):这是 SPI 通信的核心。它将并行数据转换为串行数据,通过 MOSI 线逐位发送;同时,它也将 MISO 线上的串行数据转换为并行数据。
-
接收缓冲区 (RX Buffer):存储从移位寄存器接收到的并行数据,CPU 可以通过总线读取。
-
LSBFIRST 控制位:决定数据传输的顺序。0 表示 MSB 优先(默认),1 表示 LSB 优先。
2. 控制与状态模块
-
主控制电路:根据 SPI_CR1 寄存器的配置(如 SPE、MSTR、CPOL、CPHA 等),协调波特率发生器、通信电路和 NSS 引脚的行为。
-
波特率发生器:由 SPI_CR1 的 BR [2:0] 位控制,将系统时钟分频,产生 SCK 时钟信号。
-
通信电路:处理数据的收发时序、CRC 校验等核心通信逻辑。
-
状态寄存器 (SPI_SR):实时反映 SPI 外设的工作状态,如 BSY(忙)、TXE(发送缓冲区空)、RXNE(接收缓冲区非空)等,是驱动轮询或中断实现的关键依据。
3. 寄存器组
-
SPI_CR1:主要控制寄存器,用于配置主 / 从模式、时钟极性 / 相位、波特率、使能 SPI 等。
-
SPI_CR2:次要控制寄存器,用于配置中断使能、DMA 请求、SS 输出使能等。
-
SPI_SR:状态寄存器,反映当前通信状态和错误信息。
基本结构

非连续发送

1.配置与模式
-
模式:非连续全双工模式(BIDIMODE=0, RXONLY=0)
-
时钟配置:CPOL=1(空闲时 SCK 为高),CPHA=1(第二个跳变沿采样)
-
传输数据:连续发送 3 个字节:0xF1、0xF2、0xF3
2. 关键信号与标志
-
SCK:SPI 串行时钟,由主机产生。
-
MOSI:主机输出从机输入数据线,承载串行数据。
-
TXE 标志:发送缓冲区空标志。TXE=1 表示发送缓冲区为空,CPU 可以写入下一个字节。
-
BSY 标志:忙标志。BSY=1 表示 SPI 外设正在进行数据移位操作。
-
发送缓冲器:CPU 写入 SPI_DR 寄存器的位置,数据先存入缓冲区,再进入移位寄存器。
逐帧解析传输流程
我们以发送 0xF1、0xF2、0xF3 为例,拆解整个过程:
阶段 1:启动第一个字节传输
软件写入 0xF1:CPU 将第一个字节 0xF1 写入 SPI_DR 寄存器。
-
此时,数据被存入发送缓冲区。
-
TXE 标志被硬件自动清零(缓冲区非空)。
-
移位寄存器从缓冲区取走 0xF1,开始在 SCK 驱动下逐位发送到 MOSI 线。
-
BSY 标志被硬件置 1,表明通信正在进行。
等待 TXE=1:当移位寄存器将 0xF1 全部移出后,发送缓冲区变空,TXE 标志被硬件置 1。此时,CPU 可以写入下一个字节。
阶段 2:连续发送后续字节
写入 0xF2:软件检测到 TXE=1,将 0xF2 写入 SPI_DR。
-
缓冲区被填充,TXE 清零。
-
移位寄存器立即从缓冲区取走 0xF2,开始连续发送,BSY 保持为 1。
-
当 0xF2 发送完成,缓冲区再次变空,TXE 再次置 1。
写入 0xF3:重复上述过程,写入并发送 0xF3。
阶段 3:结束传输
-
当最后一个字节 0xF3 发送完成后,移位寄存器为空。
-
BSY 标志由硬件清零,表示 SPI 外设已完全空闲。
-
软件通常会在所有字节发送后,等待 BSY=0,以确保总线上的最后一位数据稳定输出,再进行后续操作(如拉低 NSS)。
关键注意事项
TXE 与 BSY 的区别:
-
TXE 反映的是发送缓冲区的状态,用于同步 CPU 和外设的写入速度。
-
BSY 反映的是移位寄存器的状态,用于判断整个 SPI 总线是否真正空闲。
-
在发送完最后一个字节后,必须等待 BSY=0,而不能只看 TXE=1,否则可能在总线仍在传输最后一位时就错误地结束通信(如拉高 NSS)。
非连续传输的特点:
-
如图所示,每个字节的发送之间有明显的间隔,这是因为 CPU 软件在轮询 TXE 标志。
-
如果需要最大化传输效率,可以使用 DMA 或中断模式,让硬件自动处理缓冲区的填充和清空。
数据完整性:
-
严格遵循 “先等 TXE,再写入” 的原则,可以保证数据不会丢失或错位。
-
在与 W25Q64 等外设通信时,这种严格的时序控制是确保指令和数据正确传输的基础。



