这一章在干嘛?
SPI 实验:SPI 四线制协议、W25Q64 NOR Flash、模式 0/1/2/3、HAL_SPI_TransmitReceive。从此 Flash / SD 卡 / 屏幕一通百通。
27.1 SPI 及 NOR Flash 介绍
27.1.1 SPI 协议
SPI(Serial Peripheral Interface):四线制同步串行总线。
| 信号 | 方向 | 作用 |
|---|---|---|
| SCK | 主机→从机 | 时钟 |
| MOSI | 主机→从机 | 主机发从机收 |
| MISO | 从机→主机 | 从机发主机收 |
| NSS | 主机→从机 | 片选(低有效) |
原书图 27.1.1.1:SPI 总线拓扑
四种模式(CPOL × CPHA):
| 模式 | CPOL | CPHA | 空闲 SCL | 采样边沿 |
|---|---|---|---|---|
| 0 | 0 | 0 | 低 | 上升沿 |
| 1 | 0 | 1 | 低 | 下降沿 |
| 2 | 1 | 0 | 高 | 下降沿 |
| 3 | 1 | 1 | 高 | 上升沿 |
W25Q64 / 多数 Flash 用模式 0 或 3,SD 卡用模式 0。
27.1.2 W25Q64
W25Q64 是 64 Mbit(8 MB)SPI NOR Flash:
- 256 块 × 16 扇区 × 4096 字节 = 8 MB;
- 支持标准 SPI(80 MHz)/ Dual SPI / Quad SPI;
- 支持页编程(256 字节)、扇区擦除、整片擦除。
原书图 27.1.2.1:W25Q64 框图
常用命令:
| 命令 | 值 | 作用 |
|---|---|---|
| 读 ID | 0x9F | 读 JEDEC ID |
| 读数据 | 0x03 | 低速读 |
| 页编程 | 0x02 | 写一页 |
| 扇区擦除 | 0x20 | 擦 4 KB |
| 块擦除 | 0xD8 | 擦 64 KB |
| 读状态寄存器 | 0x05 | 检查 BUSY 位 |
27.2 硬件设计
SPI2 复用引脚:PB13=SCK, PB14=MISO, PB15=MOSI, PB12=NSS。
原书图 27.2.1:SPI Flash 硬件连接
27.3 程序设计
27.3.1 CubeMX 配置
- SPI2 → Full-Duplex Master, 8-bit, MSB First
- Prescaler → /2 = 42 MHz(最高 80 MHz 受限于 Flash)
- CPOL=Low, CPHA=1 Edge(模式 0)
27.3.2 关键代码
uint8_t cmd = 0x9F;
uint8_t id[3];
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2, &cmd, 1, 100);
HAL_SPI_Receive(&hspi2, id, 3, 100);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
// id 应为 0xEF, 0x40, 0x17
读写流程:
- 读:片选 → 命令 0x03 → 24 位地址 → 接收数据 → 释放;
- 写:写使能 0x06 → 等待 → 命令 0x02 → 24 位地址 → 数据 → 释放 → 等待 BUSY=0。
原书图 27.3.2.1:SPI Flash 读写流程图
27.3.3 DMA 加速
大数据量用 DMA:
HAL_SPI_Transmit_DMA(&hspi2, tx, len);
HAL_SPI_Receive_DMA(&hspi2, rx, len);
27.4 下载验证
读 ID → 0xEF4017;写入字符串 → 复位后读出对比一致。
写之前必须擦除:Flash 只能把 1 写成 0,不能反过来,所以必须先擦除(1)再写。
SPI 至少需要几根线?
4 根(SCK / MOSI / MISO / NSS)。
W25Q64 容量多大?
64 Mbit = 8 MB。
SPI Flash 写之前为什么必须先擦?
Flash 只能把 1 写成 0,不能反向。