这个问题在面试百度嵌入式技术二面的被问到,当时没有想到会问STM32的问题,答的不好。刚刚看到了类似的文章,记录一下。
参考原文链接:https://blog.csdn.net/wqx521/article/details/50925553
首先是启动文件,列举f10x比较常见几种文件,按照FLASH容量的不同使用不同的文件。
startup_stm32f10x_ld.s 小容量:FLASH<=32K
startup_stm32f10x_md.s 中容量:64K<=FLASH<=128K
startup_stm32f10x_hd.s 大容量:256K<=FLASH<=512K
startup_stm32f10x_xl.s 超大容量:FLASH>=512K
写句题外话,小于256K FLASH的STM32,页的大小为1K,大于256K的页大小为2K。在写FLASH,擦FLASH的需要注意。
;******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
;* File Name : startup_stm32f10x_cl.s
;* Author : MCD Application Team
;* Version : V3.3.0
;* Date : 04/16/2010
;* Description : STM32F10x Connectivity line devices vector table for RVMDK
;* toolchain.
;* This module performs:
;* - Set the initial SP
;* - Set the initial PC == Reset_Handler
;* - Set the vector table entries with the exceptions ISR address
;* - Configure the clock system
;* - Branches to __main in the C library (which eventually
;* calls main()).
;* After Reset the CortexM3 processor is in Thread mode,
;* priority is Privileged, and the Stack is set to Main.
;* <<< Use Configuration Wizard in Context Menu >>>
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
设置栈大小
AREA:汇编一个新的代码段或者数据段。STACK段名,任意命名;NOINIT表示不初始化;READWRITE可读可写;ALIGN=3(2^3= 8字节对齐)。
__initial_sp紧挨了SPACE放置,表示栈的结束地址,栈是从高往低生长,结束地址就是栈顶地址。
Heap_Size EQU 0x00000200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
设置堆大小
__heap_base堆的起始地址,__heap_limit堆的结束地址。堆由低向生长。动态分配内存用到堆。
PRESERVE8
THUMB
PRESERVE8 //指定当前文件的堆栈按照 8 字节对齐。
THUMB //表示后面指令兼容 THUMB 指令。THUBM 是ARM 以前的指令集,16bit,现在 Cortex-M 系列的都使用 THUMB-2 指令集,THUMB-2 是32 位的,兼容 16 位和 32 位的指令,是 THUMB 的超级。
紧接着设置的是中断向量,建立中断服务入口地址,即把中断向量与中断服务函数链接起来。
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
这个文件里面首先定义了复位中断(复位入口矢量被硬件固定在地址0x0000_0004,地址是在flash中,所以地址是0x0800 0004)的处理函数:Reset_Handler,它的作用就是将保存于flash中的初始化数据复制到sram中,调用上面说到的SystemInit来初始化时钟,接着跳转到main执行。
在进入main函数之前,我们要进行系统初始化:SystemInit
SystemInit():在"startup_stm32f10x_xx.s"文件中被调用,功能是设置系统时钟(包括时钟源,PLL系数,AHB/APBx的预分频系数还有 flash的设定),这个函数会在系统复位之后首先被执行。文件中默认的一些设置:允许HSE(外部时钟),FLASH(允许预取缓冲区,设置2个等待周 期),PLL系数为9,开启PLL并选择PLL输出作为时钟源(SYSCLK),后续设置SYSCLK = HCLK = APB2 = 72MHz,APB1 = HCLK/2 = 36MHz,HCLK即AHB的时钟。
中断处理函数提供了弱(weak)别名(Default_Handler),如果不重写,中断了默认执行Default_Handler,如果重写了,因为是弱别名,所以会被你写的同名函数覆盖。WEAK声明其他的同名标号优先于该标号被引用,就是说如果外面声明了的话,;会调用外面的
最后定义了一个中断向量表的段(.section .isr_vector,"a",%progbits),这个表将会放置在0x0000 0000那里,第二个字(0x0000 0004)是复位向量,复位之后从这地址所指的函数执行。