Cortex M0+ Keil MDK启动文件详解

本文详细介绍了Cortex M0+微控制器在Keil MDK环境下启动文件的配置和作用,包括栈和堆的设置、栈顶和堆底的定义、数据对齐以及中断处理函数的默认实现。通过对启动文件的解析,读者能够理解MCU复位后的初始状态和内存布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

;/*****************************************************************************
; * @file:    startup_MKL02Z4.s
; * @purpose: CMSIS Cortex-M0plus Core Device Startup File for the
; *           MKL02Z4
; * @version: 1.0
; * @date:    2012-10-4
; *
; * Copyright: 1997 - 2013 Freescale Semiconductor, Inc. All Rights Reserved.
;*
; *------- <<< Use Configuration Wizard in Context Menu >>> ------------------
; *
; *****************************************************************************/


; <h> Stack Configuration
;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Stack_Size      EQU     0x00000100
                ;EQU定义符号指示Stack大小
    
                AREA    STACK, NOINIT, READWRITE, ALIGN=3   
                ;AREA 通知汇编器汇编一段新的代码或数据节(section)
                ;STACK 为AREA所定义的新的节的节名称(sectionname)
                ;NOINIT 指示这段数据节不初始化或初始化为0,以SPACE等指示的空间初始化为0,但不能初始化为其它
                ;       备注:即这段不能指定初始化值,如果不加NOINIT的话,MAP文件SPACE的数据类型为Data,为RW Data
                ;             如果加NOINIT的话,MAP文件SPACE的数据类型为Zero,为ZI Data
                ;READWRITE 指示该节类型为RW
                ;ALIGN=3 指示该节对齐到8字节boundary,即为双字地址
                ;        备注:在MAP文件中,可以发现是通过添加PAD类型的数据进行节的对齐
                ;              PAD取何值可以指定
                                                            

Stack_Mem       SPACE   Stack_Size
                ;Stack_Mem 为一个标签(label),标签值为在当前节中的地址
                ;SPACE 指示(directive)一块内存(memory),这块内存所在节的特性由上面的AREA指定
__initial_sp
                ;__initial_sp 为上面SPACE块的顶端地址+1,即说明堆栈的初始值为顶端地址,堆栈是向下生长的满栈
                ;             备注:因为CM的入栈操作是,*(--R13)=R0类似的一种方式,R13指向最后的数据


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size       EQU     0x00000100
                ;定义符号指示Heap大小

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
                ;定义一个新的节,节名称为HEAP,其它与STACK相同
                ;EXPORT __heap_base
__heap_base
                ;定义一个标签,指示HEAP的基地址,这个标签只用在使用MICROLIB时被EXPORT,即只有这时有效
                ;使用MICROLIB时,这个标签被EXPORT,类似于C语言中的extern,但只有当HEAP被使用的时候
                ;                才出现在MAP文件中,如在main()中可以这样来访问__heap_base
                ;                void main(void)
                ;                {
                ;                   extern int __heap_base;
                ;                   static int HEAPBASE;    //定义静态变量,在内存中有固定的存储空间
                ;                   ......
                ;                   HEAPBASE = __heap_base; //读取HEAP的即地址,只在MICROLIB时有效
                ;                   ......
                ;                 }
                ;如果要在不使用MICROLIB时,读取__heap_base, 那只需要在__heap_base前添加EXPORT __heap_base                   
Heap_Mem        SPACE   Heap_Size
                ;EXPORT Heap_Mem
                ;定义HEAP的内存段,标签为Heap_Mem,将Heap_Mem EXPORT之后,可以这样访问:
                ;       extern int Heap_Mem;
                ;       static int* pHEAPMEM;
                ;       pHEAPMEM = (int*)Heap_Mem;
__heap_limit
                ;定义一个标签,HEAP的地址范围为__heap_base ~ (__heap_limit - 1)
                
;这里结合MAP文件外插上几句
;1. 当:STACK 所在节属性为 AREA    STACK, NOINIT, READWRITE, ALIGN=3
;       HEAP  所在节属性为 AREA    HEAP,  NOINIT, READWRITE, ALIGN=3
;   时,MAP文件的执行时期RAM镜像为
;   Execution Region RW_IRAM2 (Base: 0x20000000, Size: 0x00000268, Max: 0x00000c00, ABSOLUTE)
;
;   Base Addr    Size         Type   Attr      Idx    E Section Name        Object
;
;   0x20000000   0x00000004   Data   RW            4    .data               system_mkl02z4.o
;   0x20000004   0x00000004   Data   RW           61    .data               blinky.o
;   0x20000008   0x00000060   Zero   RW          139    .bss                c_p.l(libspace.o)
;   0x20000068   0x00000100   Zero   RW           48    HEAP                startup_mkl02z4.o
;   0x20000168   0x00000100   Zero   RW           47    STACK               startup_mkl02z4.o
;
;   可见,在程序运行时,数据在内存中存放的顺序为有初始化的Data类型,和0初始化的Zero类型
;   此时,HEAP向上增长,STACK向下生长,二者的方向是相向的
;   全局变量,如果没有指定初始值,如static int gTestData; 是存放在.dada节,而不是.bss
;
;2. 当:STACK 所在节属性为 AREA    STACK,         READWRITE, ALIGN=3
;       HEAP  所在节属性为 AREA    HEAP,  NOINIT, READWRITE, ALIGN=3
;   时,MAP文件的执行时期RAM镜像为
;   Execution Region RW_IRAM2 (Base: 0x20000000, Size: 0x00000268, Max: 0x00000c00, ABSOLUTE)
;
;   Base Addr    Size         Type   Attr      Idx    E Section Name        Object
;
;   0x20000000   0x00000004   Data   RW            4    .data               system_mkl02z4.o
;   0x20000004   0x00000004   Data   RW           61    .data               blinky.o
;   0x20000008   0x00000100   Data   RW           47    STACK               startup_mkl02z4.o
;   0x20000108   0x00000060   Zero   RW          139    .bss                c_p.l(libspace.o)
;   0x20000168   0x00000100   Zero   RW           48    HEAP                startup_mkl02z4.o
;
;   此时HEAP向上增长,STACK向下生长,二者的方向是相背的
;   同时可以看出,不用NOINIT修饰时,STACK的数据类型为Data,是一种RW Type,否则是一种ZI Type
;
;部分细节看参见Linker User Guide: Type 2 image, one load region and non-contiguous execution regions
    
                PRESERVE8
                ;通知链接器(linker)当前文件是以堆栈8字节对齐,使用PRESERVE8的话,说明我们现在的文件堆栈是以8字节对齐的
                ;这样的话,这里的函数可以调用由REQUIRE8指示的文件的函数,而不引起错误,如LDRD and STRD指令,因为
                ;LDRD and STRD instructions (double-word transfers) only work correctly if the address they access 
                ;is 8-byte aligned.
                THUMB
                ;通知编译器采用THUMB指令集


; Vector Table Mapped to Address 0 at Reset

                AREA    RESET, DATA, READONLY
                ;指示当前节为RESET,节的属性为DATA(Contains data, not instructions),RO
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size
                ;全局变量__Vectors,__Vectors_End,和__Vectors_Size
;分散加载文件SCT为
;   LR_IROM1 0x00000000 0x00008000  {       ; load region size_region
;       ER_IROM1 0x00000000 0x00008000  {   ; load address = execution address
;           *.o (RESET, +First)             ; +First指示执行时RESET节置于最开始
;           *(InRoot$Sections)             ; InRoot$Sections指代所有必须放在根区域的节
;                                           ; 如__main.o, __scatter*.o,
;                                           ;  __dc*.o, and * Region$Table
;           .ANY (+RO)                      ; Read only的数据执行时在这里
;       }
;       RW_IRAM1 0x1FFFFC00 0x00000400  {   ; RW data
;           .ANY (+RW +ZI)
;       }
;       RW_IRAM2 0x20000000 0x00000C00  {
;           .ANY (+RW +ZI)
;       }
;   }
;我们可以这样更改分散加载文件为
;   LR_IROM1 0x00000000 0x00008000  {    ; load region size_region
;       ER_IROM1 0x00000000 0x00008000  {  ; load address = execution address
;           *.o (RESET, +First)
;           *(InRoot$Sections)
;           .ANY (+RO)
;       }
;       RW_IRAM1 0x1FFFFC00 0x00000400  {  ; RW data
;           .ANY (+ZI)
;       }
;       RW_IRAM2 0x20000000 0x00000C00  {
;           .ANY (+RW)
;           *.o (.bss)
;       }
;   }
;这样,执行时候的内存镜像变成这样子了,我们利用起来了两块RAM区的特点
;    Execution Region RW_IRAM1 (Base: 0x1ffffc00, Size: 0x00000200, Max: 0x00000400, ABSOLUTE)
;
;    Base Addr    Size         Type   Attr      Idx    E Section Name        Object
;
;    0x1ffffc00   0x00000100   Zero   RW           48    HEAP                startup_mkl02z4.o
;    0x1ffffd00   0x00000100   Zero   RW           47    STACK               startup_mkl02z4.o
;
;
;    Execution Region RW_IRAM2 (Base: 0x20000000, Size: 0x00000068, Max: 0x00000c00, ABSOLUTE)
;
;    Base Addr    Size         Type   Attr      Idx    E Section Name        Object
;
;    0x20000000   0x00000004   Data   RW            4    .data               system_mkl02z4.o
;    0x20000004   0x00000004   Data   RW           61    .data               blinky.o
;    0x20000008   0x00000060   Zero   RW          139    .bss                c_p.l(libspace.o)

__Vectors       DCD     __initial_sp        ; Top of Stack
                                            ; DCD 申请4字节的空间,存放数据
                                            ; 由于分散加载文件SCT中的*.o (RESET, +First)属性
                                            ; RESET节被放在了LR_IROM1的开始位置,即__initial_sp存放在0地址
                DCD     Reset_Handler       ; Reset Handler
                DCD     NMI_Handler         ; NMI Handler
                DCD     HardFault_Handler   ; Hard Fault Handler
                DCD     0  ; Reserved
                DCD     0  ; Reserved
                DCD     0  ; Reserved
                DCD     0  ; Reserved
                DCD     0  ; Reserved
                DCD     0  ; Reserved
                DCD     0  ; Reserved
                DCD     SVC_Handler         ; SVCall Handler
                DCD     0  ; Reserved
                DCD     0  ; Reserved
                DCD     PendSV_Handler      ; PendSV Handler
                DCD     SysTick_Handler     ; SysTick Handler

                ; External Interrupts
                DCD     Reserved16_IRQHandler  ; Reserved interrupt 16
                DCD     Reserved17_IRQHandler  ; Reserved interrupt 17
                DCD     Reserved18_IRQHandler  ; Reserved interrupt 18
                DCD     Reserved19_IRQHandler  ; Reserved interrupt 19
                DCD     Reserved20_IRQHandler  ; Reserved interrupt 20
                DCD     FTFA_IRQHandler     ; FTFA command complete/read collision interrupt
                DCD     LVD_LVW_IRQHandler  ; Low Voltage Detect, Low Voltage Warning
                DCD     Reserved23_IRQHandler  ; Reserved interrupt 23
                DCD     I2C0_IRQHandler  ; I2C0 interrupt
                DCD     I2C1_IRQHandler  ; I2C1 interrupt
                DCD     SPI0_IRQHandler  ; SPI0 interrupt
                DCD     Reserved27_IRQHandler  ; Reserved interrupt 27
                DCD     UART0_IRQHandler  ; UART0 status/error interrupt
                DCD     Reserved29_IRQHandler  ; Reserved interrupt 29
                DCD     Reserved30_IRQHandler  ; Reserved interrupt 30
                DCD     ADC0_IRQHandler  ; ADC0 interrupt
                DCD     CMP0_IRQHandler  ; CMP0 interrupt
                DCD     TPM0_IRQHandler  ; TPM0 fault, overflow and channels interrupt
                DCD     TPM1_IRQHandler  ; TPM1 fault, overflow and channels interrupt
                DCD     Reserved35_IRQHandler  ; Reserved interrupt 35
                DCD     Reserved36_IRQHandler  ; Reserved interrupt 36
                DCD     Reserved37_IRQHandler  ; Reserved interrupt 37
                DCD     Reserved38_IRQHandler  ; Reserved interrupt 38
                DCD     Reserved39_IRQHandler  ; Reserved interrupt 39
                DCD     Reserved40_IRQHandler  ; Reserved interrupt 40
                DCD     Reserved41_IRQHandler  ; Reserved interrupt 41
                DCD     Reserved42_IRQHandler  ; Reserved interrupt 42
                DCD     MCG_IRQHandler  ; MCG interrupt
                DCD     LPTimer_IRQHandler  ; LPTimer interrupt
                DCD     Reserved45_IRQHandler  ; Reserved interrupt 45
                DCD     PORTA_IRQHandler  ; Port A interrupt
                DCD     PORTB_IRQHandler  ; Port B interrupt
__Vectors_End
                ;这里__Vectors_End的值为0x000000c0 (在MAP文件里查看)

__Vectors_Size         EQU     __Vectors_End - __Vectors   ;计算中断向量表的大小

; 以下为Freescale特有的配置方式(我的理解,在ST中不是采用的这种配置方法)
; Flash配置区域在Flash的0x0000_0400开始的空间,一共16字节
; 关于Flash配置区域在帖子 http://www.amobbs.com/thread-5588189-1-1.html 中有描述
; 以下定义的变量值,在下面有采用,这边略过Flash配置字的含义,详见Reference Mannual
;
;
; <h> Flash Configuration
;   <i> 16-byte flash configuration field that stores default protection settings (loaded on reset)
;   <i> and security information that allows the MCU to restrict acces to the FTFL module.
;   <h> Backdoor Comparison Key
;     <o0>  Backdoor Key 0  <0x0-0xFF:2>
;     <o1>  Backdoor Key 1  <0x0-0xFF:2>
;     <o2>  Backdoor Key 2  <0x0-0xFF:2>
;     <o3>  Backdoor Key 3  <0x0-0xFF:2>
;     <o4>  Backdoor Key 4  <0x0-0xFF:2>
;     <o5>  Backdoor Key 5  <0x0-0xFF:2>
;     <o6>  Backdoor Key 6  <0x0-0xFF:2>
;     <o7>  Backdoor Key 7  <0x0-0xFF:2>
BackDoorK0      EQU     0xFF
BackDoorK1      EQU     0xFF
BackDoorK2      EQU     0xFF
BackDoorK3      EQU     0xFF
BackDoorK4      EQU     0xFF
BackDoorK5      EQU     0xFF
BackDoorK6      EQU     0xFF
BackDoorK7      EQU     0xFF
;   </h>
;   <h> Program flash protection bytes (FPROT)
;     <i> Each program flash region can be protected from program and erase operation by setting the associated PROT bit.
;     <i> Each bit protects a 1/32 region of the program flash memory.
;     <h> FPROT0
;       <i> Program flash protection bytes
;       <i> 1/32 - 8/32 region
;       <o.0>   FPROT0.0
;       <o.1>   FPROT0.1
;       <o.2>   FPROT0.2
;       <o.3>   FPROT0.3
;       <o.4>   FPROT0.4
;       <o.5>   FPROT0.5
;       <o.6>   FPROT0.6
;       <o.7>   FPROT0.7
nFPROT0         EQU     0x00
FPROT0          EQU     nFPROT0:EOR:0xFF
;     </h>
;     <h> FPROT1
;       <i> Program Flash Region Protect Register 1
;       <i> 9/32 - 16/32 region
;       <o.0>   FPROT1.0
;       <o.1>   FPROT1.1
;       <o.2>   FPROT1.2
;       <o.3>   FPROT1.3
;       <o.4>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值