keil转IAR工程,程序运行Hardfault(RAM溢出)

一、编译后内存分配

1.    Keil工程编译后map文件

重点关注eeprom.o 发现编译后 RO Data 6148字节 存储flash中

2.    IAR工程编译后MAP文件

eeprom.o 发现编译后 RW Data 6154字节 存储RAM中

3.    在IAR工程中单独编译Eeprom.c这个文件

发现6148bytes 属于CONST memory,保存在flash中,与整个工程编译后的map文件内存分配有矛盾。

二、IAR工程Bootloader跳转App Hardfault 问题暂时解决办法

(A bus fault has occurred on an instruction prefetch)

修改bootloader堆栈空间分配

Bootloader跳转App成功。

暂不清楚原因,为何需要16k的栈空间才能跳转APP

注释掉App一部分程序,使得App的Ram使用量减少,则可以减少Bootloader的堆栈空间,即16k可以往下减少

App堆栈空间分配

主程序中未屏蔽任何程序段。

内存分配如下,

         33'372 bytes of readonly  code memory              

          1'362 bytes of readonly  data memory              

         22'558 bytes of readwrite data memory              

可以看到RAM已经溢出(最大20K)

但程序运行正常,没有跑飞(串口收发正常,指示灯常亮)(部分子函数不进入)

怀疑eeprom.c的内存分配是IAR编译器的BUG

6154bytes rw data

验证:实际测试发现去掉堆栈 22558-512=22046bytes 按理说会编译会报堆栈溢出错误。当把堆栈改为0x2000,即8K,发现报错

再次验证22046-6148=15898bytes (Eeprom.o实际输出是Ro data 6148字节)

剩余RAM: 20480bytes-15898bytes = 4582bytes = 0x11E6

实际操作当堆栈设置为0x11D8不报错,即ram没有溢出

 证明 Eeprom.o实际输出是Ro data 6148字节

在ram没有溢出的情况下,是不是把堆栈设置的越大越好?

够用就行?

三、bootloader跳转APP hardfault问题定位

(A bus fault has occurred on an instruction prefetch)

方法

1.1在硬件中断函数HardFault_Handler里的while(1)处打调试断点,程序执行到断点处时点击“STOP”停止仿真。

1.2 在Keil菜单栏点击“View”——“Registers Window”,在寄存器查看窗口查找R14(LR)的值。如果R14(LR) = 0xFFFFFFE9,继续查看MSP(主堆栈指针)的值,如果R14(LR) = 0xFFFFFFFD,继续查看PSP(进程栈指针)的值。我的程序R14(LR) = 0xFFFFFFF9,接下来以此为例。

1.3 在Keil菜单栏点击“View”——“Memory Windows”——“Memory1”,在“Address”地址栏中输入MSP的值:0x20001288,然后在对应的行里找到地址。地址一般以0x08开头的32位数。本例中,地址为0x08003CB9。

1.4 在Keil菜单栏点击“View”——“Disassembly Window”,在“Disassembly”窗口中右击,在下拉菜单中选择“Show Disassemblyat Address...”。在弹出框“Show Code atAdress”的地址框中输入地址0x08003CB9进行搜索,然后就会找到相对应的代码。这里的代码就是进入循环中断之前的情况。仔细查看附近区域的相关代码来排查错误具体原因。

IAR类似

发生报错,SP寄存器 0x2000'39a0

定位堆栈指针存放的地址

找到0x800'fba0代码段

IAR在启动main函数以前,执行了Reset_Handler,调用SystemInit()(ST库提供)进行时钟,Flash读取初始化,并转入__iar_program_start中执行__low_level_init与__iar_data_init2,并在__iar_data_init2中,先后调用__iar_zero_init2与__iar_copy_init2对全局变量、全局已初始化变量进行相应的初始化操作。最后,调用main()函数执行。

系统上电后,MSP(主堆栈指针)和PC两个寄存器被装入值,即 0x08000000 地址的值进入MSP,0x08000004 地址的值进入PC,0x08000004 地址保存的就是复位后执行的函数首地址即 Reset_Handler 的首地址,在进入 Reset_Handler 中执行SystemInit,然后再执行 __iar_program_start,最后在执行main()函数。在 __iar_program_start 中执行了几个IAR定义的启动代码函数,应该是对全局变量初始化啥的,将这些数据从ROM中copy到RAM中。

所以流程是:

上电  》  获取MSP和PC  》  进入Reset_Handler  》  执行SystemInit  》  进入__iar_program_start  》  执行__low_level_init  》  进入__iar_data_init2  》  执行__iar_zero_init2  》  执行__iar_copy_init2  》  执行main()函数

部分全局变量

全局变量执行初始化之前                                                    

        

  全局变量执行初始化之后

 

结论:App中进行全局变量初始化时发生堆栈溢出

<think>好的,我现在要处理用户关于ARM4芯片出现HardFault错误的问题。首先,我需要确认用户提到的“ARM4芯片”具体指什么。ARM架构有不同的版本,比如Cortex-M系列中的M3、M4等。可能用户指的是Cortex-M4,这在嵌入式系统中很常见,容易遇到HardFault问题。 接下来,我需要回忆HardFault的常见原因。根据之前提供的引用内容,内存溢出、堆栈溢出、访问越界是主要原因。此外,还有可能是指令错误、未对齐访问、中断处理不当等。需要将这些原因整理清楚,分点说明。 然后,解决方案部分需要分步骤。用户可能需要知道如何定位问题,比如使用调试工具、查看堆栈、反汇编代码等。引用中提到的CmBacktrace库和MDK的Disassembly窗口方法都是有用的,应该包含进去。同时,检查堆栈大小、内存分配、指针操作等也是关键点。 还要考虑用户可能的操作环境,比如使用Keil MDK或者IAR,不同的工具有不同的调试方法。需要给出通用的步骤,同时提到特定工具的操作,比如MDK的Disassembly窗口使用。 另外,用户可能需要预防措施,比如静态代码分析、增加栈大小、使用内存保护单元等。这些内容有助于用户避免未来出现类似问题。 需要确保回答结构清晰,分原因分析和解决方法两部分,每个部分用条目列出,方便用户理解。同时,引用相关的参考资料,如引用1、3、5提到的堆栈溢出排查方法,引用2的CmBacktrace库,引用4的中断优先级设置等,要正确标注引用来源。 最后,生成的相关问题要围绕HardFault的扩展,比如具体排查步骤、预防措施、常见错误代码分析,以及工具推荐。这些问题能帮助用户进一步深入学习。 检查是否有遗漏点,比如是否提到了硬件故障的可能性,虽然较少见,但也需要提及。另外,确保语言口语化,避免过于技术化,让用户容易理解。同时,按照用户要求,数学公式使用正确格式,但这个问题可能不涉及太多公式,所以重点放在代码块和结构上。</think>### ARM Cortex-M4芯片HardFault错误原因及解决方案 #### 一、HardFault错误原因分析 1. **内存操作错误** - 内存越界访问(如数组越界、指针操作错误)[^3] - 未对齐的内存访问(如对非4字节对齐地址进行强制类型换)[^4] - 访问未初始化的指针或空指针 2. **堆栈溢出** - 局部变量过大或递归调用过深导致栈空间不足[^1] - 多任务系统中任务堆栈分配不足 3. **指令执行异常** - 非法指令(如未实现的协处理器指令) - 除法除以零(部分Cortex-M4芯片触发) 4. **中断处理异常** - 中断服务函数未正确实现或未清除中断标志[^4] - 中断优先级配置冲突(如NMI与HardFault优先级设置) 5. **硬件异常** - 外部设备信号干扰 - 电源波动导致芯片工作异常 --- #### 二、问题定位与解决方法 ##### 步骤1:定位触发位置 1. **使用调试器捕获现场** 触发HardFault后立即暂停调试,查看以下寄存器: ```c stacked_pc = hardfault_args[6]; // 触发时的程序计数器值[^1] stacked_lr = hardfault_args[5]; // 链接寄存器值 ``` 2. **反汇编分析** 在Keil MDK中打开Disassembly窗口,输入`0x[stacked_pc地址]`定位问题指令[^5] ![](https://example.com/disassembly.png)(注:此为示例图) ##### 步骤2:排查高频问题 1. **堆栈溢出验证** - 在启动文件(如`startup_stm32f4xx.s`)中增加栈保护区: ```asm ; 添加栈顶标记值(如0xDEADBEEF) __initial_sp Top EQU 0x20010000 ``` - 运行时检查标记值是否被修改 2. **内存访问检查** - 使用`__attribute__((section(".ccmram")))`限定关键变量到特定内存区域 - 启用MPU(内存保护单元)设置访问权限 3. **代码静态分析** ```python # 使用PC-Lint检查潜在指针问题 lint-nt -w3 *.c ``` ##### 步骤3:高级诊断工具 1. **CmBacktrace库集成** 通过GitCode获取库文件[^2],添加错误回溯功能: ```c CmBacktrace_Init("STM32F4", "HW", "V1.0.0"); void HardFault_Handler(void) { cm_backtrace_fault("HardFault", _get_PSP()); } ``` 2. **HardFault诊断流程图** $$ \begin{cases} \text{检查PC/LR寄存器} \rightarrow \text{反汇编} & \text{指令级分析} \\ \text{内存dump对比} & \text{数据完整性验证} \\ \text{逐步注释代码} & \text{隔离故障模块} \end{cases} $$ --- #### 三、预防措施 1. **工程配置优化** - 在IDE中设置堆栈大小监控(Keil MDK配置示例): ```xml <StackSize>0x800</StackSize> <HeapSize>0x400</HeapSize> ``` 2. **硬件辅助设计** - 在PCB布局时增加电源去耦电容(推荐0.1μF+10μF组合) - 对关键信号线做阻抗匹配 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值