ARM芯片STM32出现HardFault Handler硬件中断一般有两种情况:
- 访问越界导致的Acess Violation或者内存溢出
- 堆栈溢出
这次遇到的问题是栈空间不够。
ARM程序的组成[1]
在Keil4的Build Out窗口中有下列的调试信息:
那么其中的Program Size: Code=12384 RO-data=420 RW-data=52 ZI-data=37044 分别代表什么意义呢?
此处所说的“ARM程序”是指在ARM系统中正在执行的程序(在RAM中的程序)。
一个ARM程序包含3部分:RO,RW和ZI。RO是程序中的指令和常量;RW是程序中的已初始化变量;ZI是程序中的未初始化的变量.由以上3点说明可以理解为:RO就是readonly,RW就是read/write,ZI就是zero。
堆和栈的区别
- 栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似 于数据结构中的栈。
- 堆区(heap):一般由程序员分配和释放(malloc),若程序员不释放,程序结束时可能由操作系统回收。分配 方式类似于数据结构中的链表。
- 全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态 变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系 统自动释放。
- 文字常量区:常量字符串就是存放在这里的。
- 程序代码区:存放函数体的二进制代码。
当我把几个全局的数组长度double BUFER[sample_num]都调到10000+时,Keil会出现报错。
BSS指用来存放程序中未初始化的全局变量的一块内存区域,显然这个BUFFER数组存在全局区,而ROM内存不够导致出错。
举个“栗子”说明一下这几个区的不同:
遇到问题
在main中有这样几个函数:
用来滤波和差分,然而继续在后面加上一行cnt=find_max(BUFER,peak,sample_num)时会跳入到HardFault Handler中。跟踪发现,它影响整个程序的方式还特别奇怪,不加入它的时候ADC能采样sample_num个数据。加入它时,ADC在没采够sample_num个数据时就会跳入到HardFault Handler中。这样让我一直以为是ADC采样导致的硬件错误中断。
解决问题
仔细看一下cnt=find_max(BUFER,peak,sample_num)的代码
发现它定义了两个很大的局部变量数组,而局部变量是存在栈中的,1000+1000大于开始定义的1024个字节。所以出现了硬件中断错误。
因为在程序中没有动态分配内存,可以在startup文件中把Heap_size定义为0.
Keil输出的MAP文件
__initial_sp 0x20016c68 Data 0 startup_stm32f2xx.o(STACK)
STACK 0x20014868 Section 9216 startup_stm32f2xx.o(STACK)
说明stack大小为0x2400
Reference
[1].http://blog.csdn.net/jamestaosh/article/details/4348385
[2].http://www.mcuc.com.cn/thread-660-1-1.html
[3].http://www.openedv.com/posts/list/24152.htm