PY32F系列MCU在OTA时App区概率性跑不起来的根因分析(5)
接前一篇文章PY32F系列MCU在OTA时App区概率性跑不起来的根因分析4三、问题解决上一回通过AI工具Cursor定位到了根因这里详细说明一下具体情况。实际上问题是出在了APP_DeInitInterface这个函数上。笔者工程中的APP_DeInitInterface函数代码如下static void APP_DeInitInterface(void) { #if 0 CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOBEN); CLEAR_BIT(RCC-APBENR1, RCC_APBENR1_USART3EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); SET_BIT(RCC-APBRSTR1, RCC_APBRSTR1_USART3RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); CLEAR_BIT(RCC-APBRSTR1, RCC_APBRSTR1_USART3RST); #else CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOAEN); CLEAR_BIT(RCC-APBENR2, RCC_APBENR2_USART1EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOARST); SET_BIT(RCC-APBRSTR2, RCC_APBRSTR2_USART1RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOARST); CLEAR_BIT(RCC-APBRSTR2, RCC_APBRSTR2_USART1RST); #endif #if 0 CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOBEN); CLEAR_BIT(RCC-APBENR1, RCC_APBENR1_I2C1EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); SET_BIT(RCC-APBRSTR1, RCC_APBRSTR1_I2C1RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); CLEAR_BIT(RCC-APBRSTR1, RCC_APBRSTR1_I2C1RST); #else CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOBEN); CLEAR_BIT(RCC-APBENR1, RCC_APBENR1_I2C2EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); SET_BIT(RCC-APBRSTR1, RCC_APBRSTR1_I2C2RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); CLEAR_BIT(RCC-APBRSTR1, RCC_APBRSTR1_I2C2RST); #endif CLEAR_BIT(RCC-CFGR, RCC_CFGR_SW); while (0 ! READ_BIT(RCC-CFGR, RCC_CFGR_SWS)); CLEAR_BIT(RCC-CR, RCC_CR_PLLON); }而普冉官方例程中的APP_DeInitInterface函数代码是这样的static void APP_DeInitInterface(void) { __enable_irq(); switch (guc_InterfaceDetection) { case INTERFACE_USART1: CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOAEN); CLEAR_BIT(RCC-APBENR2, RCC_APBENR2_USART1EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOARST); SET_BIT(RCC-APBRSTR2, RCC_APBRSTR2_USART1RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOARST); CLEAR_BIT(RCC-APBRSTR2, RCC_APBRSTR2_USART1RST); break; case INTERFACE_USART2: CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOAEN); CLEAR_BIT(RCC-APBENR1, RCC_APBENR1_USART2EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOARST); SET_BIT(RCC-APBRSTR1, RCC_APBRSTR1_USART2RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOARST); CLEAR_BIT(RCC-APBRSTR1, RCC_APBRSTR1_USART2RST); break; case INTERFACE_USART3: CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOBEN); CLEAR_BIT(RCC-APBENR1, RCC_APBENR1_USART3EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); SET_BIT(RCC-APBRSTR1, RCC_APBRSTR1_USART3RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); CLEAR_BIT(RCC-APBRSTR1, RCC_APBRSTR1_USART3RST); break; case INTERFACE_USART4: CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOCEN); CLEAR_BIT(RCC-APBENR1, RCC_APBENR1_USART4EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOCRST); SET_BIT(RCC-APBRSTR1, RCC_APBRSTR1_USART4RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOCRST); CLEAR_BIT(RCC-APBRSTR1, RCC_APBRSTR1_USART4RST); break; case INTERFACE_I2C: CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOBEN); CLEAR_BIT(RCC-APBENR1, RCC_APBENR1_I2C1EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); SET_BIT(RCC-APBRSTR1, RCC_APBRSTR1_I2C1RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); CLEAR_BIT(RCC-APBRSTR1, RCC_APBRSTR1_I2C1RST); break; } }看起来似乎差异不大、无关紧要实际上这里才是导致问题的紧关节要之处。先来看官方例程。官方例程中是根据不同的接口使用不同的反初始化函数。OTA的文件可能是通过UART1、UART2、UART3、UART4或者I2C1传输的这就意味着使用哪个接口之前就要初始化哪个接口与之对应地这里就要去初始化该接口。以UART1为例看一下具体代码的作用case INTERFACE_USART1: CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOAEN); CLEAR_BIT(RCC-APBENR2, RCC_APBENR2_USART1EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOARST); SET_BIT(RCC-APBRSTR2, RCC_APBRSTR2_USART1RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOARST); CLEAR_BIT(RCC-APBRSTR2, RCC_APBRSTR2_USART1RST); break;CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOAEN);这一行的意思是关闭GPIOA外设时钟。CLEAR_BIT(RCC-APBENR2, RCC_APBENR2_USART1EN);这一行的意思是关闭USART1外设时钟。SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOARST);这一行的意思是置位GPIOA复位位进入复位状态。SET_BIT(RCC-APBRSTR2, RCC_APBRSTR2_USART1RST);这一行的意思是置位USART1复位位进入复位状态。CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOARST);这一行的意思是清除GPIOA复位位退出复位。CLEAR_BIT(RCC-APBRSTR2, RCC_APBRSTR2_USART1RST);这一行的意思是清除USART1复位位退出复位。综合来看以上一段代码的作用就是关闭UART1的时钟以及复用为UART1功能的GPIO引脚的时钟然后复位UART1和对应的GPIOA。对于其它接口UART2、3、4I2C1也是类似的。再来看笔者工程对应的代码#if 0 CLEAR_BIT(RCC-IOPENR, RCC_IOPENR_GPIOBEN); CLEAR_BIT(RCC-APBENR1, RCC_APBENR1_USART3EN); SET_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); SET_BIT(RCC-APBRSTR1, RCC_APBRSTR1_USART3RST); CLEAR_BIT(RCC-IOPRSTR, RCC_IOPRSTR_GPIOBRST); CLEAR_BIT(RCC-APBRSTR1, RCC_APBRSTR1_USART3RST); #else …… #endif重点看#if 0注释掉的部分。笔者项目之前的硬件使用的是UART3最新的版本使用的则是UART1。这里的代码仍然是去初始化UART3。这就会引起问题了。上边AI工具讲得清楚调用发生在HAL_Init()SysTick 已开和UART1_Init()USART1的RXNE中断已打开之后。跳转函数只复位了USART3和GPIOB实际用的是USART1没有关系。__disable_irq()只挡住全局中断NVIC里USART1的使能和挂起标志都还在。从Boot区跳转到App区时App进入main()的第一件事就是把中断打开此时Uart1Handle还是BSS清零后的空指针。总线上一有数据或者RXNE/ORE还挂着就会立刻进App的USART1_IRQHandler对Uart1Handle.Instance做访问由于此时Uart1Handle.Instance还是NULL因此就会进入HardFault_Handler中的死循环。OTA时总线是忙的所以一重启就跑飞安静上电有时能躲过等第一帧串口数据到来再死。笔者将错误#if 0中的代码注释掉改为下边#else中的代码问题解决当然还有I2C的修改。更多内容请看下回。

相关新闻

VSCode配置Python开发环境:从安装到调试的完整教程

VSCode配置Python开发环境:从安装到调试的完整教程

很多朋友第一次打开VSCode,装完Python插件,兴冲冲写了两行。print("hello world")结果满屏红波浪线,报错一个接一个,代码跑不起来。然后就开始怀疑人生:是不是我下错了软件?是不是Python装错了版…

2026/10/10 2:51:06 阅读更多 →
2026跨境电商新规落地后,这3类卖家正在悄悄被市场淘汰

2026跨境电商新规落地后,这3类卖家正在悄悄被市场淘汰

平台规则从来不是突然转向,而是先释放信号,再逐步收紧。进入2026年,跨境电商行业最明显的变化不是流量变贵,而是合规成本开始成为经营门槛。过去靠信息差、铺货速度和低价冲量就能活下来的模式,正在被一条条新规拆解。…

2026/10/10 2:50:05 阅读更多 →
2026年跨境电商卖家别再盲目铺货了,这3个长尾词赛道正在悄悄爆单

2026年跨境电商卖家别再盲目铺货了,这3个长尾词赛道正在悄悄爆单

铺货模式曾支撑起不少卖家的早期增长,但当平台流量分配更依赖精准匹配、海外消费者对交付与内容的要求同步提高后,单纯靠SKU数量换曝光的做法,边际收益已经明显收窄。与其在红海里反复测款,不如把注意力转向搜索意图更明确、竞争密…

2026/10/10 2:50:05 阅读更多 →

最新新闻

从“无标题”到正式命名:一句话锁定项目内核

从“无标题”到正式命名:一句话锁定项目内核

项目清单里躺着个“无标题”,听起来像个段子,但我这几年真见过不少项目,起点就是这个状态。新建文档默认叫“未命名”,新建仓库默认叫“my-project”,而有些项目,连“未命名”都没人愿意给它起,…

2026/10/10 3:40:21 阅读更多 →
SpringBoot+微信小程序:共享雨伞租赁系统全栈开发实践

SpringBoot+微信小程序:共享雨伞租赁系统全栈开发实践

简介:一份围绕Spring Boot与微信小程序开发的共享雨伞租赁系统毕业设计文档,面向需要完成类似课题的计算机专业学生、Java开发者及毕业设计人员。文档基于Windows 10环境,采用Java语言、Spring Boot框架与MySQL数据库,完整梳理了微…

2026/10/10 3:40:21 阅读更多 →
micro:bit教育硬件核心价值:低成本、零门槛、强扩展的编程入门方案

micro:bit教育硬件核心价值:低成本、零门槛、强扩展的编程入门方案

1. 这不是玩具,是能真正“跑起来”的微型计算机 micro:bit 这个名字听起来有点拗口,但如果你在中小学科技教室、创客空间或者青少年编程夏令营里待过五分钟,大概率已经见过它——一块比信用卡略小、带着25颗LED灯点阵、两颗物理按钮、加速度…

2026/10/10 3:40:21 阅读更多 →
从“大模型读图”到“大模型用图”:百度地图 MCP 工具集接入与实战指南

从“大模型读图”到“大模型用图”:百度地图 MCP 工具集接入与实战指南

1. 从“大模型读图”到“大模型用图”百度地图 MCP 这个词最近在开发者圈子里热度很高,不只是因为“国内首家兼容 MCP 协议的地图服务”这个名头,更因为它把地图服务从传统的 API 调用方式,拉进了一个 AI Agent 可以自主调用的新阶段。如果你…

2026/10/10 3:40:20 阅读更多 →
MySQL函数实战指南:从索引失效到慢查询排查的避坑手册

MySQL函数实战指南:从索引失效到慢查询排查的避坑手册

我刚工作那阵,对 MySQL 函数的理解一直停留在“用到哪个查哪个”的阶段,直到后来接手了几个慢查询排查,才开始意识到函数在 SQL 里的位置和用法,直接决定了查询能不能走索引、逻辑是不是清晰、统计口径对不对。MySQL 函数体系其实…

2026/10/10 3:40:20 阅读更多 →
SpringBoot2+Vue3养老院管理系统源码解析与实战

SpringBoot2+Vue3养老院管理系统源码解析与实战

如果你正在找一套能直接拿来改、能跑通、能写进简历或毕业设计的全栈管理系统源码,SpringBoot2 Vue3 MyBatis-Plus MySQL8.0 这套养老院管理系统,恰好就是典型的“前后端分离 权限管理 CRUD 业务闭环”的项目形态。这套组合这两年几乎是 Java Web 领…

2026/10/10 3:39:20 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →