本帖最后由 zhanzr21 于 2017-1-18 21:47 编辑
一直想研究一下Cortex M系列的启动文件.这次以STM32F413为例,分析一下Cortex M4的启动过程,就是从上电到main函数之间的内容.其他CortexM系列的片也应该大同小异.开发工具使用Keil MDK,其他工具的启动语法上应该有差别,内容基本一致.比如gcc使用的是AT&T格式的汇编语言风格,而Keil的ARM CC使用的是Intel格式的汇编语言.这都是形式上的差别,闲话少叙. 首先随便建立一个工程.能跑起来就可以,建议使用CubeMX建立.这个过程直接跳过去.看打开的工程.
这里我们只对这两个文件感兴趣,主要是那个"startup_stm32f413xx.s",那个C文件只是有个函数被".s"中调用. 以下是".s"文件内容,为了叙述方便,我去掉了比较长段的注释. Stack_Size EQU 0x400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
THUMB
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD WWDG_IRQHandler ; Window WatchDog
.......
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
; Dummy Exception Handlers (infinite loops which can be modified)
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
....
Default_Handler PROC
EXPORT WWDG_IRQHandler [WEAK]
......
B .
ENDP
ALIGN
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ALIGN
ENDIF
END
代码很长,但是有规可循. 现在从上到下来分析一下. Stack_Size EQU 0x00000400
Heap_Size EQU 0x00000200
这两个分别是定义Stack与Heap大小,比较小的工程保留这样设置够用.如果不够用,则要研究.map文件重新定义了.尤其是heap,有些人认为没有动态分配内存,就把heap_size设定为0了,但是用户代码不用不代表调用的函数不用,尤其是<string.h>中的函数,有些是要用heap的.接下来就是向量区,按照ARM的规范,这些向量都是从0开始的.但是STM32F4将0与0x8000000两个地址映射在一起了. AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD WWDG_IRQHandler ; Window WatchDog
....
__Vectors_End
这是ARM公司的说明:
ST公司在编程参考手册中也有说明: The Cortex™-M4 with FPU CPU always fetches the reset vector on the ICode bus, which implies to have the boot space available only in the code area (typically, Flash memory). STM32F4xx microcontrollers implement a special mechanism to be able to boot from other memories (like the internal SRAM).
大致是说ST的F4XX用了一种特殊方法让系统可以从不同的位置启动,比如SRAM.对STM32F1系列的比较熟的应该有映像. 其实这个特殊方法在ST的Cortex整个系列都是比较类似.就是Boot1,Boot0两个引脚来配置启动选项.
这样做的实质上就是启动的时候将什么区域映射到0这个位置.为了简洁起见,这里先以常规的配置为例,也就是BOOT0拉低从Flash启动. 这样0x8000000就被映射到0这个地址.上述的向量都在0x8000000开始的地址存储. 接下来就是复位向量的处理函数. Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
这个函数翻译成C语言就是两句: SystemInit是ARM公司的CMSIS规范要求的,所有符合该规范的代码都得用SystemInit来完成初始化.需要注意的是调用SystemInit的时候,stack与heap都没有初始化,所以SystemInit函数内尽量不要过多调用别的函数或者动态分配内存,以免造成麻烦.SystemInit在"system_stm32f4xx.c"文件里面.来看看这个函数: void SystemInit(void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
#endif
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset CFGR register */
RCC->CFGR = 0x00000000;
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset PLLCFGR register */
RCC->PLLCFGR = 0x24003010;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Disable all interrupts */
RCC->CIR = 0x00000000;
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
/* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}
帖子长度超限制了,余下的在下面继续写.
|