STM32G030 SPI Flash 状态寄存器读取与写使能验证实验任务书
任务名称: 基于 STM32G030 的 SPI Flash 状态寄存器读取与写使能验证实验
实验平台: STM32G030F6P6、已完成 JEDEC ID 识别的 25Q64 SPI Flash 模块
使用外设: USART2、SPI1、GPIO、25Q64
开发工具: STM32CubeMX + Keil MDK(或现有 IDE)
工程名称: G030_SPI_FLASH_Status_Test
前置任务: 已完成任务 06,能够稳定读取实际 Flash 的 JEDEC ID,并已记录芯片厂家和完整型号。
任务要求: 在已验证的 SPI 接线和参数基础上独立创建工程,分阶段完成状态寄存器 1 读取、WIP/WEL 位解析、写使能命令发送与 WEL 置位验证。本实验不执行页编程、扇区擦除、块擦除、芯片擦除或状态寄存器写入。
适用条件:
- 本任务以常见 25Q64 SPI NOR Flash 的指令习惯为例:
0x05读取状态寄存器 1,0x06写使能。 - 常见器件中,状态寄存器 1 的 bit0 为 WIP/BUSY,bit1 为 WEL;但命令、位位置、位名称、读写属性和时序必须以实际 Flash 完整型号的数据手册为准。
- 若实物手册定义不同,必须修改程序和验收判据,不能把本文示例当作所有 25Q64 的统一规格。
- WEL 通常在上电、掉电或复位后为 0,也会在某些写入、擦除或状态寄存器操作完成后由器件自动清零;不得预设启动时 WEL 必为 1。
0x06只设置写使能锁存位,不会单独改写存储阵列。本实验在确认 WEL=1 后停止,不发送任何会改变 Flash 内容的命令。
一、实验目标
- 复用已经验证的 UART、SPI1、CS# 控制和 JEDEC ID 识别能力。
- 使用
0x05读取状态寄存器 1,并打印原始十六进制值。 - 使用位运算解析 WIP 和 WEL,区分“器件忙”“写使能已锁存”和 HAL 传输完成。
- 记录上电或复位后的初始 WEL,不把某个固定初值当作所有器件的通用结论。
- 发送
0x06写使能命令,再次读取状态寄存器 1,验证 WEL 从 0 变为 1。 - 在有限次数的重复测试和一次复位验证中确认现象可复现。
- 建立安全边界:本次只观察状态并验证写使能,不执行擦除或编程。
最终目标: JEDEC ID 识别通过后,读取并解析状态寄存器 1;当 WIP=0 时发送 0x06,再读状态寄存器 1。只有 SPI 操作均成功、WIP 判定有效且 WEL=1 时,才能输出:
FLASH WRITE ENABLE VERIFY PASS
若通信失败、ID 不匹配、WIP 持续为 1、状态值无效或发送 0x06 后 WEL 仍为 0,应输出 FAIL,并停止本轮正常流程。
二、第一阶段:创建工程并核对器件资料
2.1 创建工程
- 新建 STM32CubeMX 工程,选择实际使用的 STM32G030 完整型号。
- 工程命名为
G030_SPI_FLASH_Status_Test。 - 沿用任务 06 已验证的系统时钟、USART2、SPI1 和 CS# GPIO 配置。
- 保存
.ioc,生成代码,完成编译、下载和启动测试。 - 不直接复制任务 06 的完整程序;允许参考接线、外设参数和已理解的底层辅助函数。
2.2 推荐配置
| 项目 | 配置 | 说明 |
|---|---|---|
| UART | 115200、8N1 | 若实际硬件不同,记录真实配置 |
| SPI | Full-Duplex Master、8 Bits、MSB First | 与任务 06 已验证配置一致 |
| SPI Mode | Mode 0(CPOL=0、CPHA=0) | 最终以实际器件手册为准 |
| NSS | Software | CS# 使用普通 GPIO 控制 |
| SPI 分频 | 沿用已稳定读取 ID 的值 | 记录实际 SCK 频率 |
| 中断 / DMA | 不启用 | 使用阻塞式 HAL 接口 |
| CS# 空闲电平 | High | 每条独立指令使用一次完整片选周期 |
2.3 数据手册核对记录
开始编码前,在实验记录中填写:
| 核对项 | 实际结果 |
|---|---|
| 芯片完整型号 / 丝印 | 实测填写 |
| JEDEC ID | 沿用任务 06 实测值 |
| Read Status Register-1 命令 | 数据手册确认,常见值为 0x05 |
| Write Enable 命令 | 数据手册确认,常见值为 0x06 |
| WIP/BUSY 位 | 数据手册确认,常见为 SR1 bit0 |
| WEL 位 | 数据手册确认,常见为 SR1 bit1 |
| 上电 / 复位后的 WEL 说明 | 按数据手册填写 |
| 本实验禁止发送的命令 | 页编程、擦除、写状态寄存器等 |
本阶段验收标准
- 工程可编译、下载并运行,
.ioc已保存。 - UART、SPI1 和 CS# 配置与已通过的 ID 实验一致。
- 已确认芯片完整型号并查阅对应数据手册。
- 已核对
0x05、0x06、WIP 和 WEL 的真实定义。 - 代码中不存在编程、擦除或写状态寄存器命令。
三、第二阶段:恢复基础通信
3.1 实验目标
先恢复 UART 输出和 JEDEC ID 识别,证明基础通信仍正常,再进行状态寄存器实验。
3.2 编程任务
- 完成
printf()重定向。 - 初始化完成后确保 CS# 为高电平。
- 输出启动信息。
- 使用任务 06 已理解的方式读取 JEDEC ID。
- 将 ID 与当前实物数据手册中的期望值比较。
- ID 不匹配时停止后续状态实验,不得仅因 HAL 返回
HAL_OK就继续。
3.3 预期输出
STM32G030 BOOT OK
UART PRINTF OK
SPI1 INIT OK
JEDEC ID = .. .. ..
FLASH ID CHECK OK
本阶段验收标准
- UART 输出稳定、无乱码。
- JEDEC ID 与实际器件一致。
- ID 读取失败或不匹配时,后续写使能验证不会执行。
- 能说明 HAL 成功与器件响应正确不是同一件事。
四、第三阶段:读取并解析状态寄存器 1
4.1 实验目标
发送 0x05,读取状态寄存器 1 的原始值,解析 WIP 和 WEL。
4.2 基础知识
对常见 25Q64 器件,状态寄存器 1 常见定义如下:
| 位 | 常见名称 | 本实验关注含义 |
|---|---|---|
| bit0 | WIP / BUSY | 1 表示内部写入或擦除等操作忙;0 表示就绪 |
| bit1 | WEL | 1 表示写使能锁存有效;0 表示未使能 |
| bit2~bit7 | 保护或状态位 | 只记录原始值,按实际手册解释 |
位解析示例:
uint8_t wip = (sr1 >> 0) & 0x01;
uint8_t wel = (sr1 >> 1) & 0x01;
不要用“状态寄存器等于某个固定值”作为唯一判断。除 WIP/WEL 外的保护位可能因器件配置不同而变化。
4.3 SPI 时序
一次状态寄存器读取应在同一个 CS# 低电平窗口内完成:
CS# High -> Low -> 发送 0x05 -> 继续提供 8 个时钟并接收 SR1 -> High
可使用 HAL_SPI_TransmitReceive() 一次传输两个字节,或在保持 CS# 为低期间先发送命令再接收一个字节。无论 HAL 成功或失败,都必须恢复 CS# 为高。
最小数据结构示例:
uint8_t tx[2] = {0x05, 0xFF};
uint8_t rx[2] = {0};
若采用该方式,rx[0] 是发送命令期间收到的无效字节,rx[1] 才是状态寄存器值。
4.4 编程任务
- 封装
Flash_ReadStatus1(uint8_t *status)或等价函数。 - 拒绝空指针参数。
- 拉低 CS#,发送
0x05并接收一个有效状态字节。 - 无论传输结果如何都拉高 CS#。
- 只有 HAL 返回
HAL_OK时才更新输出参数。 - 打印 SR1 原始值、WIP 和 WEL。
- 上电或复位后记录实际初始 WEL;若为 0,这是常见且合理的现象。
- 若 WIP=1,使用有限次数或有限总时长轮询等待 WIP=0;超时则停止,不发送写使能。
4.5 预期输出
以下只展示一种常见情况,实际 SR1 高位可能不同:
STATUS1 READ START
SR1 BEFORE = 0x00
WIP BEFORE = 0
WEL BEFORE = 0
FLASH READY
如果器件忙:
SR1 BEFORE = 0x01
WIP BEFORE = 1
FLASH BUSY, WAITING
超过自定的有限等待上限时:
FLASH READY TIMEOUT
FLASH WRITE ENABLE VERIFY FAIL
本阶段验收标准
- 正确读取并打印 SR1 原始值。
- 能用位运算分别得到 WIP 和 WEL。
- 能解释 WIP=0 与 WEL=0 的区别。
- 不会把启动时 WEL=0 误判为通信故障。
- WIP 持续为 1 时有超时退出,不会无限阻塞。
五、第四阶段:发送写使能并验证 WEL
5.1 实验目标
在 Flash 已就绪的前提下发送 0x06,然后通过新的 0x05 指令验证 WEL=1。
5.2 正确指令边界
Write Enable (0x06) 是一条独立指令:
第一次片选:CS# Low -> 发送 0x06 -> CS# High
第二次片选:CS# Low -> 发送 0x05 -> 接收 SR1 -> CS# High
必须先结束 0x06 的片选周期,再开始 0x05。不能在一次连续的 CS# 低电平期间把两条独立指令直接拼接。
5.3 编程任务
- 在 ID 检查通过且 WIP=0 后,打印
WRITE ENABLE SEND。 - 拉低 CS#,使用
HAL_SPI_Transmit()或等价方式发送单字节0x06。 - 无论发送成功或失败都恢复 CS# 为高。
- 检查 HAL 返回状态;失败则停止。
- 立即重新调用状态寄存器读取函数。
- 打印写使能后的 SR1、WIP、WEL。
- 只有重新读取成功、WIP=0 且 WEL=1 时,本阶段才通过。
- 验证完成后立即停止,不发送任何编程、擦除或写状态寄存器命令。
可使用如下常量,避免魔法数字:
#define FLASH_CMD_READ_SR1 0x05U
#define FLASH_CMD_WRITE_ENABLE 0x06U
#define FLASH_SR1_WIP_MASK 0x01U
#define FLASH_SR1_WEL_MASK 0x02U
5.4 预期输出
WRITE ENABLE SEND
WRITE ENABLE COMMAND OK
SR1 AFTER = 0x02
WIP AFTER = 0
WEL AFTER = 1
WEL VERIFY OK
这里的 0x02 仅为其他状态位均为 0 时的示例;实际判定应使用掩码检查 WIP/WEL,不要求 SR1 整字节等于 0x02。
失败示例:
WRITE ENABLE COMMAND OK
SR1 AFTER = 0x00
WEL AFTER = 0
WEL VERIFY FAIL
本阶段验收标准
0x06使用独立的 CS# 片选周期。- 发送后通过新的
0x05读取验证,而不是凭发送成功推断 WEL。 - HAL 错误、状态读取错误或 WEL=0 时均不报告通过。
- WEL 判定使用位掩码,不依赖 SR1 的固定整字节值。
- 本阶段没有发送任何会修改 Flash 内容的命令。
六、第五阶段:重复验证与复位观察
6.1 测试 A:冷启动或复位后的初始状态
- 复位 MCU;若要验证 Flash 上电默认状态,应对 MCU 与 Flash 完整断电后重新上电。
- 在发送
0x06之前读取 SR1。 - 记录 WIP/WEL 的真实值。
- 对常见器件,WEL 在复位或上电后可能为 0;最终结论以实测和数据手册为准。
- 再发送
0x06并验证 WEL=1。
判据:日志必须清楚区分“初始状态”和“写使能后状态”,不能先发送 0x06 再声称读到的是上电默认值。
6.2 测试 B:重复验证
连续执行 5 轮以下流程:
- 读取 SR1。
- 确认 WIP=0。
- 发送
0x06。 - 再读 SR1。
- 判断 WEL=1。
- 记录每轮原始 SR1 与判定结果。
本实验不通过编程或擦除来主动清除 WEL,因此“下一轮开始前 WEL 必须为 0”不是通过条件。若需要重新观察默认值,应按手册允许的复位或断电方式进行。
6.3 测试 C:禁止命令审查
检查工程中的 Flash 命令常量和调用路径,确认本实验只需要:
0x9F:JEDEC ID;0x05:读取状态寄存器 1;0x06:写使能。
若代码中存在页编程、扇区/块/芯片擦除或写状态寄存器调用,本实验不能验收,必须先移除或确保完全不可达。
6.4 最终判断逻辑
PASS 条件:
- UART 和 SPI 初始化正常。
- JEDEC ID 与实际器件一致。
- 初次 SR1 读取成功。
- 发送
0x06前已确认 WIP=0。 0x06发送成功且 CS# 时序正确。- 再次读取 SR1 成功。
- WEL 掩码判定为 1,WIP 为 0。
- 5 轮重复验证均通过。
- 工程未执行任何编程、擦除或状态寄存器写入。
6.5 最终预期输出
========================================
STM32G030 SPI FLASH STATUS TEST
========================================
UART PRINTF OK
SPI1 INIT OK
JEDEC ID = .. .. ..
FLASH ID CHECK OK
STATUS1 READ START
SR1 BEFORE = 0x..
WIP BEFORE = 0
WEL BEFORE = 0
WRITE ENABLE SEND
WRITE ENABLE COMMAND OK
SR1 AFTER = 0x..
WIP AFTER = 0
WEL AFTER = 1
WEL VERIFY OK
REPEAT VERIFY COUNT = 5
REPEAT VERIFY OK
NO ERASE OR PROGRAM COMMAND EXECUTED
FLASH WRITE ENABLE VERIFY PASS
========================================
初始 WEL 若实测为 1,应打印真实结果并分析原因,不得为了匹配示例伪造为 0。只要后续流程与实际手册一致、WEL 验证有效,便可按明确判据验收。
七、常见问题与排查
| 现象 | 优先排查 |
|---|---|
| UART 无输出或乱码 | 波特率、时钟、共地、UART 句柄、重定向 |
| JEDEC ID 读取失败 | 供电、CS#、SPI Mode、MOSI/MISO、实际芯片型号 |
SR1 总是 0xFF |
MISO 浮空、CS# 未拉低、Flash 未供电、命令/时序错误 |
SR1 总是 0x00 |
MISO 被拉低、命令未送达;也可能是合法状态,先用 ID 与波形交叉验证 |
| WIP 一直为 1 | 位定义是否对应实际型号、状态字节索引是否正确、器件是否真的忙、SPI 模式是否错误 |
0x06 后 WEL 仍为 0 |
命令值、CS# 独立周期、WP#/HOLD#/RESET# 电平、器件保护/安全模式、型号差异 |
| HAL 返回 OK,但 WEL 不变 | HAL 只说明 MCU 侧传输完成,应检查返回状态位和逻辑分析仪波形 |
| 初始 WEL 不是示例值 | 记录真实复位方式和状态;核对是否在此前代码中已发送 0x06 |
| 连续读取结果不稳定 | 供电、去耦、接线长度、SPI 频率、CS# 时序 |
| 第二次命令无响应 | 第一条命令后 CS# 是否拉高、命令间是否形成完整边界 |
建议排查顺序:先确认 JEDEC ID,再核对数据手册命令和位定义,然后观察 CS#、SCK、MOSI、MISO 波形,最后降低 SPI 速度复测。
八、实验完成标准
- 独立工程可编译、下载和运行,
.ioc已保存。 - 已记录实际 Flash 完整型号、JEDEC ID、命令和状态位定义。
- UART 与 JEDEC ID 基础测试通过。
- 能读取并打印 SR1 原始值。
- 能正确解析 WIP 和 WEL。
- WIP 忙等待具有有限超时。
- 能使用独立片选周期发送
0x06。 - 发送后再次读取 SR1,并以 WEL=1 作为验证依据。
- 5 轮重复验证通过。
- 完成复位或重新上电后的初始状态观察。
- 全程未执行擦除、编程或写状态寄存器。
- 异常时不误报 PASS。
- 正确输出
FLASH WRITE ENABLE VERIFY PASS。
九、需要提交的实验成果
- 完整工程: 包含
.ioc、全部必要源码和工程配置。 - 器件核对记录: 芯片丝印、完整型号、JEDEC ID、
0x05、0x06、WIP/WEL 定义及资料页码。 - 串口日志: 包含 ID 检查、初始 SR1、WIP/WEL、写使能后 SR1 和最终判定。
- 重复验证证据: 5 轮原始状态与每轮结果。
- 复位/上电观察记录: 说明采用 MCU 复位还是完整断电重启,并记录发送
0x06前的状态。 - 安全审查结果: 说明工程未执行页编程、擦除或写状态寄存器。
- 实验总结: 说明一次遇到的问题、定位过程、解决方法,以及对 WIP、WEL 和命令边界的理解。
十、口头进度汇报参考
开始实验前
今天我会在已经完成 25Q64 JEDEC ID 识别的基础上,继续验证 Flash 的状态管理机制。重点是读取状态寄存器 1,解析 WIP 和 WEL 两个关键状态位,然后发送写使能命令并通过再次读取状态寄存器确认 WEL 是否真正置位。整个实验只做状态读取和写使能验证,不进行擦除或编程,完成后会提交串口日志和状态变化结果。
阶段性汇报
目前基础 SPI 通信和芯片身份复核已经通过,状态寄存器 1 也能够稳定读取。我正在核对 WIP 与 WEL 的位定义,并验证写使能命令前后的状态变化。下一步会完成多轮重复测试和复位后的初始状态观察,重点排除“HAL 发送成功但 Flash 状态没有改变”的误判。
完成汇报
今天已完成 STM32G030 对 25Q64 状态寄存器 1 的读取与解析,能够分别判断 WIP 和 WEL。程序在确认器件空闲后发送写使能命令,并通过重新读取状态寄存器验证 WEL 置位,重复测试结果稳定。同时完成了复位或重新上电后的初始状态记录,并确认实验全程未执行擦除和编程操作。下一步可以在单独任务中学习指定地址读取,再逐步进入带有严格范围保护和读回校验的编程实验。
十一、思考题
- WIP=0 和 WEL=0 分别说明什么?二者为什么不能混为一谈?
- 为什么
HAL_SPI_Transmit()返回HAL_OK不能证明 WEL 已经置位? - 为什么发送
0x06后必须再发送0x05验证? - 为什么
0x06和0x05需要两个独立的 CS# 片选周期? - 为什么不能用
SR1 == 0x02代替位掩码判断? - WEL 在复位、上电以及写/擦除完成后的行为为什么必须查具体型号手册?
- 若 WIP 一直为 1,应如何区分器件忙、位定义错误和 SPI 通信错误?
- 本实验发送写使能却不执行编程或擦除,能够验证什么,又不能验证什么?
- 如果 SR1 读取为
0xFF,为什么不能直接认定所有状态位都为 1? - 如何用逻辑分析仪确认
0x06和0x05的命令边界正确?
本次实验重点:独立掌握 SPI Flash 状态寄存器读取、WIP/WEL 位解析、写使能命令时序、状态回读验证、有限超时和安全操作边界。
参考资料
- STM32G030x6/x8 官方数据手册(STMicroelectronics)
- 实际 25Q64 完整型号的厂家数据手册:必须依据实物确认,不以兼容型号资料替代。
- 前置任务:STM32G030 SPI Flash(25Q64)芯片识别实验
- STM32 学习任务书模板
下一阶段建议: 在不改写数据的前提下学习 0x03 指定地址读取;完成地址范围和数据观察后,再单独设计包含保护、超时和读回校验的页编程实验。