Skip to the content.

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 置位验证。本实验不执行页编程、扇区擦除、块擦除、芯片擦除或状态寄存器写入。

适用条件:


一、实验目标

  1. 复用已经验证的 UART、SPI1、CS# 控制和 JEDEC ID 识别能力。
  2. 使用 0x05 读取状态寄存器 1,并打印原始十六进制值。
  3. 使用位运算解析 WIP 和 WEL,区分“器件忙”“写使能已锁存”和 HAL 传输完成。
  4. 记录上电或复位后的初始 WEL,不把某个固定初值当作所有器件的通用结论。
  5. 发送 0x06 写使能命令,再次读取状态寄存器 1,验证 WEL 从 0 变为 1。
  6. 在有限次数的重复测试和一次复位验证中确认现象可复现。
  7. 建立安全边界:本次只观察状态并验证写使能,不执行擦除或编程。

最终目标: 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 创建工程

  1. 新建 STM32CubeMX 工程,选择实际使用的 STM32G030 完整型号。
  2. 工程命名为 G030_SPI_FLASH_Status_Test。
  3. 沿用任务 06 已验证的系统时钟、USART2、SPI1 和 CS# GPIO 配置。
  4. 保存 .ioc,生成代码,完成编译、下载和启动测试。
  5. 不直接复制任务 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 说明 按数据手册填写
本实验禁止发送的命令 页编程、擦除、写状态寄存器等

本阶段验收标准


三、第二阶段:恢复基础通信

3.1 实验目标

先恢复 UART 输出和 JEDEC ID 识别,证明基础通信仍正常,再进行状态寄存器实验。

3.2 编程任务

  1. 完成 printf() 重定向。
  2. 初始化完成后确保 CS# 为高电平。
  3. 输出启动信息。
  4. 使用任务 06 已理解的方式读取 JEDEC ID。
  5. 将 ID 与当前实物数据手册中的期望值比较。
  6. ID 不匹配时停止后续状态实验,不得仅因 HAL 返回 HAL_OK 就继续。

3.3 预期输出

STM32G030 BOOT OK
UART PRINTF OK
SPI1 INIT OK
JEDEC ID = .. .. ..
FLASH ID CHECK OK

本阶段验收标准


四、第三阶段:读取并解析状态寄存器 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 编程任务

  1. 封装 Flash_ReadStatus1(uint8_t *status) 或等价函数。
  2. 拒绝空指针参数。
  3. 拉低 CS#,发送 0x05 并接收一个有效状态字节。
  4. 无论传输结果如何都拉高 CS#。
  5. 只有 HAL 返回 HAL_OK 时才更新输出参数。
  6. 打印 SR1 原始值、WIP 和 WEL。
  7. 上电或复位后记录实际初始 WEL;若为 0,这是常见且合理的现象。
  8. 若 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

本阶段验收标准


五、第四阶段:发送写使能并验证 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 编程任务

  1. 在 ID 检查通过且 WIP=0 后,打印 WRITE ENABLE SEND。
  2. 拉低 CS#,使用 HAL_SPI_Transmit() 或等价方式发送单字节 0x06。
  3. 无论发送成功或失败都恢复 CS# 为高。
  4. 检查 HAL 返回状态;失败则停止。
  5. 立即重新调用状态寄存器读取函数。
  6. 打印写使能后的 SR1、WIP、WEL。
  7. 只有重新读取成功、WIP=0 且 WEL=1 时,本阶段才通过。
  8. 验证完成后立即停止,不发送任何编程、擦除或写状态寄存器命令。

可使用如下常量,避免魔法数字:

#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

本阶段验收标准


六、第五阶段:重复验证与复位观察

6.1 测试 A:冷启动或复位后的初始状态

  1. 复位 MCU;若要验证 Flash 上电默认状态,应对 MCU 与 Flash 完整断电后重新上电。
  2. 在发送 0x06 之前读取 SR1。
  3. 记录 WIP/WEL 的真实值。
  4. 对常见器件,WEL 在复位或上电后可能为 0;最终结论以实测和数据手册为准。
  5. 再发送 0x06 并验证 WEL=1。

判据:日志必须清楚区分“初始状态”和“写使能后状态”,不能先发送 0x06 再声称读到的是上电默认值。

6.2 测试 B:重复验证

连续执行 5 轮以下流程:

  1. 读取 SR1。
  2. 确认 WIP=0。
  3. 发送 0x06。
  4. 再读 SR1。
  5. 判断 WEL=1。
  6. 记录每轮原始 SR1 与判定结果。

本实验不通过编程或擦除来主动清除 WEL,因此“下一轮开始前 WEL 必须为 0”不是通过条件。若需要重新观察默认值,应按手册允许的复位或断电方式进行。

6.3 测试 C:禁止命令审查

检查工程中的 Flash 命令常量和调用路径,确认本实验只需要:

若代码中存在页编程、扇区/块/芯片擦除或写状态寄存器调用,本实验不能验收,必须先移除或确保完全不可达。

6.4 最终判断逻辑

PASS 条件:

  1. UART 和 SPI 初始化正常。
  2. JEDEC ID 与实际器件一致。
  3. 初次 SR1 读取成功。
  4. 发送 0x06 前已确认 WIP=0。
  5. 0x06 发送成功且 CS# 时序正确。
  6. 再次读取 SR1 成功。
  7. WEL 掩码判定为 1,WIP 为 0。
  8. 5 轮重复验证均通过。
  9. 工程未执行任何编程、擦除或状态寄存器写入。

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 速度复测。


八、实验完成标准


九、需要提交的实验成果

  1. 完整工程: 包含 .ioc、全部必要源码和工程配置。
  2. 器件核对记录: 芯片丝印、完整型号、JEDEC ID、0x05、0x06、WIP/WEL 定义及资料页码。
  3. 串口日志: 包含 ID 检查、初始 SR1、WIP/WEL、写使能后 SR1 和最终判定。
  4. 重复验证证据: 5 轮原始状态与每轮结果。
  5. 复位/上电观察记录: 说明采用 MCU 复位还是完整断电重启,并记录发送 0x06 前的状态。
  6. 安全审查结果: 说明工程未执行页编程、擦除或写状态寄存器。
  7. 实验总结: 说明一次遇到的问题、定位过程、解决方法,以及对 WIP、WEL 和命令边界的理解。

十、口头进度汇报参考

开始实验前

今天我会在已经完成 25Q64 JEDEC ID 识别的基础上,继续验证 Flash 的状态管理机制。重点是读取状态寄存器 1,解析 WIP 和 WEL 两个关键状态位,然后发送写使能命令并通过再次读取状态寄存器确认 WEL 是否真正置位。整个实验只做状态读取和写使能验证,不进行擦除或编程,完成后会提交串口日志和状态变化结果。

阶段性汇报

目前基础 SPI 通信和芯片身份复核已经通过,状态寄存器 1 也能够稳定读取。我正在核对 WIP 与 WEL 的位定义,并验证写使能命令前后的状态变化。下一步会完成多轮重复测试和复位后的初始状态观察,重点排除“HAL 发送成功但 Flash 状态没有改变”的误判。

完成汇报

今天已完成 STM32G030 对 25Q64 状态寄存器 1 的读取与解析,能够分别判断 WIP 和 WEL。程序在确认器件空闲后发送写使能命令,并通过重新读取状态寄存器验证 WEL 置位,重复测试结果稳定。同时完成了复位或重新上电后的初始状态记录,并确认实验全程未执行擦除和编程操作。下一步可以在单独任务中学习指定地址读取,再逐步进入带有严格范围保护和读回校验的编程实验。


十一、思考题

  1. WIP=0 和 WEL=0 分别说明什么?二者为什么不能混为一谈?
  2. 为什么 HAL_SPI_Transmit() 返回 HAL_OK 不能证明 WEL 已经置位?
  3. 为什么发送 0x06 后必须再发送 0x05 验证?
  4. 为什么 0x06 和 0x05 需要两个独立的 CS# 片选周期?
  5. 为什么不能用 SR1 == 0x02 代替位掩码判断?
  6. WEL 在复位、上电以及写/擦除完成后的行为为什么必须查具体型号手册?
  7. 若 WIP 一直为 1,应如何区分器件忙、位定义错误和 SPI 通信错误?
  8. 本实验发送写使能却不执行编程或擦除,能够验证什么,又不能验证什么?
  9. 如果 SR1 读取为 0xFF,为什么不能直接认定所有状态位都为 1?
  10. 如何用逻辑分析仪确认 0x06 和 0x05 的命令边界正确?

本次实验重点:独立掌握 SPI Flash 状态寄存器读取、WIP/WEL 位解析、写使能命令时序、状态回读验证、有限超时和安全操作边界。


参考资料

  1. STM32G030x6/x8 官方数据手册(STMicroelectronics)
  2. 实际 25Q64 完整型号的厂家数据手册:必须依据实物确认,不以兼容型号资料替代。
  3. 前置任务:STM32G030 SPI Flash(25Q64)芯片识别实验
  4. STM32 学习任务书模板

下一阶段建议: 在不改写数据的前提下学习 0x03 指定地址读取;完成地址范围和数据观察后,再单独设计包含保护、超时和读回校验的页编程实验。