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中进行全局变量初始化时发生堆栈溢出