尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32G031J6M6修改NRST_MODE失败问题实战解析

STM32G031J6M6修改NRST_MODE失败问题实战解析 最近在调一块基于 STM32G031J6M6 的小板子想把复位引脚 NRST 从默认的双向复位模式改成普通复位输入模式结果被 STM32CubeProgrammer 反复提示 Unable to change NRST_MODE前前后后折腾了一个下午。这个报错在 STM32G0 系列上其实不算冷门尤其是 G031J6M6 这种引脚很少的小封装芯片在修改 Option Bytes选项字节时更容易踩中。如果你也遇到过类似情况或者正准备给 G0 系列调整 NRST 复位行为这篇内容应该能帮你少走不少弯路。先从问题本质说起NRST_MODE 不是一个普通寄存器位而是一个必须在复位后由硬件从 Flash 选项字节区加载的配置。这个机制决定了你不能像改一个 GPIO 配置寄存器那样随手写一下就完事修改流程、连接方式、甚至芯片当前的安全等级都会影响最终结果。下面我会从复位模式原理讲起再逐个排查“改不了”的原因最后给出三种可复现的修改方案。1. 先搞清楚 NRST_MODE 是什么为什么有人要改它1.1 STM32G031J6M6 这颗芯片的使用场景STM32G031J6M6 是 STM32G0 系列里非常典型的一颗小封装芯片Cortex-M0 内核主频最高 64MHz内置 32KB Flash、8KB SRAM封装形式常见的是 SOP-8 这种引脚极少的类型。因为封装小、外设丰富、价格便宜很多做传感器采集、小家电控制、简单电机驱动的工程师都喜欢拿它做小型化方案。但小封装带来的直接问题就是引脚极度紧张。8 个引脚里要分配电源、地、SWD 调试口剩下来能做事的引脚本来就没几个。NRST 这个引脚单独占了物理引脚位置虽然它不能复用为普通 GPIO但在整个复位方案的设计上你依然要对它做明确处理默认接一颗 100nF 到 1µF 的电容到地可能还要连外部复位芯片。一旦外部复位电路设计不当NRST_MODE 就成了第一个背锅的配置项。1.2 双向复位与普通复位两种模式到底差在哪在 STM32G0 系列里NRST 引脚有两种工作模式由选项字节中的 NRST_MODE 位决定默认的双向复位模式Bidirectional Reset ModeNRST_MODE0NRST 既是输入也是输出。内部任何一个复位源产生复位事件时NRST 引脚会被内部电路主动拉低一段时间用来复位外部电路同时外部也可以主动拉低 NRST 来复位芯片。这个模式的好处是复位信号可以双向共享外部复位芯片、调试器、看门狗都能通过同一条线协同工作。普通复位输入模式Normal Reset Input ModeNRST_MODE1NRST 只作为输入引脚使用芯片内部复位源不会再把引脚拉低外部给低电平依然可以触发复位。这种模式更适合低功耗应用避免了复位输出驱动带来的额外功耗也防止内部复位信号干扰外部敏感电路。很多人想改成普通模式并不是为了省出这个引脚而是为了解决实际电路问题。比如外部挂了独立的上电时序控制芯片如果芯片内部看门狗或软件复位时把 NRST 拉低可能影响外部复位设备的判断导致系统无法正常上电。改完模式后NRST 就纯粹是一个输入检测引脚系统行为会更可控。这里要特别提醒一点选项字节不是普通寄存器它在上电复位POR或 NRST 复位时才被硬件加载到内部配置寄存器里。所以无论你用哪种方式修改 NRST_MODE改完后都必须要给芯片做一次完整的断电重上电或者拉低 NRST 复位一次新配置才会真正生效。这也是很多“改完没反应”问题的根源。2. 排查思路先确认“改不了”的具体表现遇到 NRST_MODE 改不了第一步不是去试各种命令而是先判断你遇到的是哪一类“改不了”。不同表现对应完全不同的根因盲目操作容易把问题搞得更复杂。2.1 表现一STM32CubeProgrammer 直接报错在 CubeProgrammer 的 Option Bytes 页面里把 NRST Mode 从 Bidirectional 改成 Normal点 Apply 后弹窗报错常见错误包含 Option Bytes programming failed、OB: OPB Programming Error、Data error 等。这类报错说明软件确实尝试写入选项字节但芯片没有接受这次编程。最典型的场景是点击 Apply 时弹出了一个警告提示修改 Option Bytes 会擦除用户 Flash而 CubeProgrammer 默认可能不勾选擦除选项或者你下意识点了 Cancel。G0 系列在部分选项字节编程场景下芯片要求先擦除或重新编程相关区域否则会直接返回编程错误。这时候如果你一直忽略擦除提示就会陷入“怎么改都报错”的循环。另一个常见场景是连接时没有选对模式。如果芯片内部程序已经把 SWD 引脚复用成了普通 GPIO或者芯片正处于某种异常复位状态CubeProgrammer 虽然在连接界面显示成功但实际的调试握手并不稳定此时修改 Option Bytes 也会失败。2.2 表现二改完显示成功实际却没生效CubeProgrammer 提示 Option Bytes 编程成功读回来也变成了目标值但只要一断电重新上电NRST_MODE 又变回默认模式。这种情况比直接报错更让人头疼因为它表面上看起来一切正常实际上芯片根本没有加载新配置。常见原因有两个。第一个是修改后没有做完整的断电重上电只是点了 CubeProgrammer 里的复位按钮。软件复位不一定触发选项字节重新加载很多 STM32 系列必须由 POR 或 NRST 复位才能装载新选项。第二个是芯片在跑用户程序时程序启动阶段主动把选项字节改回了默认值。这种情况在带有 bootloader 或“恢复出厂设置”逻辑的工程里很常见CubeProgrammer 改的配置被用户代码在初始化时覆盖看起来就是“改完不生效”。还有一种隐蔽情况CubeProgrammer 修改成功后你重新连接时看到的值确实是对的目标值但芯片内部实际加载的仍然是旧值因为你连接时使用的复位方式不对调试器的 shadow 寄存器显示和硬件加载不一致。这种情况在 under reset 连接模式下偶尔会出现重新上电后读回才能确认真实状态。2.3 表现三代码里调用 HAL 接口返回错误或卡死排除了 CubeProgrammer 的问题后有些人会改用手写代码的方式修改 NRST_MODE比如在程序里调用 HAL_FLASHEx_OBProgram。结果发现 HAL 函数返回 HAL_ERROR或者调用 HAL_FLASH_OB_Launch 后芯片没有按预期复位甚至程序直接跑飞。这类问题大概率是流程没走完整。修改选项字节的完整流程包含解锁 Flash、解锁选项字节、修改目标配置、编程写入、启动加载等步骤缺少任何一环都可能失败。很多人在修改用户选项字节时没有先读回当前选项字节配置导致编程时把其他关键选项覆盖了虽然 NRST_MODE 写进去了但其他配置异常导致启动时校验失败最终芯片回退到默认值。此外直接在代码里操作 FLASH-OPTR 寄存器也是一大坑。Option Bytes 区域必须通过 Flash 控制器接口编程单纯往寄存器的影子值里写数据断电后不会保留。真正可靠的代码修改方式一定要走 HAL 或 LL 库提供的选项字节编程接口。3. 五大常见根因与解决步骤3.1 选项字节没有解锁或连接阶段不对STM32G0 的选项字节区域在上电后默认处于锁定状态不解锁直接写入Flash 控制器会直接拒绝。CubeProgrammer 正常会自动完成解锁但如果你修改时连接不稳定或者芯片正处于低功耗模式解锁操作可能没有成功。解决思路很简单在 CubeProgrammer 中不要用 hot plug 模式连接尽量使用 Mode Under Reset。这种模式下调试器会先把 NRST 拉低让芯片处于复位状态然后在复位释放瞬间建立连接。对于一开始就连不上、或者连接成功后操作异常的情况under reset 是最稳的选择。连接稳定后再进入 Option Bytes 页面修改 NRST_MODE成功率会高很多。代码修改时也同理。HAL 库的流程是先调用 HAL_FLASH_Unlock() 解锁 Flash再调用 HAL_FLASH_OB_Unlock() 解锁选项字节。如果你在程序里跳过了第二步后续的编程操作必然失败。检查代码时优先确认这两个解锁函数都被正确调用且返回值没有错误。3.2 修改选项字节与 Flash 擦除的关系这是最容易被误判的根因。在 STM32G0 系列上修改部分选项字节会触发 Flash 内容的擦除尤其是与读保护、写保护相关的配置。CubeProgrammer 在检测到需要擦除时会弹出确认框如果这个确认框被忽略或取消修改操作就会直接失败报错信息就是那串 Option Bytes programming failed。很多工程师不理解“改个复位模式为什么要擦程序”其实这是芯片的保护机制选项字节决定了 Flash 的访问权限如果同步修改了保护相关选项芯片必须通过擦除来确保新的安全状态被连贯加载。NRST_MODE 本身虽然不直接涉及 Flash 保护但它在用户选项字节区域里和其他选项共享同一套编程流程某些情况下工具会选择全片擦除的方式来简化操作。实操建议是改 NRST_MODE 之前先把当前 Flash 完整读取备份成 .hex 或 .bin 文件。然后在 CubeProgrammer 中点 Apply 时如果弹出擦除确认框直接确认擦除等修改完成后再把备份的固件烧回去。不要为了保留 Flash 里的旧程序而强行取消擦除提示那样只会陷入“改不了”的死循环。3.3 RDP 读保护等级把选项字节锁死了这个原因最容易踩但也很少有人第一时间想到。如果芯片的选项字节里 RDP读保护等级不是 Level 0而是 Level 1 或 Level 2那么通过调试器修改选项字节会受到严格限制。Level 1 状态下调试口仍然可以有限访问但修改选项字节可能被拒绝或者要求先执行整片擦除将 RDP 降回 Level 0。Level 2 则是永久锁定状态调试口完全关闭任何通过调试器修改选项字节的操作都会失败。如果芯片被设置过 Level 2基本只能换一片芯片处理。排查方法很简单在 CubeProgrammer 的 Option Bytes 页面里直接看 RDP 等级。如果显示不是 Level 0先用 Remove Protection 功能解除读保护这个过程会擦除整个 Flash需要提前做好备份。解除后再修改 NRST_MODE就不会被 RDP 挡路了。3.4 NRST 被外部硬件拉低芯片一直处于复位状态回到标题里这颗 STM32G031J6M6SOP-8 封装的引脚间距很小如果开发板上 NRST 引脚的飞线、排针、复位芯片连接有问题导致 NRST 长期处于低电平芯片就会一直处于复位状态所有调试操作都会失败。这种故障有个典型特征CubeProgrammer 基本连不上目标芯片即使选择 under reset 模式也可能在连接瞬间又因为外部拉低而立刻回到复位状态。这时候不要急着折腾软件先拿万用表量一下 NRST 引脚的直流电平。正常工作时应该接近 VDD高电平如果量到接近 0V优先断开外部复位电路、飞线和电容再重新测量。另外NRST 引脚外围的电容也很关键。如果电容值取得太大比如 10µF复位释放时间会变长under reset 连接模式下调试器可能等不到芯片完全启动就超时。G0 系列手册推荐的 NRST 滤波电容通常是 100nF 到 1µF 范围。如果你在调试的时候发现连接时好时坏可以换一颗更小的电容试试或者干脆先拿掉电容确认修改成功后再加回去。3.5 用户程序每次上电都把配置改回去最后一种根因比较隐蔽。目标芯片里烧录的程序如果自己就包含选项字节修改逻辑比如 bootloader 启动时强制把 NRST_MODE 设置为双向模式那么你用 CubeProgrammer 再怎么改只要一执行用户程序配置就会被覆盖回去。如何确认是这个原因先修改 NRST_MODE 成功后不要运行用户程序直接再次连接并读回选项字节。如果值是你要的目标值但一执行用户程序再读回就变回旧值基本可以断定是程序主动改写。解决办法有两种一种是临时烧录一个空程序让芯片跑一个空 main修改完选项字节后再烧回正式固件另一种是在工程代码里定位到写选项字节的地方把相关代码去掉或加条件判断确保不在每次启动时覆盖已有配置。4. 实操三种方式修改 NRST_MODE附完整步骤4.1 方式一STM32CubeProgrammer 图形界面修改这是最推荐给新手的方式全程可视化步骤清晰。前提是你已经正确连接好 ST-Link 或兼容调试器。第一步打开 STM32CubeProgrammer在右上角选择连接方式。接口选 SWDMode 选择 Under Reset然后点击 Connect。如果正常连接左侧导航栏会显示芯片型号 STM32G031J6M6。第二步进入 Option Bytes 页面。在左侧菜单里找到 Option Bytes点击后在主界面能看到 OB 配置列表。找到 NRST Mode 对应行默认值一般是 Bidirectional Reset Mode双向复位模式。把这个值改成你要的模式比如 Normal Reset Input Mode。第三步点右上角的 Apply 按钮。此时如果弹出任何关于擦除 Flash 的提示不要急着取消仔细看一下提示内容。确认可以接受擦除后点确认继续。如果 CubeProgrammer 提示编程成功说明选项字节已经写入。第四步断开连接移除目标板电源等待几秒后重新上电。这一步非常关键只有完整断电后重新上电新的 NRST_MODE 才会被硬件加载。上电后再用 CubeProgrammer 连接进入 Option Bytes 页面确认 NRST Mode 已经是目标值。注意CubeProgrammer 版本差异会导致界面文字略有不同但核心步骤一致。如果 Apply 后弹出 Error: Option bytes programming failed优先检查你是不是取消了一个需要擦除 Flash 的确认框。4.2 方式二命令行工具 STM32_Programmer_CLI如果需要在产线上批量配置芯片或者不想打开图形界面可以用命令行工具完成同样的操作。STM32CubeProgrammer 安装目录下自带 STM32_Programmer_CLI 可执行文件。修改 NRST_MODE 为普通复位输入模式的命令大致如下STM32_Programmer_CLI -c portSWD modeUR -ob NRST_MODE1如果想把 NRST_MODE 改回双向复位模式把最后的值换成 0STM32_Programmer_CLI -c portSWD modeUR -ob NRST_MODE0命令里的-c portSWD modeUR表示使用 SWD 接口并在复位期间连接-ob NRST_MODE1表示把选项字节中的 NRST_MODE 设置为 1。不同版本的 STM32_Programmer_CLI 对参数名的解析略有差别有些版本接受Normal或Bidirectional这样的字符串值如果不识别就改用数字 0/1。如果修改过程中提示需要擦除 Flash可以先把固件备份好然后单独执行一次全片擦除STM32_Programmer_CLI -c portSWD modeUR -e all擦除完成后再执行选项字节修改命令。修改完成后同样要断电重上电再执行选项字节读取命令确认STM32_Programmer_CLI -c portSWD -ob displ这条命令会列出当前所有选项字节的状态注意看 NRST_MODE 或类似名称的字段。4.3 方式三HAL 库代码在用户程序里修改有时候现场没有调试器只能通过芯片里已有的程序来修改本身。这种情况下需要在固件里加入一段选项字节编程代码通过自定义触发条件执行一次。下面是一个基于 STM32G0 系列 HAL 库的示例函数功能是把 NRST_MODE 设置为普通复位输入模式#include stm32g0xx_hal.h void Set_NRST_Mode_Normal(void) { FLASH_OBProgramInitTypeDef ob {0}; /* 1. 解锁 Flash 和选项字节 */ HAL_FLASH_Unlock(); HAL_FLASH_OB_Unlock(); /* 2. 读取当前选项字节配置避免覆盖其他关键项 */ HAL_FLASHEx_OBGetConfig(ob); /* 3. 配置需要修改的类型为用户选项字节并修改 NRST_MODE */ ob.OptionType OPTIONBYTE_USER; ob.USERType OB_USER_NRST_MODE; ob.USERConfig OB_USER_NRST_MODE_RESET; /* 对应普通复位输入模式 */ /* 4. 写入选项字节 */ if (HAL_FLASHEx_OBProgram(ob) ! HAL_OK) { Error_Handler(); } /* 5. 启动选项字节加载执行后芯片会立即复位 */ HAL_FLASH_OB_Launch(); }不同版本的 HAL 库在宏命名上可能有差异比如OB_USER_NRST_MODE_RESET和OB_USER_NRST_MODE_SET的映射方向建议在编译前先查一下你使用的stm32g0xx_hal_flash_ex.h头文件里这两个宏的具体定义。如果你是想改回双向复位模式把USERConfig换成对应的另一个宏即可。这里有两个必须注意的坑第一个是HAL_FLASH_OB_Launch()调用后芯片会立刻复位。如果你的整个程序都依赖每次启动时重新调用Set_NRST_Mode_Normal()那么这次复位后又会被你的代码改一遍等于没有修改。所以这段代码最好放在一个通过外部信号触发的引导模块里并且执行后设置一个标志位保证只写一次。第二个是不要试图直接修改FLASH-OPTR寄存器来绕过流程。FLASH-OPTR只是加载后的影子寄存器直接写它不会进入 Flash 的选项字节区断电后一定丢。所有修改都必须通过HAL_FLASHEx_OBProgram或等价的 Flash 编程接口完成。4.4 修改后必须做的验证与动作不管用哪种方式修改最终都要做一轮验证否则无法确定配置真的生效。首先是最直接的软件验证重新连接 CubeProgrammer在 Option Bytes 页面读回 NRST_MODE确认值和目标一致。这一步能确认选项字节区的值与预期一致但还不能百分百保证硬件已经加载。其次是硬件验证用示波器或万用表观察 NRST 引脚。如果是双向复位模式触发一次看门狗复位或软件复位NRST 引脚会出现一个低电平脉冲如果是普通复位输入模式执行同样操作时 NRST 引脚不会主动被拉低只有外部给一个低电平信号时芯片才会复位。最后是断电重上电验证断开所有调试器连接完全断电再上
返回列表