问题描述
- 单片机烧录代码(刚上电)无法立即运行,必须要复位一次或多次才能运行;
- 跟踪调试会进入HardFault_Handler中断。
问题分析
- 烧录配置如下图,首先排除配置问题
- 那么该问题就比较让人头大了,理论上,如果代码有问题,那工程应该运行不起来才对;但是话又说回来,如果代码没问题,那为什么会出现这种运行卡死的情况?
- 常理上讲,一般代码进入HardFault_Handler,多半是跟硬件有关,这个时候就需要检查硬件相关的一些外设的配置了,如gpio、uart、spi、DMA等等,跟io相关的外设要尤其注意!!!
- 排查相关外设,最终发现某个gpio驱动存在问题(该io本来是要控制某一个开关的,拉低导通,但是由于硬件修改,已经把该io接地,这就导致本来已经接地的io又被我初始化了一遍,且默认拉高)
方案验证
由于硬件已经接地,所以开关处于常导通状态,此时不用再对该io做任何配置,屏蔽掉该io的相关初始化接口,最终问题解决。
反思及总结
电平之间的相互冲突可能会导致硬件冲突,进而出现代码不能稳定运行的情况,所以在使能外设时一定要仔细检查相关的时钟配置是否正确(如spi、iic、adc等)、电平是否被钳位到稳定状态(拉高或者拉低,最好不要出现悬空!!!)、硬件资源是否存在冲突。
备注
以下列举一些进入硬件错误中断的情况:
1. 非法内存访问
- 访问未分配的内存区域,例如:
- 空指针访问 (
NULL pointer
)。 - 超出有效范围的数组下标。
- 访问不存在的外设寄存器地址。
- 空指针访问 (
2. 执行非法指令
- 程序计数器(PC寄存器)跳转到非代码区域,导致执行无效指令。
- 通常是函数指针错误、栈溢出或闪存内容被错误修改。
3. 堆栈溢出
- 当任务栈或主栈使用超出分配的内存时,可能覆盖到其他内存区域,引发异常。
- 常见原因:
- 函数递归调用太深。
- 大量局部变量分配,超过栈的容量。
4. 总线错误(Bus Fault)
- 对外设或存储器执行无效的访问操作,可能因以下原因导致:
- 非对齐的内存访问(具体取决于目标处理器,Cortex-M0 不支持非对齐访问,M3/M4 通常支持)。
- 缓存一致性问题或外设配置错误。
5. 除以零
- 在代码中执行除以零操作时会触发异常,除非已经禁用异常。
6. 非法优先级设置
- NVIC 优先级分组与中断优先级配置错误可能导致异常。
7. MPU(内存保护单元)访问限制
- 如果启用了 MPU(Memory Protection Unit),对受保护区域的访问将触发硬件异常。
- 常见情况:
- 用户代码访问了受保护的内存区域。
- 不同的任务越界访问了非分配的内存。
8. 其他硬件异常
- 在调试或运行过程中出现意外电气或硬件问题,例如:
- 外设初始化错误。
- 系统时钟配置错误。
- 电源管理模块异常。