硬件复位后,第一步是执行复位处理程序,这个程序的入口在启动代码里(默认),摘录一段cortex-m3的复位处理入口代码:
- Reset_Handler PROC ;PROC等同于FUNCTION,表示一个函数的开始,与ENDP相对?
- EXPORT Reset_Handler [WEAK]
- IMPORT SystemInit
- IMPORT __main
- LDR R0, =SystemInit
- BLX R0
- LDR R0, =__main
- BX R0
- ENDP
-
Reset_Handler PROC ;PROC等同于FUNCTION,表示一个函数的开始,与ENDP相对?
-
EXPORT Reset_Handler [WEAK]
-
IMPORT SystemInit
-
IMPORT __main
-
LDR R0, =SystemInit
-
BLX R0
-
LDR R0, =__main
-
BX R0
-
ENDP
这里SystemInit函数是我自己用C代码写的硬件底层时钟初始化代码,这个可不算是keil mdk给代劳的.初始化堆栈指针、执行完用户定义的底层初始化代码后,发现接下来的代码是调用了__main函数,这里之所以有__main函数,是因为在C代码中定义了main函数,函数标签 main() 具有特殊含义。main() 函数的存在强制链接器链接到 __main 和 __rt_entry 中的初始化代码。
其中,__main函数执行代码和数据复制、解压缩以及 ZI 数据的零初始化。解释一下,C代码中,已经赋值的全局变量被放在RW属性的输入节中,这些变量的初值被keil mdk压缩后放到ROM或Flash中(RO属性输入节)。什么是赋值的全局变量呢?如果你在代码中这样定义一个全局变量:int nTimerCount=20;变量nTimerCount就是已经赋值的变量,如果是这样定义:int nTimerCount;变量nTimerCount就是一个非赋值的变量,keil默认将它放到属性为ZI的输入节。为什么要压缩呢?这是因为如果赋值变量较多,会占用较多的Flash存储空间,keil 默认用自己的压缩算法。这个“解压缩”就是将存放在RO输入区(一般为ROM或Flash)的变量初值,按照一定算法解压缩后,拷贝到相应RAM区。ZI数据清零是指将ZI区的变量所在的RAM区清零。使用 UNINIT 属性对执行区进行标记可避免 __main 对该区域中的 ZI 数据进行零初始化。这句话很重要,比如我有一些变量,保存一些重要信息,不希望复位后就被清零,这时就可以用分散加载文件定义一块UNINIT属性的区,将不希望零初始化的变量定义到这个区即可。
|