STM32之启动文件详细解析(V3.5.0)讲解
- 格式:doc
- 大小:59.51 KB
- 文档页数:11
STM32启动文件详解(2012-07-28 11:22:34)转载▼分类:STM32标签:stm32启动在<<STM32不完全手册里面>>,用的是STM32F103RBT6,所有的例程都采用了一个叫STM32F10x.s的启动文件,里面定义了STM32的堆栈大小以及各种中断的名字及入口函数名称,还有启动相关的汇编代码。
STM32F10x.s是MDK提供的启动代码,从其里面的内容看来,它只定义了3个串口,4个定时器。
实际上STM32的系列产品有5个串口的型号,也只有有2个串口的型号,定时器也是,做多的有8个定时器。
比如,如果你用的STM32F103ZET6,而启动文件用的是STM32F10x.s的话,你可以正常使用串口1~3的中断,而串口4和5的中断,则无**常使用。
又比如,你TIM1~4的中断可以正常使用,而5~8的,则无法使用。
而在固件库里出现3个文件startup_stm32f10x_ld.sstartup_stm32f10x_md.sstartup_stm32f10x_hd.s其中,ld.s适用于小容量产品;md.s适用于中等容量产品;hd适用于大容量产品;这里的容量是指FLASH的大小.判断方法如下:小容量:FLASH≤32K中容量:64K≤FLASH≤128K大容量:256K≤FLASH;******************** (C) COPYRIGHT 2011 STMicroelectronics ******************** ;* File Name : startup_stm32f10x_hd.s;* Author : MCD Application Team;* Version : V3.5.0;* Date : 11-March-2011;* Description : STM32F10x High Density Devices vector table for MDK-ARM;* 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 and also configure the external;* SRAM mounted on STM3210E-EVAL board to be used as data;* memory (optional, to be enabled by user);* - 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.;* 说明: 此文件为STM32F10x高密度设备的MDK工具链的启动文件;* 该模块执行以下操作:;* -设置初始堆栈指针(SP);* -设置初始程序计数器(PC)为复位向量,并在执行main函数前初始化系统时钟;* -设置向量表入口为异常事件的入口地址;* -复位之后处理器为线程模式,优先级为特权级,堆栈设置为MSP主堆栈;* <<< Use Configuration Wizard in Context Menu >>>; 首先对栈和堆的大小进行定义,并在代码区的起始处建立中断向量表,其第一个表项是栈; 顶地址,第二个表项是复位中断服务入口地址。
STM32的启动分析一、STM32的复位序列当STM32产生复位后,做的第一件事就是读取下列两个32位整数的值:1、从地址0x0000,0000处取出MSP(主堆栈指针)的初始值放入MSP寄存器中;2、从地址0x0000,0004处取出复位向量放入PC寄存器中,然后从PC中存取的地址出取指并开始执行。
图1:复位序列请注意,这与传统的ARM架构以及其他的单片机完全不同,他们复位后一般是从0x0000,0000地址处取出第一条指令并执行,而一般0x0000,0000都是一条跳转指令。
而在STM32中,在0地址处提供的是MSP的初始值,然后紧跟着就是向量表(上电复位时向量表是被默认放在0x04地址处,但是通过修改向量表偏移量寄存器(VTOR)可以将其定义在其他位置)。
另外,向量表中的数值是32位的地址,而不是跳转指令,系统会自动将该数值存入PC寄存器中后从该32为地址指向的地址出开始执行,这有点像指针的指针。
图2:初始化MSP及PC的初始化的一个范例因为SMT32使用的是向下生长的满栈,所以MSP初始值必须是堆栈内存的末地址加1。
举例来说,如果你的堆栈区域在0x20007C00-0x20007FFF之间,那么MSP的初始值就必须是0x20008000。
向量表跟随在MSP的初始化之后——也就是第2个标目。
要注意因为STM32是在Thumb 态下执行,所以向量表中每个数值必须把LSB(最低权重位)置1.正是因为这个原因,图2中就是用0x101来表示0x100.当0x100处的指令得到执行后,就正是开始了程序的执行。
在这之前MSP是必须的,因为可能第1条指令还没来得及执行,就发生了NMI(不可屏蔽中断)或者其他的Fault,MSP初始化好后就已经为他们的服务例程准备好了堆栈。
二、STM32的3种启动模式在STM32中,可以通过BOOT[1:0]引脚选择三种不同的启动模式,如表1:表1:STM32的三种启动模式根据选定的启动模式,主闪存存储器、系统存储器或SRAM可以按照以下方式访问:1、从主闪存存储器启动:主闪存存储器被映射到启动空间(0x0000,0000),但仍然能够在原有的地址(0x8000,0000)访问它,即闪存存储器的内容可以在两个地址区域访问,0x0000,0000或者0x8000,0000.2、1、从系统存储器启动:系统存储器被映射到启动空间(0x0000,0000),但仍然能够在原有的地址(0x1FFF,F000)访问它。
system_stm32f10x.c⽂件解读(V3.5.0版本)startup_stm32f10x_hd.s⽂件中,调⽤了⼀个叫SystemInit的函数,该函数其实在system_stm32f10x.c中定义,旨在初始化系统时钟、初始化外部SRAM、设置中断向量表地址。
void SystemInit (void){/* 使能内部⾼速时钟 */RCC->CR |= (uint32_t)0x00000001;#ifndef STM32F10X_CLRCC->CFGR &= (uint32_t)0xF8FF0000;#elseRCC->CFGR &= (uint32_t)0xF0FF0000;#endif/* 禁⽤PLL、禁⽤始时钟检测、禁⽤外部⾼速时钟 */RCC->CR &= (uint32_t)0xFEF6FFFF;/* 外部1-25M振荡器未被绕过 */RCC->CR &= (uint32_t)0xFFFBFFFF;/* USB预分频器PLL未分频、PLL倍频2、HSE未被分频、HSI/2作为PLL频率 */RCC->CFGR &= (uint32_t)0xFF80FFFF;/* 禁⽤时钟中断寄存器 */#ifdef STM32F10X_CLRCC->CR &= (uint32_t)0xEBFFFFFF;RCC->CIR = 0x00FF0000;RCC->CFGR2 = 0x00000000;#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)RCC->CIR = 0x009F0000;/* Reset CFGR2 register */RCC->CFGR2 = 0x00000000;#elseRCC->CIR = 0x009F0000;#endif /* STM32F10X_CL *//* 设置外部SRAM */#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)#ifdef DATA_IN_ExtSRAMSystemInit_ExtMemCtl();#endif /* DATA_IN_ExtSRAM */#endif/* 配置系统时钟 */SetSysClock();/*中断向量偏移地址设置 */#ifdef VECT_TAB_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */#elseSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */#endif}由源代码注释的第2条可以得知,单⽚机⼀上电或复位,以8M的HSI运⾏,之后执⾏函数SystemInit (),此函数的功能主要是复位与时钟相关的寄存器,并执⾏SetSysClock()。
;* 文件名: startup_stm32f10x_hd.s;* 库版本: V3.5.0;* 说明: 此文件为STM32F10x高密度设备的MDK工具链的启动文件;* 该模块执行以下操作:;* -设置初始堆栈指针(SP);* -设置初始程序计数器(PC)为复位向量,并在执行main函数前初始化系统时钟;* -设置向量表入口为异常事件的入口地址;* -复位之后处理器为线程模式,优先级为特权级,堆栈设置为MSP主堆栈;*Stack_Size EQU 0x00000200 ;定义堆栈的大小;AREA 命令指示汇编器汇编一个新的代码段或数据段。
;段是独立的、指定的、不可见的代码或数据块,它们由链接器处理.;段是独立的、命名的、不可分割的代码或数据序列。
一个代码段是生成一个应用程序的最低要求;默认情况下,ELF 段在四字节边界上对齐。
expression 可以拥有0 到31 的任何整数。
;段在2expression 字节边界上对齐AREA STACK, NOINIT, READWRITE, ALIGN=3 ;堆栈段,未初始化,允许读写,8字节边界对齐; 说明: Cortex-M3的指令地址要求是字边界对齐(4字节);但是代码段是8字节边界对齐的Stack_Mem SPACE Stack_Size ;分配堆栈空间,把首地址赋给Stack_Mem __initial_sp ;初始化堆栈指针,指向堆栈顶.; 此处有个一个问题讨论,关于栈顶在RAM中所处位置问题,很多初学者一直以为是编译器特意放在HEAP段之后是有意为之,并且认为这样可以利用heap 未分配空间来防止未知的栈溢出问题; 这种理解是错误的,链接器并不会为栈的位置做特殊的处理,而且这样做也并不会利用heap段,在此文件的最后对堆栈的初始化代码中可以看出他们是两个互相独立的数据区。
此处出现的现; 象是因为MDK按数据段的字母顺序链接数据段的地址的,所以此处造成了堆的地址在栈的前面的假象,不要窃以为是有某种特殊的约定。
STM32固件库V3.5.0的CMSIS文件解析1.首先选择启动文件:根据自己所用芯片的型号,选择正确的启动文件。
例如选择STM32F107系列的处理器,我们就选择startup_stm32f10x_hd.s。
在这个文件里首先要定义自己堆栈的大小,根据自己的需要确定。
文件中已经定义好了中断向量的位置及堆栈的初始化操作。
/* Reset handler*/Reset_Handler PROCEXPORT Reset_Handler [WEAK]IMPORT __mainIMPORT SystemInitLDR R0, =SystemInitBLX R0LDR R0, =__mainBX R0ENDP通过上面的代码可以看到先执行SystemInit()函数在进入main()函数。
SystemInit()函数在文件system_stm32f10x.c中有定义。
2.stm32f10x.h:这个头文件包含了STM32的大部份定义:①定义了芯片的类型,例如:#define STM32F10X_CL②定义是否包含标准外设库,#defined USE_STDPERIPH_DRIVER③定义外部振荡器频率,#defined HSE_V ALUE上面的三个定义,最好在编译器选项中定义好,这样就不用修改stm32f10x.h文件,最好不要修改这个文件。
④采用枚举的方式定义中断号。
⑤包含core_cm3.h,system_stm32f10x.h。
#include "core_cm3.h"#include "system_stm32f10x.h"#include <stdint.h>⑥定义数据类型,例如:typedef uint32_t u32此外还定义了FlagStatus,ITStatus及ErrorStatus等。
⑦定义外设结构体,地址及用到的常量。
⑧包含stm32f10x_conf.h来配置外设。
STM32库文件1.1.1 STM32标准外设库概述STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。
该函数库还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了一个中间API,通过使用固件函数库,无需深入掌握底层硬件细节,开发者就可以轻松应用每一个外设。
因此,使用固态函数库可以大大减少用户的程序编写时间,进而降低开发成本。
每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。
每个器件的开发都由一个通用API (application programming interface 应用编程界面)驱动,API对该驱动程序的结构,函数和参数名称都进行了标准化。
ST公司2007年10月发布了V1.0版本的固件库,MDK ARM3.22之前的版本均支持该库。
2008年6月发布了V2.0版的固件库,从2008年9月推出的MDK ARM3.23版本至今均使用V2.0版本的固件库。
V3.0以后的版本相对之前的版本改动较大,本书使用目前较新的V3.4版本。
1.1.2 使用标准外设库开发的优势简单的说,使用标准外设库进行开发最大的优势就在于可以使开发者不用深入了解底层硬件细节就可以灵活规范的使用每一个外设。
标准外设库覆盖了从GPIO到定时器,再到CAN、I2C、SPI、UART和ADC等等的所有标准外设。
对应的C源代码只是用了最基本的C编程的知识,所有代码经过严格测试,易于理解和使用,并且配有完整的文档,非常方便进行二次开发和应用。
1.1.3 STM32F10XXX标准外设库结构与文件描述1. 标准外设库的文件结构在上一小节中已经介绍了使用标准外设库的开发的优势,因此对标准外设库的熟悉程度直接影响到程序的编写,下面让我们来认识一下STM32F10XXX的标准外设库。
STM32F10XXX的标准外设库经历众多的更新目前已经更新到最新的3.5版本,开发环境中自带的标准外设库为2.0.3版本,本书中以比较稳定而且较新的V3.4版本为基础介绍标准外设库的结构。
STM32 之启动文件详解在嵌入式应用程序开发过程里,由于使用C 语言编程,基本很少涉及到机器底层寄存器的执行过程,一般都会直接在main 函数里开始写代码,似乎main 成为了理所当然的起点,尽管从C 程序的角度来看程序都是直接从main 函数开始执行。
然而,MCU 上电后,是如何寻找到并执行main 函数这一问题却很自然的被忽略了!事实上微控制器是无法从硬件上去定位main 函数的入口地址,因为使用C 语言作为开发语言后,变量/函数的地址便由编译器在编译时自行分配,因此main 函数的入口地址在编译后便不一定是一个绝对地址。
MCU 上电后又是如何寻找到这个入口地址呢?以前接触无论是PIC、AVR、MSP430 或是51 过程中都没涉及到启动文件的配置,仅仅只有熔丝位或配置字是需要根据实际使用配置来设置,其实并非没有,而是由于大部分的开发环境往往自动完整地提供了这个启动文件,不需要开发人员再行干预启动过程,只需要从main 函数开始进行应用程序的设计即可。
然而,但接触到嵌入内核比如Linux 系统移植过程bootloader 却是很重要也是必不可少的一个环节。
事实上,每一种微控制器,无论性能高下,结构简繁,价格贵贱都是必须有启动文件才能正常工作的,它的作用同bootloader 类似。
启动文件完成了微控制器从复位到开始执行main 函数中间这段时间的必要启动配置。
在STM32 中,如果是在MDK 下创建一个工程,一般都有提示是否加入Star up Code 文件,这个就是启动文件,这里有个误区,一般对于初学者来看,很容易误以为STM32F10x.s 这个启动文件是STM32 所有类型芯片的通用启动文件,因此也自然不会去理会它的作用,事实上,这个启动文件只是。
关于STM32F103 V3.5.0 固件库stm32f10x_conf.h 文件最近项目使用STM32,又重新熟悉了一下STM32 的工程建立与程序设计,总结了一下,发现了之前没有发现的技巧与设置。
关于STM32F103 的V3.5.0固件库,使用起来,挺方便,移植性也不错,当然,如果使用Keil uVesion4 开始的话,首先需要设置好工作环境,才可以正常的编译。
为什么会有:main.c里面怎么来的stm32f10x_conf.h 文件?我搜索了一下代码,发现来自:主头文件#include “stm32f10x.h”若是使用ST 公司为STM32 开发的固件库,就会包括头文件:stm32f10x_conf.h。
打开stm32f10x_conf.h 文件一看,原来,只有:#include “stm32f10x.h”还不够,如果要使用外设什么的,还要在这里打开配置开关,不用的外设可以不加入头文件,看来设计的挺巧妙的。
这样使用外设库时,只要配置好就行了,在main.c 里只使用一个:#include “stm32f10x.h”就可以了。
看来如果不配置好stm32f10x_conf.h,当使用外设如ADC TIM USART 时,根据无法编译通过。
因为没有在项目里加入头文件调用,这里若全不选,根本不能调用固件外设库,即使你把固件库文件加入了工程里。
当然,你可以在main.c 里面全部加入需要的头文件来解决,不过我觉得配置stm32f10x_conf.h 简单方便,有组织。
在这里,加入了需要使用的固件库外设文件,但还不够,还需要设置如下:还加入头文件路径:根据使用的外设固件库配置一下:stm32f10x_conf.h,如果使用systick 系统滴答定时器等,只要在stm32f10x_conf.h 里,取消#include “misc.h”前面的注释,即包含这个misc.h 文件即可,否则,滴答定时器不工作。
本文通过对STM32的官方固件库STM32F10x_StdPeriph_Lib_V3.5.0里的MDK启动文件分析,简化部分不需要的代码,并从繁杂的固件库里,精炼出一个类似于“hello world”的入门实战小程序——点亮一个LED。
该工程仅仅包含一个启动文件和一个有main函数的C文件。
本文初衷:不用固件库建立自己的工程!实验软件:Keil uVision4实验硬件:神舟IV号开发板芯片型号:STM32F107VCSTM32启动代码分析、简化、实战汇编基础:1.伪指令:EQU语法格式:名称EQU表达式{,类型}EQU伪指令用于为程序中的常量、标号等定义一个等效的字符名称,类似于C语言的#define。
其中EQU可以用“*”代替。
名称为EQU伪指令定义的字符名称,当表达式为32位的常量时,可以指定表达式的数据类型,可以有一下三种类型:CODE16、CODE32和DA TA2.伪指令:AREA语法格式:AREA段名{,属性1}{,属性2}……AREA命令指示汇编程序汇编一个新的代码段或数据段。
段是独立的、指定的、不可见的代码或数据块,它们由链接程序处理。
段名:可以为段选择任何段名。
但是,以一个数字开始的名称必须包含在竖杠号内,否则会产生一个缺失段名错误。
例如,|1_DataArea|。
有些名称是习惯性的名称。
例如:|.text|用于表示由C编译程序产生的代码段,或用于以某种方式与C库关联的代码段。
属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。
常用的属性如下:——CODE属性:用于定义代码段,默认为READONLY。
——DA TA属性:用于定义数据段,默认为READWRITE。
——READONLY属性:指定本段为只读,代码段默认为READONLY。
——READWRITE属性:指定本段为可读可写,数据段的默认属性为READWRITE。
——ALIGN属性:使用方式为ALIGN表达式。
**这里是STM32比较重要的头文件我愛你的吻123原創講解QQ:1746430162****************************************************************************** * @file stm32f10x.h ST 标准的头文件* @author MCD Application Team 微控制器开发小组。
* @version V3.5.0 版本* @date 11-March-2011 2011年3月11* @brief CMSIS Cortex-M3 Device Peripheral Access Layer Header File.(CMSIS:Cortex Microcontroller Software Interface Standard) 是Cortex-M 处理器系列的与供应商无关的硬件抽象层。
* This file contains all the peripheral register's definitions, bits* definitions and memory mapping for STM32F10x Connectivity line,* High density, High density value line, Medium density,* Medium density Value line, Low density, Low density Value line* and XL-density devices.* 这个文件包含了芯片STM32F10X(接口增强型)内部的寄存器定义,位定义,内存地址变换定义,还有一些相应的高密度,低密度产品线的设备。
* The file is the unique include file that the application programmer* is using in the C source code, usually in main.c. This file contains:* - Configuration section that allows to select:* - The device used in the target application* - To use or not the peripherals drivers in application code(i.e.* code will be based on direct access to peripherals registers* rather than drivers API), this option is controlled by* "#define USE_STDPERIPH_DRIVER"* - To change few application-specific parameters such as the HSE* crystal frequency* - Data structures and the address mapping for all peripherals* - Peripheral's registers declarations and bits definition* - Macros to access peripheral registers hardware*这个文件在应用程序中是至关重要的头文件,它是用C代码编写而成。
1/6/afeibfp/archive/2013/01/08/2850408.html <2013年1月>日一二三四五六303112345678910111213141516171819202122232425262728293031123456789昵称:afeibfp 园龄:2年5个月粉丝:0关注:0+加关注搜索找找看 谷歌搜索常用链接我的随笔我的评论我的参与最新评论我的标签更多链接我的标签51单片机(2)多字节除法(2)汇编(2)随笔分类(2)转发(2)随笔档案(16)2013年1月 (14)2011年9月 (2)最新评论1. Re:014:针对mdk 中STM32程序无法使用printf ,产生停留BEAB BKPT 0xAB 处问题的解决(转)不点那个MiclroLIB 就行了--blakeliu阅读排行榜1. 001:无符号双字节除以单字节(51单片机,汇编源码)(418)2. 004:STM32启动文件详解及SystemInit 函数分析(转)(389)3. 014:针对mdk 中STM32程序无法使用printf ,产生停留BE AB BKPT 0xAB 处问题的解决(转)(312)4. 010:请教STM32用JLINK V8 SWD 输出调试信息到ITM V iewer 的问题(转)(208)5. 009:semihost/ITM 机制浅析以及使用JLINK 通过ITM 调试stm32单片机(转)(190)评论排行榜1. 014:针对mdk 中STM32程序无法使用printf ,产生停留BE AB BKPT 0xAB 处问题的解决(转)(1)2. 013:ADS semihosting 与硬件重定向(转)(0)3. 012:Keil 调试技术(转)(0)4. 011:Nuvoton(新唐) Cort ex M0 使用semihost 输入输出办法(转)(0)5. 010:请教STM32用JLINK V8 SWD 输出调试信息到ITM V iewer 的问题(转)(0)推荐排行榜博客园首页新随笔联系管理订阅 随笔- 16 文章- 0 评论- 1afeibfp004:STM32启动文件详解及SystemInit 函数分析(转)1 ;先在R A M 中分配系统使用的栈,R A M 的起始地址为0x 2000_00002 ;然后在R A M 中分配变量使用的堆3 ;然后在C O D E 区(f l a s h )分配中断向量表,f l a s h 的起始地址为0x 0800_0000,该中断向量表就从这个起始地址开始分配4 ;分配完成后,再定义和实现相应的中断函数,5 ;所有的中断函数全部带有[w e a k ]特性,即弱定义,如果编译器发现在别处文件中定义了同名函数,在链接时用别处的地址进行链接。
STM32启动文件详解一、启动文件的作用1.初始化堆栈指针 SP;2.初始化程序计数器指针 PC;3.设置堆、栈的大小;4.设置异常向量表的入口地址;5.配置外部 SRAM作为数据存储器(这个由用户配置,一般的开发板可没有外部SRAM);6.设置 C库的分支入口__main(最终用来调用 main函数);7.在 3.5版的启动文件还调用了在 system_stm32f10x.c文件中的SystemIni()函数配置系统时钟。
二、汇编指令三、启动代码1.stack ----- 栈Stack_Size EQU 0x00000400 ; 栈的大小AREA STACK, NOINIT, READWRITE,ALIGN=3 Stack_Mem SPACE Stack_Size ; 分配栈空间__initial_sp ; 栈的结束地址(栈顶地址) 分配名为STACK,不初始化,可读可写,8(2^3)字节对齐的1KB空间。
栈:局部变量,函数形参等。
栈的大小不能超过内部SRAM大小。
AREA:汇编一个新的代码段或者数据段。
STACK段名,任意命名;NOINIT表示不初始化;READWRITE可读可写;ALIGN=3(2^3= 8字节对齐)。
__initial_sp紧挨了SPACE放置,表示栈的结束地址,栈是从高往低生长,结束地址就是栈顶地址。
2.heap ----- 堆Heap_Size EQU 0x00000200 ; 堆的大小(512Bytes)AREA HEAP, NOINIT, READWRITE,ALIGN=3__heap_base ; 堆的起始地址Heap_Mem SPACE Heap_Size ; 分配堆空间__heap_limit ; 堆的结束地址分配名为HEAP,不初始化,可读可写,8(2^3)字节对齐的512字节空间。
__heap_base堆的起始地址,__heap_limit堆的结束地址。
;******************** (C) COPYRIGHT 2011 STMicroelectronics ********************;* File Name : startup_stm32f10x_hd.s;* Author : MCD Application Team;* Version : V3.5.0;* Date : 11-March-2011;* Description : STM32F10x High Density Devices vector table for MDK-ARM;* 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 and also configure the external;* SRAM mounted on STM3210E-EVAL board to be used as data;* memory (optional, to be enabled by user);* - 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 >>>;****************************************************************************** *; THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS; WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.; AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,; INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE ; CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING; INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.;****************************************************************************** *; Amount of memory (in bytes) allocated for Stack; Tailor this value to your application needs; <h> Stack Configuration; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>; </h>Stack_Size EQU 0x00000400//栈大小为1KAREA STACK, NOINIT, READWRITE, ALIGN=3//分配一个8字节对齐的段给栈,NOINT指定数据仅仅保留了内存单元Stack_Mem SPACE Stack_Size //分配栈空间为1K,用0填充__initial_sp //标号_init_sp表示栈顶地址; <h> Heap Configuration; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>; </h>Heap_Size EQU 0x00000200 //定义堆大小为512B,类似于链表AREA HEAP, NOINIT, READWRITE, ALIGN=3 //定义堆空间,8字节对其__heap_base //堆空间基址Heap_Mem SPACE Heap_Size //分配512B对空间并清0__heap_limit //对空间结束PRESERVE8 //告诉编译器链接时8字节对齐THUMB //Thumb指令//中断向量表定义,实际上在CODE区,如果从FLASH启动,则起始地址为0x8000000; Vector Table Mapped to Address 0 at Reset //复位后中断向量表映射到地址0AREA RESET, DATA, READONLY //只读的数据段RESETEXPORT __Vectors //声明全局标号_Vector,向量表入口EXPORT __Vectors_End //声明全部标号,中断向量表结束地址EXPORT __Vectors_Size //向量大小__Vectors DCD __initial_sp ; Top of Stack/*栈顶地址0x00000000,该处存放_init_sp表示的地址的值,放在向量表的开始,FLASH的0地址,复位后首先装载栈顶指针*/DCD Reset_Handler ; Reset Handler//复位中断,地址0x00000004,装载完栈顶指针后执行,不返回DCD NMI_Handler ; NMI Handler//不可屏蔽中断,地址0x00000008DCD HardFault_Handler ; Hard Fault HandlerDCD MemManage_Handler ; MPU Fault HandlerDCD BusFault_Handler ; Bus Fault HandlerDCD UsageFault_Handler ; Usage Fault HandlerDCD 0 ; ReservedDCD 0 ; ReservedDCD 0 ; ReservedDCD 0 ; ReservedDCD SVC_Handler ; SVCall HandlerDCD DebugMon_Handler ; Debug Monitor HandlerDCD 0 ; ReservedDCD PendSV_Handler ; PendSV HandlerDCD SysTick_Handler ; SysTick Handler//以上给出的都是内核中断的函数指针; External Interrupts //以下为外设中断函数指针DCD WWDG_IRQHandler ; Window WatchdogDCD PVD_IRQHandler ; PVD through EXTI Line detect DCD TAMPER_IRQHandler ; TamperDCD RTC_IRQHandler ; RTCDCD FLASH_IRQHandler ; FlashDCD RCC_IRQHandler ; RCCDCD EXTI0_IRQHandler ; EXTI Line 0DCD EXTI1_IRQHandler ; EXTI Line 1DCD EXTI2_IRQHandler ; EXTI Line 2DCD EXTI3_IRQHandler ; EXTI Line 3DCD EXTI4_IRQHandler ; EXTI Line 4DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7DCD ADC1_2_IRQHandler ; ADC1 & ADC2DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX DCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0 DCD CAN1_RX1_IRQHandler ; CAN1 RX1DCD CAN1_SCE_IRQHandler ; CAN1 SCEDCD EXTI9_5_IRQHandler ; EXTI Line 9..5DCD TIM1_BRK_IRQHandler ; TIM1 BreakDCD TIM1_UP_IRQHandler ; TIM1 UpdateDCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation DCD TIM1_CC_IRQHandler ; TIM1 Capture CompareDCD TIM2_IRQHandler ; TIM2DCD TIM3_IRQHandler ; TIM3DCD TIM4_IRQHandler ; TIM4DCD I2C1_EV_IRQHandler ; I2C1 EventDCD I2C1_ER_IRQHandler ; I2C1 ErrorDCD I2C2_EV_IRQHandler ; I2C2 EventDCD I2C2_ER_IRQHandler ; I2C2 ErrorDCD SPI1_IRQHandler ; SPI1DCD SPI2_IRQHandler ; SPI2DCD USART1_IRQHandler ; USART1DCD USART2_IRQHandler ; USART2DCD USART3_IRQHandler ; USART3DCD EXTI15_10_IRQHandler ; EXTI Line 15..10DCD RTCAlarm_IRQHandler ; RTC Alarm through EXTI Line DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend DCD TIM8_BRK_IRQHandler ; TIM8 BreakDCD TIM8_UP_IRQHandler ; TIM8 UpdateDCD TIM8_TRG_COM_IRQHandler ; TIM8 Trigger and CommutationDCD TIM8_CC_IRQHandler ; TIM8 Capture CompareDCD ADC3_IRQHandler ; ADC3DCD FSMC_IRQHandler ; FSMCDCD SDIO_IRQHandler ; SDIODCD TIM5_IRQHandler ; TIM5DCD SPI3_IRQHandler ; SPI3DCD UART4_IRQHandler ; UART4DCD UART5_IRQHandler ; UART5DCD TIM6_IRQHandler ; TIM6DCD TIM7_IRQHandler ; TIM7DCD DMA2_Channel1_IRQHandler ; DMA2 Channel1DCD DMA2_Channel2_IRQHandler ; DMA2 Channel2DCD DMA2_Channel3_IRQHandler ; DMA2 Channel3DCD DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5__Vectors_End__Vectors_Size EQU __Vectors_End - __Vectors//计算中断向量表长度//地址重映射及中断向量表的转移AREA |.text|, CODE, READONLY//代码段//|.text|表示由C编译器产生的代码段或用于以某种方式与C库关联的代码段; Reset handler //复位中断函数入口Reset_Handler PROC //函数开始EXPORT Reset_Handler [WEAK]//声明为全局中断向量IMPORT __mainIMPORT SystemInitLDR R0, =SystemInit //系统初始化BLX R0LDR R0, =__main//__main是C_library中函数,调用下面定义的_user_initial_stackheap完成堆、栈的初始化BX R0//main函数丕返回ENDP; Dummy Exception Handlers (infinite loops which can be modified)NMI_Handler PROCEXPORT NMI_Handler [WEAK]B .ENDPHardFault_Handler\ // \换行PROCEXPORT HardFault_Handler [WEAK]B .ENDPMemManage_Handler\PROCEXPORT MemManage_Handler [WEAK]B .ENDPBusFault_Handler\PROCEXPORT BusFault_Handler [WEAK]B .ENDPUsageFault_Handler\PROCEXPORT UsageFault_Handler [WEAK]B .ENDPSVC_Handler PROCEXPORT SVC_Handler [WEAK]B .ENDPDebugMon_Handler\PROCEXPORT DebugMon_Handler [WEAK]B .ENDPPendSV_Handler PROCEXPORT PendSV_Handler [WEAK]B .ENDPSysTick_Handler PROCEXPORT SysTick_Handler [WEAK]B .ENDPDefault_Handler PROC/*WEAK是弱定义的意思,如果外部定义了同名的函数,优先执行外面的,否则下面的用nop 代替*/EXPORT WWDG_IRQHandler [WEAK]EXPORT PVD_IRQHandler [WEAK]EXPORT TAMPER_IRQHandler [WEAK]EXPORT RTC_IRQHandler [WEAK]EXPORT FLASH_IRQHandler [WEAK]EXPORT RCC_IRQHandler [WEAK]EXPORT EXTI0_IRQHandler [WEAK]EXPORT EXTI1_IRQHandler [WEAK]EXPORT EXTI3_IRQHandler [WEAK] EXPORT EXTI4_IRQHandler [WEAK] EXPORT DMA1_Channel1_IRQHandler [WEAK] EXPORT DMA1_Channel2_IRQHandler [WEAK] EXPORT DMA1_Channel3_IRQHandler [WEAK] EXPORT DMA1_Channel4_IRQHandler [WEAK] EXPORT DMA1_Channel5_IRQHandler [WEAK] EXPORT DMA1_Channel6_IRQHandler [WEAK] EXPORT DMA1_Channel7_IRQHandler [WEAK] EXPORT ADC1_2_IRQHandler [WEAK] EXPORT USB_HP_CAN1_TX_IRQHandler [WEAK] EXPORT USB_LP_CAN1_RX0_IRQHandler [WEAK] EXPORT CAN1_RX1_IRQHandler [WEAK] EXPORT CAN1_SCE_IRQHandler [WEAK] EXPORT EXTI9_5_IRQHandler [WEAK] EXPORT TIM1_BRK_IRQHandler [WEAK] EXPORT TIM1_UP_IRQHandler [WEAK] EXPORT TIM1_TRG_COM_IRQHandler [WEAK] EXPORT TIM1_CC_IRQHandler [WEAK] EXPORT TIM2_IRQHandler [WEAK] EXPORT TIM3_IRQHandler [WEAK] EXPORT TIM4_IRQHandler [WEAK] EXPORT I2C1_EV_IRQHandler [WEAK] EXPORT I2C1_ER_IRQHandler [WEAK] EXPORT I2C2_EV_IRQHandler [WEAK] EXPORT I2C2_ER_IRQHandler [WEAK] EXPORT SPI1_IRQHandler [WEAK] EXPORT SPI2_IRQHandler [WEAK] EXPORT USART1_IRQHandler [WEAK] EXPORT USART2_IRQHandler [WEAK] EXPORT USART3_IRQHandler [WEAK] EXPORT EXTI15_10_IRQHandler [WEAK] EXPORT RTCAlarm_IRQHandler [WEAK] EXPORT USBWakeUp_IRQHandler [WEAK] EXPORT TIM8_BRK_IRQHandler [WEAK] EXPORT TIM8_UP_IRQHandler [WEAK] EXPORT TIM8_TRG_COM_IRQHandler [WEAK] EXPORT TIM8_CC_IRQHandler [WEAK] EXPORT ADC3_IRQHandler [WEAK] EXPORT FSMC_IRQHandler [WEAK] EXPORT SDIO_IRQHandler [WEAK] EXPORT TIM5_IRQHandler [WEAK] EXPORT SPI3_IRQHandler [WEAK]EXPORT UART5_IRQHandler [WEAK] EXPORT TIM6_IRQHandler [WEAK] EXPORT TIM7_IRQHandler [WEAK] EXPORT DMA2_Channel1_IRQHandler [WEAK] EXPORT DMA2_Channel2_IRQHandler [WEAK] EXPORT DMA2_Channel3_IRQHandler [WEAK] EXPORT DMA2_Channel4_5_IRQHandler [WEAK] //下面只是定义一个空函数WWDG_IRQHandlerPVD_IRQHandlerTAMPER_IRQHandlerRTC_IRQHandlerFLASH_IRQHandlerRCC_IRQHandlerEXTI0_IRQHandlerEXTI1_IRQHandlerEXTI2_IRQHandlerEXTI3_IRQHandlerEXTI4_IRQHandlerDMA1_Channel1_IRQHandlerDMA1_Channel2_IRQHandlerDMA1_Channel3_IRQHandlerDMA1_Channel4_IRQHandlerDMA1_Channel5_IRQHandlerDMA1_Channel6_IRQHandlerDMA1_Channel7_IRQHandlerADC1_2_IRQHandlerUSB_HP_CAN1_TX_IRQHandlerUSB_LP_CAN1_RX0_IRQHandlerCAN1_RX1_IRQHandlerCAN1_SCE_IRQHandlerEXTI9_5_IRQHandlerTIM1_BRK_IRQHandlerTIM1_UP_IRQHandlerTIM1_TRG_COM_IRQHandlerTIM1_CC_IRQHandlerTIM2_IRQHandlerTIM3_IRQHandlerTIM4_IRQHandlerI2C1_EV_IRQHandlerI2C1_ER_IRQHandlerI2C2_EV_IRQHandlerI2C2_ER_IRQHandlerSPI1_IRQHandlerSPI2_IRQHandlerUSART1_IRQHandlerUSART2_IRQHandlerUSART3_IRQHandlerEXTI15_10_IRQHandlerRTCAlarm_IRQHandlerUSBWakeUp_IRQHandlerTIM8_BRK_IRQHandlerTIM8_UP_IRQHandlerTIM8_TRG_COM_IRQHandlerTIM8_CC_IRQHandlerADC3_IRQHandlerFSMC_IRQHandlerSDIO_IRQHandlerTIM5_IRQHandlerSPI3_IRQHandlerUART4_IRQHandlerUART5_IRQHandlerTIM6_IRQHandlerTIM7_IRQHandlerDMA2_Channel1_IRQHandlerDMA2_Channel2_IRQHandlerDMA2_Channel3_IRQHandlerDMA2_Channel4_5_IRQHandlerB .ENDPALIGN;****************************************************************************** *; User Stack and Heap initialization;****************************************************************************** *IF :DEF:__MICROLIB/*判断是否定义了宏_MICROLIB,如果是将栈顶地址、堆始末地址赋予全局属性使外部程序可以使用*/EXPORT __initial_sp //全局_inital_spEXPORT __heap_baseEXPORT __heap_limitELSE/*否则(使用C库),声明以下全局标号,使外部程序可以调用此标号进行堆栈赋值*/ IMPORT __use_two_region_memoryEXPORT __user_initial_stackheap__user_initial_stackheap//堆栈初始化程序入口,堆向上生长,栈向下生长LDR R0, = Heap_MemLDR R1, =(Stack_Mem + Stack_Size)LDR R2, = (Heap_Mem+ Heap_Size)LDR R3, = Stack_MemBX LRALIGNENDIFEND;******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****说明1、Stm32系统复位后,sysclk第4个上升沿,通过设置BOOT1和BOOT0引脚状态选择启动模式。
STM32 启动过程全解
电子发烧友网核心提示:本文主要阐述了STM32 启动过程全面解
析,包括启动过程的介绍、启动代码的陈列以及深入解析。
相对于ARM 上一代的主流ARM7/ARM9 内核架构,新一代Cortex
内核架构的启动方式有了比较大的变化。
ARM7/ARM9 内核的控制器在复位后,CPU 会从存储空间的绝对地址0x000000 取出第一条指令执行复位中断
服务程序的方式启动,即固定了复位后的起始地址为0x000000(PC = 0x000000)同时中断向量表的位置并不是固定的。
而Cortex-M3 内核则正好相反,有3 种情况:
1、通过boot 引脚设置可以将中断向量表定位于SRAM 区,即起始地址为0x2000000,同时复位后PC 指针位于0x2000000 处;
2、通过boot 引脚设置可以将中断向量表定位于FLASH 区,即起始地址为0x8000000,同时复位后PC 指针位于0x8000000 处;
3、通过boot 引脚设置可以将中断向量表定位于内置Bootloader 区,本文不对这种情况做论述;。
STM32启动代码详细分析最近需要学习iap的功能,因此离不开stm32的启动代码的分析,以前看了很多遍,都看不懂,读书百遍,其义⾃见,因此我有看了⼀遍,下⾯的⽂章,挺好的,因此转载:在上电复位后,我们都知道会先运⾏启动代码,但是启动代码到底使⼲什么⽤的呢?下⾯⼩弟给⼤家⼀⼀列出来。
1、初始化堆栈指针2、初始化 PC 指针3、初始化中断向量表4、配置系统时钟5、调⽤ C 库函数_main 初始化⽤户堆栈我们根据这以上的⼏个步骤⼀⼀进⾏详细的解析:1、栈的内存分配这段代码的意思是,开辟了⼀个栈,这个栈的⼤⼩是0x00000400也就是1KB的⼤⼩,名字为STACK,不初始化,可读可写,2^3=8字节对齐。
那么问题来了,那这个栈到底使⼲什么的呢?⼩弟相信⼤家在学习C语⾔的时候应该也是知道了,栈区保存的是局部变量,只是当时并没有深⼊研究它的⼤⼩问题。
那在这⾥⼩弟给⼤家详细讲解⼀下栈的作⽤:1、局部变量2、函数调⽤3、函数形参以上的这三种情况的开销都是使⽤我们的栈区的资源的。
所以啊!这⾥⼩弟给个位提个醒,千万不要把栈区当成⽆⽌境⼤⼩的哦!STM32可不⽐我们的电脑,没有那么多的空间可以给⼤伙挥霍,如果我们定义的局部变量过⼤可是会莫名其妙报错的。
温馨提⽰:请不要在写程序时,过度使⽤局部变量,会造成栈的益处,从⽽导致编译报错,如果在特殊情况下真的需要很⼤的栈区空间,只需来这⾥进⾏栈区⼤⼩的修改即可。
那么⼩弟再来给这个程序段⾥的汇编指令做⼀个详细的介绍Stack_Size EQU 0x00000400EQU:宏定义的伪指令,相当于等于,类似与 C 中的 define。
这句话的意思是,定义⼀个宏名Stack_Size这个宏代表0x00000400的意思,⽤我们C语⾔来表⽰就是#define Stack_Size 0x00000400AREA STACK, NOINIT, READWRITE, ALIGN=3AREA:告诉汇编器汇编⼀个新的代码段或者数据段。
在<<STM32不完全手册里面>>,用的是STM32F103RBT6,所有的例程都采用了一个叫STM32F10x.s的启动文件,里面定义了STM32的堆栈大小以及各种中断的名字及入口函数名称,还有启动相关的汇编代码。
STM32F10x.s是MDK提供的启动代码,从其里面的内容看来,它只定义了3个串口,4个定时器。
实际上STM32的系列产品有5个串口的型号,也只有有2个串口的型号,定时器也是,做多的有8个定时器。
比如,如果你用的STM32F103ZET6,而启动文件用的是STM32F10x.s的话,你可以正常使用串口1~3的中断,而串口4和5的中断,则无**常使用。
又比如,你TIM1~4的中断可以正常使用,而5~8的,则无法使用。
而在固件库里出现3个文件startup_stm32f10x_ld.sstartup_stm32f10x_md.sstartup_stm32f10x_hd.s其中,ld.s适用于小容量产品;md.s适用于中等容量产品;hd适用于大容量产品;这里的容量是指FLASH的大小.判断方法如下:小容量:FLASH≤32K中容量:64K≤FLASH≤128K大容量:256K≤FLASH;******************** (C) COPYRIGHT 2011 STMicroelectronics ********************;* File Name : startup_stm32f10x_hd.s;* Author : MCD Application Team;* Version : V3.5.0;* Date : 11-March-2011;* Description : STM32F10x High Density Devices vector table for MDK-ARM;* 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 and also configure the external;* SRAM mounted on STM3210E-EVAL board to be used as data;* memory (optional, to be enabled by user);* - 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.;* 说明: 此文件为STM32F10x高密度设备的MDK工具链的启动文件;* 该模块执行以下操作:;* -设置初始堆栈指针(SP);* -设置初始程序计数器(PC)为复位向量,并在执行main函数前初始化系统时钟;* -设置向量表入口为异常事件的入口地址;* -复位之后处理器为线程模式,优先级为特权级,堆栈设置为MSP主堆栈;* <<< Use Configuration Wizard in Context Menu >>>; 首先对栈和堆的大小进行定义,并在代码区的起始处建立中断向量表,其第一个表项是栈; 顶地址,第二个表项是复位中断服务入口地址。
然后在复位中断服务程序中跳转??C/C++标; 准实时库的__main函数。
假设STM32被设置为从内部FLASH启动中断向量表起始地位为0x8000000,; 则栈顶地址存放于0x8000000处,而复位中断服务入口地址存放于0x8000004处。
当STM32遇; 到复位信号后,则从0x80000004处取出复位中断服务入口地址继而执行复位中断服务程序,; 然后跳转__main函数,最后来到C的世界。
; DCD指令:作用是开辟一段空间,其意义等价于C语言中的地址符“&”。
开始建立的中断向量; 表则类似于使用C语.其每一个成员都是一个函数指针,分别指向各个中断服务函数;伪指令AREA,表示开辟一段大小为Stack_Size的内存空间作为栈,段名是STACK,可读可写。
;NOINIT:指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各个内存单元值初始化为0;*******************************************************************************; THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS; WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.; AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,; INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE ; CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING; INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.;*******************************************************************************; Amount of memory (in bytes) allocated for Stack; Tailor this value to your application needs; <h> Stack Configuration; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>; </h>Stack_Size EQU 0x00000400 ;定义栈大小1024BAREA STACK, NOINIT, READWRITE, ALIGN=3;###AREA 命令指示汇编器汇编一个新的代码段或数据段。
;段是独立的、指定的、不可见的代码或数据块,它们由链接器处理.;段是独立的、命名的、不可分割的代码或数据序列。
一个代码段是生成一个应用程序的最低要求;默认情况下,ELF 段在四字节边界上对齐。
expression 可以拥有0 到31 的任何整数。
;段在2expression 字节边界上对齐Stack_Mem SPACE Stack_Size ;### ;分配连续Stack_Size 字节的存储单元并初始化为0。
;堆栈段,未初始化,允许读写,8字节边界对齐;说明: Cortex-M3的指令地址要求是字边界对齐(4字节);但是代码段是8字节边界对齐的__initial_sp ;###初始化堆栈指,标号__initial_sp表示指向堆栈顶.; ###此处有个一个问题讨论,关于栈顶在RAM中所处位置问题,很多初学者一直以为是编译器特意放在HEAP段之后是有意为之,并且认为这样可以利用heap未分配空间来防止未知的栈溢出问题; 这种理解是错误的,链接器并不会为栈的位置做特殊的处理,而且这样做也并不会利用heap段,在此文件的最后对堆栈的初始化代码中可以看出他们是两个互相独立的数据区。
此处出现的现; 象是因为MDK按数据段的字母顺序链接数据段的地址的,所以此处造成了堆的地址在栈的前面的假象,不要窃以为是有某种特殊的约定。
; <h> Heap Configuration; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>; </h>Heap_Size EQU 0x00000200 ;定义堆的大小AREA HEAP, NOINIT, READWRITE, ALIGN=3 ;堆段,malloc用的地方,不一定连续空间,未初始化,允许读写,堆数据段8字节边界对齐__heap_base ;表示堆空间起始地址Heap_Mem SPACE Heap_Size ;分配堆空间__heap_limit ;表示堆空间结束地址与__heap_base配合限制堆的大小PRESERVE8 ;命令指定当前文件保持栈的八字节对齐THUMB ;指令集,THUMB 必须位于使用新语法的任何Thumb代码之前; EXPORT 命令声明一个符号,可由链接器用于解释各个目标和库文件中的符号引用,相当于声明了一个全局变量。
GLOBAL 于EXPORT相同。
; 以下为向量表,在复位时被映射到FLASH的0地址; Vector Table Mapped to Address 0 at Reset;实际上是在CODE区(假设STM32从FLASH启动,则此中断向量表起始地址即为0x8000000)AREA RESET, DATA, READONLY ;定义一块数据段,只可读,段名字是RESET,复位段,只包含数据,只读EXPORT __Vectors ;标号输出,中断向量表开始;EXPORT在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用EXPORT __Vectors_End ;在程序中声明一个全局标号__Vectors_EndEXPORT __Vectors_Size ;在程序中声明一个全局号__Vectors_Size,中断向量表大小; DCD 命令分配一个或多个字的存储器,在四个字节的边界上对齐,并定义存储器的运行时初值。
__Vectors ;建立中断表DCD __initial_sp ; Top of Stack 栈顶指针,被放在向量表的开始,FLASH的0地址,复位后首先装载栈顶指针DCD Reset_Handler ; Reset Handler 复位异常,装载完栈顶后,第一个执行的,并且不返回。