简析STM32的启动过程
/* PLL configuraTIon: PLLCLK = HSE * 9 = 72 MHz */
RCC-》CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC-》CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
startup_stm32f10x_md.s:(针对F103RBT6为中容量的产品)
这个文件里面首先定义了复位中断(复位入口矢量被硬件固定在地址0x0000_0004)的处理函数:Reset_Handler,它的作用就是将保存于flash中的初始化数据复制到sram中,调用上面说到的SystemInit来初始化时钟,接着跳转到main执行。
接着定义了Default_Handler, 这个是作为其他所有中断的默认处理函数,作用就是死循环,所以你假如开启了某个中断,请按照这里面的中断函数名给它写中断处理函数,例如串口中断处理函数名是 USART1_IRQHandler,你开了串口中断,如果不重写USART1_IRQHandler,就默认执行Default_Handler,死循环了。而如果你有重写,那么中断向量表中的处理函数的地址就会更新为你自己写的那个函数的地址了。为什么会这样呢?因为此文件的末尾用了类似这样的语句:
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
它给中断处理函数提供了弱(weak)别名(Default_Handler),如果不重写,中断了默认执行Default_Handler,如果重写了,因为是弱别名,所以会被你写的同名函数覆盖。
最后定义了一个中断向量表的段(.secTIon .isr_vector,"a",%progbits),这个表将会放置在0x0000 0000那里,第二个字(0x0000 0004)是复位向量,复位之后从这地址所指的函数执行。
那么,如何保证.isr_vector这个段将放在flash的最开始(0x08000000)呢?这就需要链接脚本了,即我们用的那个stm32_flash.ld文件了,查看一下就知道了,里面先定义了堆栈的地址:
_estack
/* Highest address of the user mode stack */
_estack = 0x20005000; /* end of 20K RAM */
接着定义了堆和栈的大小:
/* Generate a link error if heap and stack don‘t fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x100; /* required amount of stack */
接着声明了各个内存的区域(定义了几个代表某个线性空间的名字,如下面的FLASH):
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K }
接着下面再介绍上面这三个名字里面都放了什么东西,首先是FLASH的:
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
。 = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */
。 = ALIGN(4); } 》FLASH
/* The program code and other data goes into FLASH */
.text :
{
。 = ALIGN(4); *(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
KEEP (*(.init))
KEEP (*(.fini))
。 = ALIGN(4); _etext = 。; /* define a global symbols at end of code */
} 》FLASH
可以看到startup_stm32f10x_md.s中定义的这个段.isr_vector确实放在了最开头的位置。
但是我们前面说复位向量在0x0000 0004,现在其地址是在flash中,所以地址是0x0800 0004,这个怎么回事呢?原来,stm32可以通过boot0、boot1引脚的配置将flash映射到0x0000 0000处。具体可参考stm32的用户手册2.4节。
从主闪存存储器启动(BOOT0 = 0,BOOT1 = X):主闪存存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址(0x0800 0000)访问它,即闪存存储器的内容可以在两个地址区域访问,0x0000 0000或0x0800 0000。
至此,整个STM32的启动过程以及程序结构都可以比较清晰了。
STM32 相关文章:
- 盘点STM32-NUCLEO开发与仿真平台(03-28)
- 一种基于ZigBee和STM32的室内智能照明系统的设计(05-13)
- 大联大友尚集团推出ST STM32马达控制Nucleo开发工具包,可直接开始运转无刷直流马达(05-27)
- 这些VR设备“内脏”构造大解剖!绝对有你没见过的(02-14)
- 在变频空调风机中永磁同步电机矢量控制方案的运用(04-04)
- 基于STM32和SIM900A的无线通信模块设计(10-07)