搜档网
当前位置:搜档网 › Cortex-M0(NXP LPC11C14)启动代码分析

Cortex-M0(NXP LPC11C14)启动代码分析

Cortex-M0(NXP LPC11C14)启动代码分析
Cortex-M0(NXP LPC11C14)启动代码分析

启动代码的一般作用

1、堆和栈的初始化;

2、向量表定义;

3、地址重映射及中断向量表的转移;

4、初始化有特殊要求的断口;

5、处理器模式;

6、进入C应用程序。

ARM复位后程序从0x00地址开始执行代码,所以一般都会有将Flash地址映射到0x00的过程。但对于这一款Cortex M0的启动代码比较简单,从存储分布图中我们可以看到LPC11C14拥有32K的片内Flash,地址范围是0x0000 0000 ~ 0x0000 8000,当我们将程序(小于32K)烧写进片内Flash时,启动代码中就可以不用再对Flash的地址重新映射。

NXP LPC11C14存储分布图主要看Flash

CortexM0的启动代码进行分析:

一、堆栈初始化部分

在程序开始处,首先定义栈的大小及属性,然后对堆进行初始化操作,ARM-Thumb过程调用标准和ARM、Thumb C/C++ 编译器总是使用满减(Full descending)类型堆栈。

; Stack Configuration

; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>

; Stack Configuration

; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>

;

Stack_Size EQU 0x00000020 //定义堆栈大小

AREA STACK, NOINIT, READWRITE, ALIGN=3 //定义一个数据段按8个字节对齐AREA伪指令用于定义一//个代码段或者数据段

//NOINIT定义此数据段仅仅保留了内存单元,而没有将各初

//始值写入内存单元,或者将各个内存单元值初始化为0

Stack_Mem SPACE Stack_Size //保留Stack_Size 大小的堆栈空间,来分配连续Stack_Size //节的存储单元并初始化为0

__initial_sp //标号--堆栈顶部地址。M0中堆栈式满递减堆栈,堆栈指针位//于堆栈的高地址Stack_Size EQU 0x00000020 //定义堆栈大小

; Heap Configuration

; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>

;

Heap_Size EQU 0x00000000 // 定义堆空间大小

AREA HEAP, NOINIT, READWRITE, ALIGN=3 // 定义了一个数据段,8字节对齐

__heap_base // 标号--代表为堆末底部地址

Heap_Mem SPACE Heap_Size // 保留Heap_Size的堆空间

__heap_limit // 标号--堆的界限地址

PRESERVE8 // 指令指定当前文件保持堆栈8字节对齐。它设置PRES8编译属性,以

//通知链接器。链接器检查要求堆栈8字节对齐的任何代码是否仅由保持//堆栈8字节对齐的代码直接或者间接地调用。

THUMB//指示编译器以后的伪指令为Thum指令

二、中断量表定义

在MDK生成分散加载文件中,RESET被设置在flash的0地址处,这样就规定了向量表的地址。

; Vector Table Mapped to Address 0 at Reset

AREA RESET, DATA, READONLY //定义只读数据段,位于0地址,其实放在CODE区

//EXPORT在程序中声明一个全局的标号__Vetors号可

//可以在其他文件中使用

/*

DCD伪指令用于分配一片连续的字存储单元并用伪指令中指定的表达式初始化。其中,表达式可以为程序标号或数字表达式。DCD也可用“&”代替。

*/

__Vectors DCD __initial_sp ; Top of Stack // 给__initial_sp分配4字节32位的地址

DCD Reset_Handler ; Reset Handler//给标号Reset_Handler分配地址

DCD NMI_Handler ; 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 WAKEUP_IRQHandler ; 15 wakeup sources for all the

DCD WAKEUP_IRQHandler ; I/O pins starting from PIO0 (0:11) DCD WAKEUP_IRQHandler ; all 40 are routed to the same ISR DCD WAKEUP_IRQHandler

DCD WAKEUP_IRQHandler

DCD WAKEUP_IRQHandler

DCD WAKEUP_IRQHandler

DCD WAKEUP_IRQHandler

DCD WAKEUP_IRQHandler

DCD WAKEUP_IRQHandler

DCD WAKEUP_IRQHandler

DCD WAKEUP_IRQHandler

DCD WAKEUP_IRQHandler ; PIO1 (0:11)

DCD CAN_IRQHandler ; CAN

DCD SSP1_IRQHandler ; SSP1

DCD I2C_IRQHandler ; I2C

DCD TIMER16_0_IRQHandler ; 16-bit Timer0

DCD TIMER16_1_IRQHandler ; 16-bit Timer1

DCD TIMER32_0_IRQHandler ; 32-bit Timer0

DCD TIMER32_1_IRQHandler ; 32-bit Timer1

DCD SSP0_IRQHandler ; SSP0

DCD UART_IRQHandler ; UART

DCD USB_IRQHandler ; USB IRQ

DCD USB_FIQHandler ; USB FIQ

DCD ADC_IRQHandler ; A/D Converter

DCD WDT_IRQHandler ; Watchdog timer

DCD BOD_IRQHandler ; Brown Out Detect

DCD FMC_IRQHandler ; IP2111 Flash Memory Controller

DCD PIOINT3_IRQHandler ; PIO INT3

DCD PIOINT2_IRQHandler ; PIO INT2

DCD PIOINT1_IRQHandler ; PIO INT1

DCD PIOINT0_IRQHandler ; PIO INT0

IF :LNOT::DEF:NO_CRP //进行宏定义判断

AREA |.ARM.__at_0x02FC|, CODE, READONLY

/*************************************************************************************************************** *************************************************

这有几个关键的地方“NO_CRP”、0x02FC和0xFFFFFFFF,如果我们在前面定义有“NO_CRP”,那么我们后面的代码也就不起作用了,所以在需要加密的时候前面就一定不能再定义了代码读保护,也就是加密的关键字,经过加密后芯片再也无法擦除,除非之前烧写的程序带有IAP,IAP可以使芯片进入ISP 模式。

**************************************************************************************************************** ************************************************/

CRP_Key DCD0xFFFFFFFF // 加密等级

ENDIF

AREA |.text|, CODE, READONLY //代码段定义

利用PROC,ENDP这一对伪指令把程序段分为若干个过程,是程序的结构更加清晰

; Reset Handler

Reset_Handler PROC//过程的开始

EXPORT Reset_Handler [WEAK] //[WEAK]弱定义,意思是如果在别处也定义该标

//(函数),在连接时,用别处的地址。如果没有

//他地方定义,编译器也不报错,以此处地址进行链接

IMPORT __main // 通知编译要使用标号在其他文件

LDR R0, =__main //使用“=”表示LDR目前是伪指令,不是标准指令。把__main

//地址赋给R0。

BX R0//BX是ARM指令集和THUMB指令集之间程序的跳转

ENDP//过程结束

; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler PROC

EXPORT NMI_Handler [WEAK]

B .//原地跳转(即无限循环)

ENDP

HardFault_Handler\

PROC

EXPORT HardFault_Handler [WEAK]

B .

ENDP

MemManage_Handler\

PROC

EXPORT MemManage_Handler [WEAK]

B .

ENDP

BusFault_Handler\

PROC

EXPORT BusFault_Handler [WEAK]

B .

ENDP

UsageFault_Handler\

PROC

EXPORT UsageFault_Handler [WEAK]

B .

ENDP

SVC_Handler PROC

EXPORT SVC_Handler [WEAK]

B .

ENDP

DebugMon_Handler\

PROC

EXPORT DebugMon_Handler [WEAK]

B .

ENDP

PendSV_Handler PROC

EXPORT PendSV_Handler [WEAK]

B .

ENDP

SysTick_Handler PROC

EXPORT SysTick_Handler [WEAK]

B .

ENDP

Default_Handler PROC

EXPORT WAKEUP_IRQHandler [WEAK]

EXPORT CAN_IRQHandler [WEAK]

EXPORT SSP1_IRQHandler [WEAK]

EXPORT I2C_IRQHandler [WEAK]

EXPORT TIMER16_0_IRQHandler [WEAK]

EXPORT TIMER16_1_IRQHandler [WEAK]

EXPORT TIMER32_0_IRQHandler [WEAK]

EXPORT TIMER32_1_IRQHandler [WEAK]

EXPORT SSP0_IRQHandler [WEAK]

EXPORT UART_IRQHandler [WEAK]

EXPORT USB_IRQHandler [WEAK]

EXPORT USB_FIQHandler [WEAK]

EXPORT ADC_IRQHandler [WEAK]

EXPORT WDT_IRQHandler [WEAK]

EXPORT BOD_IRQHandler [WEAK]

EXPORT FMC_IRQHandler [WEAK]

EXPORT PIOINT3_IRQHandler [WEAK]

EXPORT PIOINT2_IRQHandler [WEAK]

EXPORT PIOINT1_IRQHandler [WEAK]

EXPORT PIOINT0_IRQHandler [WEAK]

WAKEUP_IRQHandler

CAN_IRQHandler

SSP1_IRQHandler

I2C_IRQHandler

TIMER16_0_IRQHandler

TIMER16_1_IRQHandler

TIMER32_0_IRQHandler

TIMER32_1_IRQHandler

SSP0_IRQHandler

UART_IRQHandler

USB_IRQHandler

USB_FIQHandler

ADC_IRQHandler

WDT_IRQHandler

BOD_IRQHandler

FMC_IRQHandler

PIOINT3_IRQHandler

PIOINT2_IRQHandler

PIOINT1_IRQHandler

PIOINT0_IRQHandler

B .

ENDP

ALIGN填充字节使地址对齐

; User Initial Stack & Heap

三、堆和栈的初始化

IF :DEF:__MICROLIB// “DEF”的用法:DEF:xx就是说xx定义了则为真,否则为假

EXPORT __initial_sp//则将栈顶定制

EXPORT __heap_base// 堆起始地址赋予全局属性

EXPORT __heap_limit //堆末端界限地址赋予全局属性,使外部程序可调用

ELSE//如果没有定义__MICROLIB,则使用默认的C运行时库

IMPORT __use_two_region_memory// 通知编译器要使用的标号在其他文件

//__use_two_region_memory

EXPORT __user_initial_stackheap// 声明全局标号__user_initial_stackheap,这样外程序也可调用此标号

//则进行堆栈和堆的赋值,在__main函数执行过程中调用

//如果了使用默认的C库,程序启动过程中不会执行标号下//的代码

/*************************************************************************************************************** ***********************************************

_user_initial_stackheap() 返回:

· r0 中的堆基址

· r1 中的堆栈基址,即堆栈区中的最高地址

· r2 中的堆限制

· r3 中的堆栈限制,即堆栈区中的最低地址。

有单区模型和双区模型。

单区模型:(r0,r1)是单个堆栈和堆区。r1 大于r0,并忽略r2和r3。

r0--r1这一块内存区域被堆和栈共用,堆从r0向上生长,栈从r1向下生长。

双区模型:(r0, r2)是初始堆,(r3, r1) 是初始堆栈。r2 大于或等于r0,r3小于r1。

堆和栈分别指定了单独的内存区域。

**************************************************************************************************************** **********************************************/

__user_initial_stackheap// 标号__user_initial_stackheap,表示拥护堆栈初始化程序入口

//则进行堆栈和堆得赋值,在__main函数执行过程中调用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

相关主题