ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32MP157-M4-SRAM调试踩坑-flash脚本不跑main

STM32MP157-M4-SRAM调试踩坑-flash脚本不跑main STM32MP157 M4 SRAM 调试踩坑OpenOCD unknown-state、AP write error、脚本 resume 直接 shutdown 不跑 main技术博客面向 STM32MP157 M4 核 LiteOS-M 移植的开发者一句话结论一键下载脚本「看着全部成功、LED 却不闪」问题几乎不在你的代码而在脚本的 halt 时机、shutdown 时机、向量表写入地址这三处。本文把这条最隐蔽的坑一次性讲透。环境Windows OpenOCD arm-none-eabi-gcc MakefileM4 内核程序直接下载运行在内部 SRAM0x10000000不烧写 FlashA7 不参与 M4 程序加载。摘要运行一键下载脚本flash-m4.batOpenOCD 输出一切看着正常但板子 LED 不闪烁、程序没跑起来用手动 GDB 连接调试却一切正常可以单步、可以跑 main。本文讲清楚target was in unknown state when halt was requested与AP write error, reset will not halt这两条高频告警的真相以及旧脚本init → halt → resume → shutdown命令链里埋着的三个致命问题并给出最小改动的修复方案与验证标准。 适用场景STM32MP157 M4 独立运行在内部 SRAM、LiteOS-M 操作系统、GCC Makefile 裸金属开发不使用 Keil、不使用 STM32CubeIDE。上一篇讲 GDB 交互调试的坑本篇讲一键脚本的坑两篇互补。一、现象总览运行一键下载脚本flash-m4.bat控制台输出看着一切正常但板子 LED 不闪烁、程序没跑起来。下面用两张日志图把「看着成功」和「完整告警」都摆出来。图1unknown-state 告警日志抛出问题博文用途脚本输出看着全部正常但程序实际不跑 main。肉眼看镜像下载成功、SP/PC 寄存器回显数值全部和链接脚本预期一致没有报错。实际结果LED 不闪烁M4 根本没有跑到 main 函数。手动用 GDB 连接target extended-remote :3334调试一模一样的 elf 镜像同样的 SP、PC程序正常跑LED 闪烁。图2AP write error 完整日志问题分析博文用途完整复现告警现场。关键看点AP write error, reset will not halt软件复位无法把 M4 可靠停住根因见第二节②stm32mp15x.cpu0 / cpu1: ran after reset and before haltA7 双核上电抢跑[stm32mp15x.cm4] halted ... pc: 0x00000008 msp: 0x00000100M4 停在**初始 PC 槽向量表基址 0x08**处还没有真正进入你的Reset_Handler。本工程链接脚本向量表基址是0x10000000正常应为0x10000008日志显示0x00000008是旧脚本把向量表误写到 RETRAM/别名区0x0所致见第四节问题3。二、两条高频警告的人话解释① Warn: target was in unknown state when halt was requested人话OpenOCD 刚连上 M4完全不知道当前 CPU 是正在跑代码、还是停住、还是刚复位。直接强行发 halt 暂停命令这个暂停不一定真的生效。init完成调试器握手内核状态是混沌未知的。后面脚本修改 SP、PC、XPSR 寄存器前提条件必须是M4 已经被可靠 halt。如果 halt 没有真正生效写寄存器就是无效操作或行为不可预测——此时你看到的reg打印出来的数值只是 OpenOCD 本地缓存不等于真正写到 CPU 寄存器里面了。注意这条警告无法 100% 消除。MP157 是双核A7 主核上电抢跑M4 初始状态先天混沌即便改用reset halt极端情况下仍可能偶发。我们的整改目标是大幅抑制、把必现变偶发而非根治。② Info : AP write error, reset will not halt人话STM32MP157 是双核A7 主核上电抢跑OpenOCD 软件复位命令无法把 M4 内核可靠停住。不是硬件坏是芯片的硬件特性。MP157 上电永远 A7 双核先启动跑起来M4 是从核。单纯软件reset指令不能保证 M4 被停下于是 OpenOCD 写调试 AP 寄存器时报AP write error并提示reset will not halt。不要用-c halt要用-c reset halt用 SRST 硬件复位再 halt。注意 cfg 配置reset_config srst_only只复位 M4不会干扰 A7。三、为什么 GDB 手动交互调试不会踩这三个坑同一份 elfGDB 连 3334 端口单步 / 跑 main 都正常并不是 GDB 比脚本高级而是交互调试天然规避了前两节的三个问题halt 时机对了交互调试时操作者或.gdbinit会先敲monitor reset halt把 M4 从混沌未知态拉到明确的复位暂停态——天然绕开问题①的unknown state。shutdown 时机对了GDB 连接期间 OpenOCD 进程持续运行、不退出continue/resume之后人还在交互不存在「resume 完立刻 shutdown 把程序打断」——天然绕开问题②。向量表/状态处理对了GDB 加载 elf 通常用load并正确设置入口与 Thumb 状态不会把向量表写到错误地址——天然绕开问题③的表象。所以「脚本看着成功、GDB 正常」的差异本质不在你的代码而在脚本命令链缺了halt 时机、shutdown 时机、向量表地址这三处。四、旧脚本三个致命问题根因分析问题 1init 之后直接 haltM4 状态未知旧命令链init → targets → haltinit完成调试器连接此时 M4 状态未知直接halt就弹出unknown state警告。风险寄存器写入不可靠。脚本设置 sp/pc 看似打印正常实际 CPU 并没有真正更新寄存器resume之后跑飞 HardFault。问题 2resume 之后立刻 shutdown程序来不及跑旧命令-c resume -c shutdownresume通知 M4 开始执行紧接着马上shutdownOpenOCD 进程直接退出。OpenOCD 退出时会做调试适配器 detach 清理动作。M4 刚跳转到Reset_HandlerSystemInit还没执行还没进 main调试端口被强行断开程序直接被打断。问题 3向量表 mww 写入地址写错脚本旧代码-c mww 0x00000000 0x10060000 -c mww 0x00000004 %ENTRY%我们工程链接脚本stm32mp157_m4.lds向量表.isr_vector放在 SRAM 起始地址0x10000000。但是脚本却写到了0x00000000这是 BOOT 别名 / RETRAM 备份域。当前为什么还没彻底跑飞因为脚本紧接着使用reg sp / reg pc直接强行改写 CPU 内核寄存器绕过向量表读取。隐患未来一旦删掉 reg 强制写寄存器两行依靠硬件读取向量表启动M4 直接跑飞。补充小细节脚本reg sp 0x10060000是冗余的。启动汇编startup_stm32mp15xx.s的Reset_Handler第一行就会重新加载 SP 为_estack 0x10060000写了无害不影响。五、最小改动修复方案bat 脚本关键片段%OCD_BIN% ^ -s %OCD_SCRIPTS% ^ -f openocd/board_stm32mp157_m4.cfg ^ -c init ^ -c targets stm32mp15x.cm4 ^ -c reset halt ^ ::整改1硬件 SRST 复位再 halt大幅抑制 unknown-state 警告双核特性偶发难根除 -c load_image build/m4_liteos.elf ^ -c mww 0x10000000 0x10060000 ^ ::整改3修正向量表写入地址和链接脚本匹配 -c mww 0x10000004 %ENTRY% ^ -c reg sp 0x10060000 ^ -c reg pc %ENTRY% ^ -c reg xpsr 0x01000000 ^ ::补强显式置 Thumb 状态位防止进 ARM 态触发 UsageFault -c resume ^ -c sleep 200 ^ ::整改2留出 200ms等待 M4 跑起来再 shutdown -c shutdown三处整改 一处补强说明1.-c halt改为-c reset halt使用硬件 SRST 复位 M4 内核再 haltM4 进入明确的复位暂停状态大幅抑制unknown-state警告——但 MP157 双核 A7 抢跑特性下极端情况仍可能偶发无法 100% 保证消除与本系列已发布结论一致后续写寄存器在已 halt 前提下真正生效。cfg 中必须配置reset_config srst_only只复位 M4不会干扰 A7 内核。2. resume 之后新增-c sleep 200给 M4 留出 200ms 执行时间完成Reset_Handler → SystemInit → 库初始化 → main 任务循环。等程序真正跑起来之后再执行shutdown断开调试器。OpenOCD 退出时的 detach 不会打断已经正在运行的 M4 程序。3. mww 写内存地址从 0x00000000 改成 0x10000000和链接脚本向量表基地址完全对齐代码不依赖reg pc强行跳转也可以正常启动消除隐患。4.原脚本缺失本次补上reg xpsr 0x01000000Cortex-M 必须运行在 Thumb 态xPSR 的 T 位bit24必须置 1。脚本用reg pc %ENTRY%直接强跳入口时入口地址低位通常已是 1Thumb 函数地址为奇数硬件据 BX 地址低位进 Thumb但显式设xPSR 0x01000000T 位1作为兜底可避免任何状态下因状态位异常而进入 ARM 态触发 UsageFault。关于 reset halt 之后为何还要reg pc强跳reset halt把 M4 停在复位向量处、等待复位释放脚本为了让程序立刻从 SRAM 入口跑起来、不依赖复位释放时序直接改 sp/pc 强制跳转到 entry。同时mww把向量表 SP/PC 槽也写正确作为双保险——即使将来去掉reg强写、改回依赖硬件读向量表启动也能正常。六、修复之后验证标准修复之后重新运行flash-m4.bat控制台输出趋于干净AP write error通常消除unknown-state大幅减少但双核特性下极端情况仍可能偶发无法 100% 消除图3修复之后正常输出日志效果对比博文用途对比图。修复后AP write error警告消除unknown-state警告大幅减少双核特性下仍可能偶发无法 100% 消除与本系列已发布结论一致。修复验证标准AP write error, reset will not halt警告消除target was in unknown state when halt was requested警告大幅减少、通常不再出现——但 MP157 双核 A7 抢跑特性下极端情况仍可能偶发无法 100% 保证消除与本系列已发布结论一致。运行flash-m4.bat一键下载结束LED 正常闪烁代表 M4 成功跑到 main 任务循环。下载脚本执行完毕之后重新启动 OpenOCDGDB 连接 3334 端口执行monitor halt查看 PC 寄存器落在 main 或者业务任务循环地址而不是随机地址——说明 M4 在 OpenOCD 退出之后依旧持续运行。七、额外配套重要经验M4 SRAM 调试必看M4 内部 SRAM 靠 VDD_CORE 供电普通 NRST 复位按键不会清空 SRAM 内容SRAM 会残留旧程序。想要彻底清空 M4-SRAM关闭开发板总电源开关切断 5V 总输入等待 2~3 秒放电不要只按 RESET 复位键。不要迷信 OpenOCD 的reset软件命令MP157 双核特性软件复位不能可靠控制 M4。一键脚本调试 SRAM 场景resume之后一定要sleep一段时间再shutdown不要resume立刻退出进程否则会出现「控制台看着全部正常程序就是不跑」的诡异现象。八、总结坑点清单现象根因解决办法OpenOCD 打印unknown state when halt was requested偶发无法 100% 消除刚 init 直接 halt 致状态未知双核 A7 抢跑致状态偶发混沌改用reset halt大幅抑制仍可能偶发脚本下载成功LED 不闪GDB 手动调试正常resume 后马上 shutdownM4 还没跑 main 就被 detach 打断resume 后面加sleep延时mww 写到0x00000000向量表地址错误向量表实际在0x10000000脚本地址写错位修改 mww 目标地址为0x10000000AP write error, reset will not haltMP157 双核A7 优先启动软件复位无法停住 M4使用reset haltreset_config srst_only四行的根因与解法在正文第二、四、五节已展开此表仅作速查。系列文章索引LiteOS-M 移植①环境搭建、编译链接脚本LiteOS-M 移植⑤链接脚本与基础运行LiteOS-M PendSV 阻塞修复从绕开调度器到 SVCPendSV 标准启动LiteOS-M 再辨析启动第一个任务到底需不需要 SVC上一篇STM32MP157 M4 GDB 交互调试踩坑本篇STM32MP157 M4 一键脚本 SRAM 调试踩坑
返回列表