本帖最后由 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
- }
帖子长度超限制了,余下的在下面继续写.
|