M0启动代码详解全

;/*---------------------------------------------------------------------------------------------------------*/
;/* */
;/* Copyright(c) 2009 Nuvoton Technology Corp. All rights reserved. */
;/* 优尔顺电子 整理:马万宏 */
;/*---------------------------------------------------------------------------------------------------------*/
; 启动代码作用一般是:1)堆和栈的初始化;2)向量表定义;3)地址重映射及中断向量表的转移;
; 4)设置系统时钟频率;5)中断寄存器的初始化;6)进入C应用程序。
Stack_Size EQU 0x00000400 ; 定义Stack_Size为0x00000400

AREA STACK, NOINIT, READWRITE, ALIGN=3 ;定义栈,可初始为0,8字节对齐
Stack_Mem SPACE Stack_Size ;分配0x200个连续字节,并初始化为0

__initial_sp ;汇编代码地址标号


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


Heap_Size EQU 0x00000000 ;定义Heap_Size为0x00000000

AREA HEAP, NOINIT, READWRITE, ALIGN=3 ;定义堆,可初始为0,8字节对齐
__heap_base
Heap_Mem SPACE Heap_Size ;分配0x00个连续字节,并初始化为0
__heap_limit


PRESERVE8 ; 指定当前文件堆栈8字节对齐
THUMB ; 告诉汇编器下面是32为的Thumb指令,如果需要汇编器将插入位以保证对齐


; Vector Table Mapped to Address 0 at Reset
;以下中断向量表定义
AREA RESET, DATA, READONLY ;定义复位向量段,只读
EXPORT __Vectors ; 定义一个可以在其他文件中使用的全局标号。此处表示中断地址

__Vectors DCD __initial_sp ; Top of Stack 给__initial_sp分配4字节32位的地址0x0
DCD Reset_Handler ; Reset Handler 给标号Reset Handler分配地址为0x00000004
DCD NMI_Handler ; NMI Handler 给标号NMI Handler分配地址0x00000008
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
; maximum of 32 External Interrupts are possible
DCD BOD_IRQHandler
DCD WDT_IRQHandler
DCD EINT0_IRQHandler
DCD EINT1_IRQHandler
DCD GPIOP0P1_IRQHandler
DCD GPIOP2P3P4_IRQHandler
DCD PWMA_IRQHandler
DCD PWMB_IRQHandler
DCD TMR0_IRQHandler
DCD TMR1_IRQHandler
DCD TMR2_IRQHandler
DCD TMR3_IRQHandler
DCD UART0_IRQHandler
DCD UART1_IRQHandler
DCD SPI0_IRQHandler
DCD SPI1_IRQHandler
DCD Default_Handler
DCD Default_Handler
DCD I2C_IRQHandler
DCD Default_Handler
DCD Default_Handler
DCD Default_Handler
DCD Default_Handler
DCD Default_Handler
DCD Default_Handler
DCD Default_Handler
DCD Default_Handler
DCD Default_Handler
DCD PWRWU_IRQHandler
DCD ADC_IRQHandler
DCD Default_Handler
DCD Default_Handler

; 中断向量表的转移

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


; Reset Handler

;ENTRY

Reset_Handler PROC ; 标记一个函数的开始 (这里是复位子程序从0x04开始

EXPORT Reset_Handler [WEAK] ;将Reset_Handler设为外部可引用的标号
; [WEAK] 选项表示当所有的源文件都没有 定义这样一个标号时,
;编译器也不给出错误信息,在多数情况下将该标号置为 0 ,
;若该标号为 B 或 BL 指令引用,则将 B 或 BL指令置为 NOP 操作。
;EXPORT提示编译器该标号可以为外部文件引用。



;IMPORT SystemInit [WEAK] ;在自建工程时一般会出现这一行 ,并在复位子程序结束处跳到MAIN前
;会先跳到这个初始化程序,如果你的主程序里没有这一初始化程序
;而是在MAIN中初

始化,将会导致编译器因找不到这一程序而报错
;解决的办法是注解这一行,或加上 [WEAK]
;当然后面跳到MAIN之前进初始化函数必须注解掉




IMPORT __main ; 通知编译器要main在其他的源文件中定义,但要在当前源文件中引用

LDR R0, =0x50000100 ;送立即数到R0 这个是寄存器写保护寄存器 (复位为锁定bit0为0)
LDR R1, [R0, #0x10] ;将0x50000110(rc校验寄存器)处的值送到R1
CMP R1, #0x3F ;比较0x50000110处的值与0x3f (默认的中心频率应该是0x20)
BNE %F0 ; 如果不相等向前搜索标号为0的行,(以此实现循环,具体可看局部标号的知识)
;如果相等就解锁 寄存器写保护寄存器 并 将 rc校验寄存器 设为中心值0x20
LDR R1, =0x59
STR R1, [R0]
LDR R1, =0x16
STR R1, [R0]
LDR R1, =0x88
STR R1, [R0] ; 向0x50000100写入0x59 0x16 0x88 解锁寄存器写保护寄存器(bit0为1)

LDR R1, =0x20 ;加载0x20到R1
STR R1, [R0, #0x10] ;将R1(0x20默认中心频率)送到0x50000110(rc校验寄存器)
MOVS R1, #0 ;将0送到R1
STR R1, [R0] ;将0写入0x50000100重锁保护寄存器
0 ;标号

;LDR R0, =SystemInit
;BLX R0 ;这就是前面说的进初始化函数,如果你主程序里没有,必须注解掉。



LDR R0, =__main ; 使用“=”表示LDR目前是伪指令不是标准指令。这里是把__main的地址给RO。

BX R0 ; BX是ARM指令集和THUMB指令集之间程序的跳转
; 也就是跳到MAIN处
ENDP ; 复位子程序结束


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

NMI_Handler PROC ; 函数的开始
EXPORT NMI_Handler [WEAK] ; EXPORT NMI_Handler可外部引用 的标号
B . ; 跳到当前行
ENDP ; 函数的结束


HardFault_Handler\
PROC
; "/"是换行的意思
EXPORT HardFault_Handler [WEAK]
B .
ENDP



SVC_Handler PROC
EXPORT SVC_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 BOD_IRQHandler [WEAK]
EXPORT WDT_IRQHandler [WEAK]
EXPORT EINT0_IRQHandler [WEAK]
EXPORT EINT1_IRQHandler [WEAK]
EXPORT GPIOP0P1_IRQHandler [WEAK]
EXPORT GPIOP2P3P4_IRQHandler [WEAK]
EXPORT PWMA_IRQHandler [WEAK]
EXPORT PWMB_IRQHandler [WEAK]
EXPORT TMR0_IRQHandler [WEAK]
EXPORT TMR1_IRQHandler [WEAK]
EXPORT TMR2_IRQHandler [WEAK]
EXPORT TMR3_IRQHandler [WEAK]
EXPORT UART0_IRQHandler [WEAK]
EXPORT UART1_IRQHandler [WEAK]
EXPORT SPI0_IRQHandler [WEAK]
EXPORT SPI1_IRQHandler [WEAK]
EXPORT I2C_IRQHandler [WEAK]
EXPORT PWRWU_IRQHandler [WEAK]
EXPORT ADC_IRQHandler [WEAK]

BOD_IRQHandler
WDT_IRQHandler
EINT0_IRQHandler
EINT1_IRQHandler
GPIOP0P1_IRQHandler
GPIOP2P3P4_IRQHandler
PWMA_IRQHandler
PWMB_IRQHandler
TMR0_IRQHandler
TMR1_IRQHandler
TMR2_IRQHandler
TMR3_IRQHandler
UART0_IRQHandler
UART1_IRQHandler
SPI0_IRQHandler
SPI1_IRQHandler
I2C_IRQHandler
PWRWU_IRQHandler
ADC_IRQHandler
B .
ENDP


ALIGN


; User Initial Stack & Heap
; 堆和栈的初始化
IF :DEF:__MICROLIB ;;“DEF”的用法——:DEF:X 就是说X定义了则为真,否则为假

EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit

ELSE

IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap

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

相关文档
最新文档