目录
文章目录
- 目录
- 摘要
- 第一部分:汇编指令学习
- 1.伪指令
- 2. 汇编指令
- 第二部分:STM32启动流程学习
- 1.基础知识储备
- 2.反汇编工具
- 第三部分:STM32启动代码分析
摘要 本节主要记录字节学习STM32启动代码的过程,通过对启动代码的分析,可以更清晰的了解STM32的CPU是如何运行的;欢迎批评指针!!!
第一部分:汇编指令学习 1.伪指令 1).EQU
EQU伪指令:用来为一个数字常量、或一个和内核寄存器相关的数值或一个和程序计数器相关的数值定义的一个符号名称。类似于C语言中的#define 。
格式: nameEQUexpr{ , type}
格式:名称EQU表达式(,类型)
例如:
Stack_SizeEQU0X00000400//定义1k字节的栈空间
Heap_SizeEQU0x00000200//定义512字节的堆空间
2).AREA
AREA伪指令:用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用“|”括起来,如:|1_test| 。
格式: AREA 段名 属性1 ,属性2 ,……
属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:
— CODE 属性:用于定义代码段,默认为READONLY 。
— DATA 属性:用于定义数据段,默认为READWRITE 。
— READONLY 属性:指定本段为只读,代码段默认为READONLY 。
— READWRITE 属性:指定本段为可读可写,数据段的默认属性为READWRITE 。
— ALIGN 属性:使用方式为ALIGN表达式。在默认时,ELF(可执行连接文件)的代码段和数据段是按字对齐的,表达式的取值范围为0~31,相应的对齐方式为2表达式次方。
— COMMON 属性:该属性定义一个通用的段,不包含任何的用户代码和数据。各源文件中同名的COMMON段共享同一段存储单元。
例如1:
AREA HEAP, NOINIT, READWRITE, ALIGN=3
其中:
HEAP: 定义一个堆段,名字 HEAP
NOINIT: 只分配空间不初始化零
READWRITE:可以读写
ALIGN=3 : 8字节对齐
例如2:
AREA STACK, NOINIT, READWRITE, ALIGN=3
定义一个栈段,名字是STACK,不初始化为0,可以读写,8字节对齐
例如3:
AREA RESET, DATA, READONLY
定义一个数据段,名字是RESET,只可读;这里面的DATA属性表示RESET是一个数据段
例如4:
AREA |.text|, CODE, READONLY
定义一个代码段,名字是 |.text|,只可读;这里面的CODE属性表示|.text|是一个代码段
3). SPACE
SPACE伪指令:用于分配一片连续的存储单元并初始化为0,其中表达式为要分配的字节数
格式:标号 SPACE 表达式
例如1:
Stack_Mem SPACE Stack_Size
分配连续Stack_Size 字节的存储单元,存储单元的名字是Stack_Mem,这里是在内存中连续分配1k字节的栈空间
例如2:
Heap_Mem SPACE Heap_Size
分配连续Heap_Size 字节的存储单元,存储单元的名字是Heap_Mem,这里是在内存中连续分配512字节的堆空间
4). DCD(或DCDU)
DCD伪指令:用于分配一片连续的字存储单元,并用伪指令中指定的表达式初始化。其中,表达式可以为程序标号或数字表达式。 DCD 也可用 “ & ” 代替。用 DCD 分配的字存储单元是字对齐的,而用 DCDU 分配的字存储单元并不严格字对齐。
格式:标号DCD (或 DCDU )表达式
**例如1:**下面是摘自STM32f4启动代码的例子
其中:_Vectors是一个标号,该处的物理地址值即为 _Vetors 标号所表示的值,该地址中存储__initial_sp所表示的地址值。使用DCD定义了一个内存数组,数组首地址放置的是栈指针地址,然后是复位中断服务入口地址。这个表的作用的作用定义一个存放地址的数组表。
例如2:
SwiFunction
DCD TASK_SW
DCD ENTER_CRITICAL
DCD EXIT_CRITICAL
DCD ISRBegin
DCD ChangeToSYSMode
DCD ChangeToUSRMode
5). ENTRY
ENTRY伪指令用于指定汇编程序的入口点。
6).PROC/ENDP
过程就是子程序。一个程序可以被其他程序所调用(CALL),过程的最后一投指令一般反汇指令(RET),需要注意PROC和ENDP必须成对出现。
格式:
<过程名>PROC[类型]
...
...ENDP
例如1:复位中断服务函数
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDRR0, =SystemInit
BLXR0
LDRR0, =__main
BXR0
ENDP
例如2:硬件中断服务函数
HardFault_Handler PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
7).END
END伪指令:用于指示汇编语言程序段结束,因此一个源程序中仅有一个END,且一般放在程序最后。若END放在程序中间,则END后面的语句将不再被汇编。
8).LDR、STR
LDR指令:将存储器地址所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中
STR指令:将寄存器内容存入内存空间中
格式:
LDR{条件} 目的寄存器 <存储器地址>
STR{条件}源寄存器, <存储器地址>
例如1:
LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0
LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0
LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0
LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,然后R1=R1+8
LDR R0,[R1],#8 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存入
LDR R0,=DATA ;将立即数DATA 加载到寄存器R0
STR R0,[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8
STR R1, [R0] ;将R1寄存器的值,传送到地址值为R0的(存储器)内存中
例如2:
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
2. 汇编指令 1). IMPORT
表示这是一个外部变量的标号,不是在本程序定义的,表明要调用的函数为外部文件定义
2).EXPORT
表示本程序里面用到的变量提供给其他模块调用的。
3).PRESERVE8
PRESERVE8指令指定当前文件需保持堆栈八字节对齐方式。其通过设置PRES8编译属性通知连接器。
格式:
PRESERVE8{bool}
PRESERVE8;保持代码堆栈八字节对齐。
PRESERVE8 {FALSE};不保持代码堆栈八字节对齐。
4).Thumb
Thumb是ARM体系结构中一种16位的指令集。Thumb指令集可以看作是ARM指令压缩形式的子集,它是为减小代码量而提出,具有16bit的代码密度。Thumb指令体系并不完整,只支持通用功能,必要时仍需要使用ARM指令,如进入异常时。其指令的格式与使用方式与ARM指令集类似,而且使用并不频繁,Thumb指令集作一般了解。
5).跳转指令B,BL,BX,BLX
B Label ; 跳转到Label处对应的地址
BL Label ; 跳转到Label对应的地址,并且把跳转前的下条指令地址保存到LR
BX reg ; 跳转到由寄存器reg给出的地址
BLX reg ; 跳转到由寄存器reg给出的地址,并根据REG的LSB切换处理器;状态还要把转移前的下条指令地址保存到LR.
其中BX 和BLX 都会启动中断返回序列。即从SP中依次将值返回至xPSR, PC, LR, R12以及R3-R0—-其中从堆栈SP中返回PC值实现了程序跳转。 对于B和BL 则是多用于函数跳转,其中BL保存了下条指令地址到LR.
6).IF——ELSE——ENDIF
格式:
IF 判断式
执行1
ELSE
执行2
ENDIF
7).weak
一般来说,这个关键字使用在IMPORT和EXPORT这两个声明段,weak 声明其他的同名标号优先于该标号被引用。
IMPORTStackTop [WEAK] AREA |.text|, CODE, READONLY
;
Vector list
ARM_Vectors
DCDStackTop
IMORT: 如果我们有一个名为ARM_Vectors的量表,向量表的第一个数值指向一个StackTop函数的地址。因为我们可能定义了该函数,也可能没有,为了代码的简便,我们可以使用WEAK关键字。
当我们定义了StackTop函数后,那么ARM_Vectors里第一个向量值就是StackTop函数的地址。如果没有定义StackTop,那么编译器不会报错,而这时候第一个向量值就直接赋予0。
EXPORT: EXPORT的函数带有WEAK标志的话,并且别的源代码没有定义同名函数,那么连接时就是该函数;否则,就是另外的一个同名函数(类似类的继承)
第二部分:STM32启动流程学习 1.基础知识储备 每一款芯片的启动文件都值得去研究,因为它是程序跑的最初一段代码。通过了解启动文件,我们可以体会到处理器的架构、指令集、中断向 量安排等内容,是非常值得研究的。
STM32作为一款高端Cortex-M3系列单片机,有必要了解它的启动文件。打好基础,为以后优化程序,写出高质量的代码最准备。
相对于ARM上一代的主流ARM7/ARM9内核架构,新一代Cortex内核架构的启动方式有了比较大的变化。ARM7/ARM9内核的控制器在复位后,CPU会从存储空间的绝对地址0x000000取出第一条指令执行复位中断服务程序的方式启动,即固定了复位后的起始地址为0x000000(PC = 0x000000)同时中断向量表的位置并不是固定的。而Cortex-M3内核则正好相反,有3种情况:
![STM32启动代码学习](https://img.it610.com/image/info8/0a30f5a3b4a6440983e63aa762e3b2f5.jpg)
文章图片
1、 通过boot引脚设置可以将中断向量表定位于SRAM区,即起始地址为0x2000000,同时复位后PC指针位于0x2000000处;
2、 通过boot引脚设置可以将中断向量表定位于FLASH区,即起始地址为0x8000000,同时复位后PC指针位于0x8000000处;
3、 通过boot引脚设置可以将中断向量表定位于内置Bootloader区,本文不对这种情况做论述;
**
而Cortex-M3内核规定,起始地址必须存放堆顶指针,而第二个地址则必须存放复位中断入口向量地址,这样在Cortex-M3内核复位后,会自动从起始地址的下一个32位空间取出复位中断入口向量,跳转执行复位中断服务程序。对比ARM7/ARM9内核,Cortex-M3内核则是固定了中断向量表的位置而起始地址是可变化的。
STM整个启动过程是指从上电开始,一直到运行到main函数之间的这段过程,步骤为:
①上电后硬件设置SP、PC
②设置系统时钟
③软件设置SP
④加载.data、.bss,并初始化栈区
⑤跳转到C文件的main函数
启动过程涉及的文件不仅包含startup_stm32f40x_hd.s,还涉及到了MDK自带的连接库文件entry.o、entry2.o、entry5.o、entry7.o等(从生成的map文件可以看出来)。
2.反汇编工具 STM32启动代码startup_stm32f40_41xxx.s,这里以天穹飞控代码的启动进行反汇编分析。使用的反汇编工具是IDAIDA下载地址,对应的密码是a2mm,怎么使用的这里就不做讲述,可以自行查资料。界面下图所示。
![STM32启动代码学习](https://img.it610.com/image/info8/2e05babb48be4aa981e1f8709d569bef.jpg)
文章图片
**步骤:
直接点击OK,然后Go,继续File选择open,选择BlueSky.axf(这里可以随意打开电脑上的一个.exe文件,主要学会使用这个软件)**打开之后主要出现IDA View-A,Hex View-1 ,Structures ,Enums,Imports,Exports这些窗口
整体界面显示:
![STM32启动代码学习](https://img.it610.com/image/info8/25d9e25b2c3f469b8d305efdd5ee0941.jpg)
文章图片
(1)IDA View-A
![STM32启动代码学习](https://img.it610.com/image/info8/34cceb7e280c41819caebbf7ca167816.jpg)
文章图片
这个就是启动代码如何运行到main()函数的流程图
![STM32启动代码学习](https://img.it610.com/image/info8/d8210b36298f45c0b66093b752d69e64.jpg)
文章图片
也可以参考这个博客:如何到main()函数
(2)Hex View-1
![STM32启动代码学习](https://img.it610.com/image/info8/b28956e39fd64f2a9bf3d87f6d6de303.jpg)
文章图片
**(3)Structures **
![STM32启动代码学习](https://img.it610.com/image/info8/741e7f6804594b638ee1bd54a9075c58.jpg)
文章图片
(4)Enums
![STM32启动代码学习](https://img.it610.com/image/info8/c338d09409034e918af5855225c001b2.jpg)
文章图片
(5)Exports
![STM32启动代码学习](https://img.it610.com/image/info8/6f865881d5c446698fe09c90b6dda76e.jpg)
文章图片
第三部分:STM32启动代码分析
Stack_SizeEQU0x00000400;
EQU伪指令,作用是左边的符号名代表右边的表达式AREASTACK, NOINIT, READWRITE, ALIGN=3;
定义栈段:名称为STACK,未初始化,可读写,ELF 的栈段按2^3=8对齐
Stack_MemSPACEStack_Size;
分配一片连续的存储区域并初始化为 0,栈空间:0x400个字节
__initial_sp;
栈空间顶地址;
Heap Configuration;
堆定义
;
Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
Heap_SizeEQU0x00000200
AREAHEAP, NOINIT, READWRITE, ALIGN=3__heap_base;
堆空间起始地址
Heap_MemSPACEHeap_Size;
堆空间:0x200个字节
__heap_limit;
堆空间结束地址PRESERVE8;
PRESERVE8 指令指定当前文件保持堆栈八字节对齐
THUMB;
告诉汇编器下面是32位的Thumb指令,如果需要汇编器将插入位以保证对齐;
Vector Table Mapped to Address 0 at Reset;
中断向量表定义
;
实际上是在CODE区(假设STM32从FLASH启动,则此中断向量表起始地址即为0x8000000)
AREARESET, DATA, READONLY;
定义一块数据段,只可读,段名字是RESET
EXPORT__Vectors;
EXPORT:在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用
EXPORT__Vectors_End;
在程序中声明一个全局的标号__Vectors_End
EXPORT__Vectors_Size;
在程序中声明一个全局的标号__Vectors_Size;
DCD(DCDU)用于分配一片连续的字存储单元并用指定的数据初始化。
__VectorsDCD__initial_sp;
Top of Stack;
该处物理地址值存储__initial_sp所表示的地址值,即为 __Vetors 标号所表示的值
DCDReset_Handler;
Reset Handler
DCDNMI_Handler;
NMI Handler
DCDHardFault_Handler;
Hard Fault Handler
DCDMemManage_Handler;
MPU Fault Handler
DCDBusFault_Handler;
Bus Fault Handler
DCDUsageFault_Handler;
Usage Fault Handler
DCD0;
Reserved
DCD0;
Reserved
DCD0;
Reserved
DCD0;
Reserved
DCDSVC_Handler;
SVCall Handler
DCDDebugMon_Handler;
Debug Monitor Handler
DCD0;
Reserved
DCDPendSV_Handler;
PendSV Handler
DCDSysTick_Handler;
SysTick Handler;
External Interrupts;
以下为外部中断向量表
DCDWWDG_IRQHandler;
Window Watchdog
DCDPVD_IRQHandler;
PVD through EXTI Line detect
DCDTAMPER_IRQHandler;
Tamper
DCDRTC_IRQHandler;
RTC
DCDFLASH_IRQHandler;
Flash
DCDRCC_IRQHandler;
RCC
DCDEXTI0_IRQHandler;
EXTI Line 0
DCDEXTI1_IRQHandler;
EXTI Line 1
DCDEXTI2_IRQHandler;
EXTI Line 2
DCDEXTI3_IRQHandler;
EXTI Line 3
DCDEXTI4_IRQHandler;
EXTI Line 4
DCDDMA1_Channel1_IRQHandler;
DMA1 Channel 1
DCDDMA1_Channel2_IRQHandler;
DMA1 Channel 2
DCDDMA1_Channel3_IRQHandler;
DMA1 Channel 3
DCDDMA1_Channel4_IRQHandler;
DMA1 Channel 4
DCDDMA1_Channel5_IRQHandler;
DMA1 Channel 5
DCDDMA1_Channel6_IRQHandler;
DMA1 Channel 6
DCDDMA1_Channel7_IRQHandler;
DMA1 Channel 7
DCDADC1_2_IRQHandler;
ADC1 & ADC2
DCDUSB_HP_CAN1_TX_IRQHandler;
USB High Priority or CAN1 TX
DCDUSB_LP_CAN1_RX0_IRQHandler ;
USB LowPriority or CAN1 RX0
DCDCAN1_RX1_IRQHandler;
CAN1 RX1
DCDCAN1_SCE_IRQHandler;
CAN1 SCE
DCDEXTI9_5_IRQHandler;
EXTI Line 9..5
DCDTIM1_BRK_IRQHandler;
TIM1 Break
DCDTIM1_UP_IRQHandler;
TIM1 Update
DCDTIM1_TRG_COM_IRQHandler;
TIM1 Trigger and Commutation
DCDTIM1_CC_IRQHandler;
TIM1 Capture Compare
DCDTIM2_IRQHandler;
TIM2
DCDTIM3_IRQHandler;
TIM3
DCDTIM4_IRQHandler;
TIM4
DCDI2C1_EV_IRQHandler;
I2C1 Event
DCDI2C1_ER_IRQHandler;
I2C1 Error
DCDI2C2_EV_IRQHandler;
I2C2 Event
DCDI2C2_ER_IRQHandler;
I2C2 Error
DCDSPI1_IRQHandler;
SPI1
DCDSPI2_IRQHandler;
SPI2
DCDUSART1_IRQHandler;
USART1
DCDUSART2_IRQHandler;
USART2
DCDUSART3_IRQHandler;
USART3
DCDEXTI15_10_IRQHandler;
EXTI Line 15..10
DCDRTCAlarm_IRQHandler;
RTC Alarm through EXTI Line
DCDUSBWakeUp_IRQHandler;
USB Wakeup from suspend
DCDTIM8_BRK_IRQHandler;
TIM8 Break
DCDTIM8_UP_IRQHandler;
TIM8 Update
DCDTIM8_TRG_COM_IRQHandler;
TIM8 Trigger and Commutation
DCDTIM8_CC_IRQHandler;
TIM8 Capture Compare
DCDADC3_IRQHandler;
ADC3
DCDFSMC_IRQHandler;
FSMC
DCDSDIO_IRQHandler;
SDIO
DCDTIM5_IRQHandler;
TIM5
DCDSPI3_IRQHandler;
SPI3
DCDUART4_IRQHandler;
UART4
DCDUART5_IRQHandler;
UART5
DCDTIM6_IRQHandler;
TIM6
DCDTIM7_IRQHandler;
TIM7
DCDDMA2_Channel1_IRQHandler;
DMA2 Channel1
DCDDMA2_Channel2_IRQHandler;
DMA2 Channel2
DCDDMA2_Channel3_IRQHandler;
DMA2 Channel3
DCDDMA2_Channel4_5_IRQHandler ;
DMA2 Channel4 & Channel5
__Vectors_End;
Vectors结束__Vectors_SizeEQU__Vectors_End - __Vectors;
得到向量表的大小,304个字节也就是0x130个字节AREA|.text|, CODE, READONLY;
定义一个代码段,可读,段名字是.text
;
|.text|用于表示由 C 编译程序产生的代码段,或用于以某种方式与 C 库关联的代码段
;
Reset handler;
利用PROC、ENDP这一对伪指令标记程序开始、结束,把程序段分为若干个过程,使程序的结构加清晰
Reset_HandlerPROC
EXPORTReset_Handler[WEAK];
WEAK声明其他的同名标号优先于该标号被引用,就是说如果外面声明了的话,调用外面的对应函数
IMPORT__main;
IMPORT:伪指令用于通知编译器要使用的标号在其他的源文件中定义
IMPORTSystemInit
LDRR0, =SystemInit;
系统初始化
BLXR0;
带链接的跳转,切换指令集,跳到SystemInit
LDRR0, =__main;
__main为运行时库提供的函数;完成堆栈,堆的初始化等工作,会调用下面定义的__user_initial_stackheap
BXR0;
切换指令集,main函数不返回跳到__main,进入C的世界
ENDP;
Dummy Exception Handlers (infinite loops which can be modified)NMI_HandlerPROC
EXPORTNMI_Handler[WEAK];
不可屏蔽中断处理函数
B.
ENDP
HardFault_Handler\;
\意为换行
PROC
EXPORTHardFault_Handler[WEAK];
硬件错误处理函数
B.
ENDP
MemManage_Handler\
PROC
EXPORTMemManage_Handler[WEAK]
B.
ENDP
BusFault_Handler\
PROC
EXPORTBusFault_Handler[WEAK]
B.
ENDP
UsageFault_Handler\
PROC
EXPORTUsageFault_Handler[WEAK]
B.
ENDP
SVC_HandlerPROC
EXPORTSVC_Handler[WEAK]
B.
ENDP
DebugMon_Handler\
PROC
EXPORTDebugMon_Handler[WEAK]
B.
ENDP
PendSV_HandlerPROC
EXPORTPendSV_Handler[WEAK]
B.
ENDP
SysTick_Handler PROC
EXPORTSysTick_Handler[WEAK]
B.
ENDPDefault_Handler PROC
;
输出异常向量表标号,方便外部实现异常的具体功能,[WEAK]是弱定义的意思,如果外部定义了,优先执行外部定义,否则下面的函数定义
EXPORTWWDG_IRQHandler[WEAK]
EXPORTPVD_IRQHandler[WEAK]
EXPORTTAMPER_IRQHandler[WEAK]
EXPORTRTC_IRQHandler[WEAK]
EXPORTFLASH_IRQHandler[WEAK]
EXPORTRCC_IRQHandler[WEAK]
EXPORTEXTI0_IRQHandler[WEAK]
EXPORTEXTI1_IRQHandler[WEAK]
EXPORTEXTI2_IRQHandler[WEAK]
EXPORTEXTI3_IRQHandler[WEAK]
EXPORTEXTI4_IRQHandler[WEAK]
EXPORTDMA1_Channel1_IRQHandler[WEAK]
EXPORTDMA1_Channel2_IRQHandler[WEAK]
EXPORTDMA1_Channel3_IRQHandler[WEAK]
EXPORTDMA1_Channel4_IRQHandler[WEAK]
EXPORTDMA1_Channel5_IRQHandler[WEAK]
EXPORTDMA1_Channel6_IRQHandler[WEAK]
EXPORTDMA1_Channel7_IRQHandler[WEAK]
EXPORTADC1_2_IRQHandler[WEAK]
EXPORTUSB_HP_CAN1_TX_IRQHandler[WEAK]
EXPORTUSB_LP_CAN1_RX0_IRQHandler [WEAK]
EXPORTCAN1_RX1_IRQHandler[WEAK]
EXPORTCAN1_SCE_IRQHandler[WEAK]
EXPORTEXTI9_5_IRQHandler[WEAK]
EXPORTTIM1_BRK_IRQHandler[WEAK]
EXPORTTIM1_UP_IRQHandler[WEAK]
EXPORTTIM1_TRG_COM_IRQHandler[WEAK]
EXPORTTIM1_CC_IRQHandler[WEAK]
EXPORTTIM2_IRQHandler[WEAK]
EXPORTTIM3_IRQHandler[WEAK]
EXPORTTIM4_IRQHandler[WEAK]
EXPORTI2C1_EV_IRQHandler[WEAK]
EXPORTI2C1_ER_IRQHandler[WEAK]
EXPORTI2C2_EV_IRQHandler[WEAK]
EXPORTI2C2_ER_IRQHandler[WEAK]
EXPORTSPI1_IRQHandler[WEAK]
EXPORTSPI2_IRQHandler[WEAK]
EXPORTUSART1_IRQHandler[WEAK]
EXPORTUSART2_IRQHandler[WEAK]
EXPORTUSART3_IRQHandler[WEAK]
EXPORTEXTI15_10_IRQHandler[WEAK]
EXPORTRTCAlarm_IRQHandler[WEAK]
EXPORTUSBWakeUp_IRQHandler[WEAK]
EXPORTTIM8_BRK_IRQHandler[WEAK]
EXPORTTIM8_UP_IRQHandler[WEAK]
EXPORTTIM8_TRG_COM_IRQHandler[WEAK]
EXPORTTIM8_CC_IRQHandler[WEAK]
EXPORTADC3_IRQHandler[WEAK]
EXPORTFSMC_IRQHandler[WEAK]
EXPORTSDIO_IRQHandler[WEAK]
EXPORTTIM5_IRQHandler[WEAK]
EXPORTSPI3_IRQHandler[WEAK]
EXPORTUART4_IRQHandler[WEAK]
EXPORTUART5_IRQHandler[WEAK]
EXPORTTIM6_IRQHandler[WEAK]
EXPORTTIM7_IRQHandler[WEAK]
EXPORTDMA2_Channel1_IRQHandler[WEAK]
EXPORTDMA2_Channel2_IRQHandler[WEAK]
EXPORTDMA2_Channel3_IRQHandler[WEAK]
EXPORTDMA2_Channel4_5_IRQHandler [WEAK]
;
如下只是定义一些空函数
WWDG_IRQHandler
PVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
DMA1_Channel5_IRQHandler
DMA1_Channel6_IRQHandler
DMA1_Channel7_IRQHandler
ADC1_2_IRQHandler
USB_HP_CAN1_TX_IRQHandler
USB_LP_CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_SCE_IRQHandler
EXTI9_5_IRQHandler
TIM1_BRK_IRQHandler
TIM1_UP_IRQHandler
TIM1_TRG_COM_IRQHandler
TIM1_CC_IRQHandler
TIM2_IRQHandler
TIM3_IRQHandler
TIM4_IRQHandler
I2C1_EV_IRQHandler
I2C1_ER_IRQHandler
I2C2_EV_IRQHandler
I2C2_ER_IRQHandler
SPI1_IRQHandler
SPI2_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
USART3_IRQHandler
EXTI15_10_IRQHandler
RTCAlarm_IRQHandler
USBWakeUp_IRQHandler
TIM8_BRK_IRQHandler
TIM8_UP_IRQHandler
TIM8_TRG_COM_IRQHandler
TIM8_CC_IRQHandler
ADC3_IRQHandler
FSMC_IRQHandler
SDIO_IRQHandler
TIM5_IRQHandler
SPI3_IRQHandler
UART4_IRQHandler
UART5_IRQHandler
TIM6_IRQHandler
TIM7_IRQHandler
DMA2_Channel1_IRQHandler
DMA2_Channel2_IRQHandler
DMA2_Channel3_IRQHandler
DMA2_Channel4_5_IRQHandler
B.ENDPALIGN;
默认是字对齐方式;
*******************************************************************************
;
User Stack and Heap initialization 用户堆栈初始化
;
*******************************************************************************
IF:DEF:__MICROLIB;
判断是否使用DEF:__MICROLIB(micro lib),如果勾选了micro libEXPORT__initial_sp;
将栈顶地址、堆起始地址、堆结束地址赋予全局属性,使外部程序可用
EXPORT__heap_base
EXPORT__heap_limitELSE;
如果没有勾选micro libIMPORT__use_two_region_memory;
两区堆栈空间,堆和栈有各自的空间地址
EXPORT__user_initial_stackheap__user_initial_stackheap;
标号__user_initial_stackheap,表示用户堆栈初始化程序入口
;
此处是初始化两区的堆栈空间,堆是从由低到高的增长,栈是由高向低生长的,两个是互相独立的数据段,并不能交叉使用。
LDRR0, =Heap_Mem;
保存堆起始地址
LDRR1, =(Stack_Mem + Stack_Size);
保存栈结束地址
LDRR2, = (Heap_Mem +Heap_Size);
保存堆结束地址
LDRR3, = Stack_Mem;
保存栈起始地址
BXLRALIGNENDIFEND;
END命令指示汇编器,已到达一个源文件的末尾;
******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****