STM32启动库文件学习笔记

                                                      STM32启动库文件学习笔记

一、Stack–栈

EQU:宏定义的伪指令,就是给数字取一个符号名,相当于C语言中的define
SPACE:分配内存空间
AREA:告诉汇编语言一个新的代码段或数据段
PRESERVE8:当前文件堆栈需要按八字节对齐。
ALIGN:编译器对指令或数据的存放地址进行对齐,不写的话默认4字节对齐,这个不是ARM指令,是编译器的指令。
比如:ALIGN=3 表示8(2^3)字节对齐

 例程
:Stack_Size   EQU   0X00000400   //定义了一个量Stack_Size表示1k,即0x00000400
		   
						AREA STACK,NOINIT,READWRITE,ALIGN=3;//STACK表示段名,NOINIT表示不初始化,READWRITE表示可读可写
		   Stack_Mem	SPACE  Stack_Size		   
	   __initial_sp    //__initial_sp紧挨着SPACE语句放置,表示栈的结束地址,即栈顶地址,栈是由高向低生长,
	                  //而堆则是由低向高生长,这样可以充分利用空闲的地址空间

注意:栈的作用就是为了存放局部变量,函数调用,函数形参等,栈的大小不能超过内部SRAM的大小。如果程序比较大,
定义的局部变量很多,那么就要修改栈的大小,不然会出错。

二、Heap–堆

例程:

Heap_Size    EQU      0X00000200 //开辟堆的大小是512字节,即0x00000200

				  AREA   HEAP,NOINIT,READWRITE,ALIGN=3 //堆的名字是HEAP,
      __heap_base
      Heap_Mem     SPACE   Heap_Size
	  __heap_limit
	  
	               PRESERVE8
				   THUMB

解析: __heap_base表示堆的起始地址,__heap_limit表示堆的结束地址。堆主要用来分配动态内存,比如malloc()函数申请的
内存就是在堆上面,PRESERVE8表示当前文件堆栈按8字节对齐,THUMB表示后面的指令兼容THUMB指令,THUMB是ARM以前的指令
集,16bit,现在Cortex-M系列都使用THUMB-2指令集,THUMB-2是32位的,兼容16位和32位的指令,是THUMB的超集。

三、向量表

例程:

AREA        RESET, DATA, READONLY

	EXPORT      __Vectors
	EXPORT      __Vectors_End
	EXPORT      __Vectors_Size

解析:定义一个数据段,名字是RESET,可读。声明__Vectors、__Vectors_End、__Vectors_Size这三个标号具有全局变量
EXPORT:声明一个标号可以被外部的文件使用,使标号具有全局属性。如果使用的是IAR编译器,则用GLOBAL这个指令。
该段函数的作用:比如我们的内核响应了一个发生的异常,对应的异常服务例程(ESR)就会被执行。为了决定ESR的入口地址,
内核使用了“向量表查表机制”,所以这里使用一张向量表。向量表其实是一个WORD(32位整数)数组,
每个下表对应一种异常,该下标元素的值就是该ESP的入口地址。向量表在地址空间中的位置是可以通过NVIC
中的一个重定位寄存器来设置的。复位后该寄存器的值为0。所以在地址0的地方必须包含一张向量表,用于初始
时候的异常分配。

__Vectors     DCD    __initial_sp     //栈顶地址
				   DCD    Reset_Handler  //复位程序地址
				   DCD    NMI_Handler
				   DCD    HardFault_Handler
				   DCD    MemManage_Handler
				   DCD    BusFault_Handler
				   DCD    UsageFault_Handler
				   DCD    0
				   DCD    0
                   DCD    0	  
				   DCD    0
				   DCD    SVC_Handler
				   DCD    DebugMon_Handler
				   DCD    0
				   DCD    PendSV_Handler
				   DCD    SysTick_Handler
		//外部中断开始
                   DCD    WWDG_IRQHandler
				   DCD    PVD_IRQHandler
				   ....//限于篇幅,中间省略
				   DCD    DMA2_Channe14_5_IRQHandler
	 __Vectors_End
	 __Vectors_Size EQU __Vectors_End - __Vectors

解析:__Vectors为向量表起始地址,__Vectors_End为向量表结束地址,两个相减即可算出向量表的实际大小。
向量表从FLASH的0地址开始放置,以四个字节为一个单位,地址0存放的是栈顶的地址,0x04存放的是复位
程序的地址,以此类推。从代码上来看,向量表中存放的都是中断服务函数的函数名,其实C语言中
的函数名就是一个地址。
DCD:分配一个或者多个字节为单位的内存,以四字节对齐,并要求初始化这些内存。在向量表中,DCD分配了
一些内存,并且以ESR的入口地址初始化它们。

四、复位程序

	   AREA |.text|, CODE, READONLY    //定义一个名称为.text的代码段,可读
Reset_Handler PROC
			EXPORT  Reset_Handler   [WEAK]
			IMPORT  SystemInit
			IMPORT  __main
			
			LDR     R0, =SystemInit
			BLX     R0
			LDR     R0, =main
			BX      R0
			ENDP

解析:WEAK:表示弱定义,就是如果外部文件优先定义了这个标号,则首先引用该标号,
即使外部文件没有声明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,
在这里并不是唯一的。
IMPORT:表示该标号来自外部文件,和c语言中的extern关键字作用类似,这个程序中表示
SystemInit和__main这两个函数均来自外部文件。

  LDR、BLX、BX是CM4内核的指令,作用如下:
  LDR:从存储器中加载字到一个寄存器中
  BL:跳转到由寄存器/标号给出的地址,并把跳转前的下条指令的地址保存到LR
  BLX:跳转到由寄存器给出的地址,并根据寄存器的LSE确定处理器的状态,还要
      把跳转前的下条指令地址保存到LR
  BX:跳转到由寄存器/标号给出的地址,不用返回。	  

说明:复位子程序是系统上电后第一个执行的程序,调用SystemInit函数初始化系统时钟,然后调用c库函数__main,
初始化用户堆栈 该函数的最后进入main()函数,最终去到C的世界,这就是为什么我们写的程序中都
有一个main()函数。
SystemInit()是一个标准的库函数,在system_stm32f10x.c这个库文件中定义,主要作用是配置系统时钟,这里调用
这个函数后,单片机的系统时钟被配置为72M。

五、中断服务程序

NMI_Handler   	PROC // 系统异常
				EXPORT NMI_Handler [WEAK] 
				B .
				ENDP
				// 限于篇幅,中间代码省略
			 
SysTick_Handler PROC
				EXPORT SysTick_Handler [WEAK] B .
				ENDP
Default_Handler PROC // 外部中断
				EXPORT WWDG_IRQHandler [WEAK]
				EXPORT PVD_IRQHandler [WEAK]
				EXPORT TAMP_STAMP_IRQHandler [WEAK]
				// 限于篇幅,中间代码省略
			  
			  LTDC_IRQHandler
              LTDC_ER_IRQHandler
              DMA2D_IRQHandler
              B .

              ENDP

说明:在启动文件里面已经写好了所有的中断服务函数,但是这些函数都是空的,真正的中断程序需要我们在外部的c文件
里面重新实现,这里只是占个位置。但是如果我们使用外设开启了某个中断但是又没有编写配套的中断服务函数
或者函数名写错那么中断来临时候就会进入启动文件预先写好的空的中断服务程序,并且在这个空函数里面无线循环,
程序就死在这里。
解析:B:跳转到一个标号,这里跳转到“.”,即表示无线循环。

六、用户堆栈初始化

例程:
 IF      :DEF:__MICROLIB  //这个宏在keil里面开启
                
                 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	  

说明:该程序首先判断是否定义了__MICROLIB,如果定义了则赋予 __initial_sp(栈顶地址)、__heap_base(堆起始地址)、
__heap_limit(堆结束地址)全局属性,可供外部文件调用。这个宏在keil里面设置,之后堆栈的初始化就由c库函数
__main来完成。如果没有定义,则用双段存储器模式,且声明标号__user_initial_stackheap具有全局属性,让用户自己
初始化堆栈。
解析:IF,ELSE,ENDIF:汇编的条件分支语句,跟C语言的if,else类似
END:文件结束。

查看文章 STM32 keil mdk启动代码发分析_转2010年01月29日 星期五 13:50 ;// Stack Configuration ;// Stack Size (in Bytes) ;// Stack_Size EQU 0x00000200 ;//定义堆栈大小 AREA STACK, NOINIT, READWRITE, ALIGN=3 ;//定义一个数据段 按8字节对齐 ;AREA 伪指令用于定义一个代码段或数据段 NOINIT:指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各个内存单元值初始化为0 Stack_Mem SPACE Stack_Size ;//保留Stack_Size大小的堆栈空间 分 配连续 Stack_Size 字节的存储单元并初始化为 0 __initial_sp ;//标号,代表堆栈顶部地址,后面有用 ;// Heap Configuration ;// Heap Size (in Bytes) ;// Heap_Size EQU 0x00000020 ;//定义堆空间大小 AREA HEAP, NOINIT, READWRITE, ALIGN=3 ;//定义一个数据段,8字节对齐 __heap_base Heap_Mem SPACE Heap_Size ;//保留Heap_Size的堆空间 __heap_limit ;//标号,代表堆末尾地址,后面有用 PRESERVE8 ;//指示编译器8字节对齐 THUMB ;//指示编译器为THUMB指令 ; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY ;//定义只读数据段,其实放在CODE区,位于0地址 EXTERN NMIException EXTERN HardFaultException EXTERN MemManageException EXTERN BusFaultException EXTERN UsageFaultException EXTERN SVCHandler EXTERN DebugMonitor EXTERN PendSVC EXTERN SysTickHandler ;//声明这些符号在外部定义,同C ;//在××it.c中实现这些函数 ,中断就能自动调用了 EXPORT __Vectors EXPORT __initial_sp ;EXPORT:在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用;IMPORT:伪指令用于通知编译器要使用的标号在其他的源文件中定义, ;但要在当前源文件中引用,而且无论当前源文件是否引用该标号,该标号均会被加入到当前源文件的符号表中 __Vectors DCD __initial_sp ; Top of Stack //Cotex-M 要求此处为堆栈顶部地址 DCD Reset_Handler ; Reset Handler DCD NMIException ; NMI Handler DCD HardFaultException ; Hard Fault Handler DCD MemManageException ; MPU Fault Handler DCD BusFaultException ; Bus Fault Handler DCD UsageFaultException ; Usage Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVCHandler ; SVCall Handler DCD DebugMonitor ; Debug Monitor Handler DCD 0 ; Reserved DCD PendSVC ; PendSV Handler DCD SysTickHandler ; SysTick Handler //一大堆的异常处理函数地址 ; External Interrupts EXTERN WWDG_IRQHandler EXTERN PVD_IRQHandler EXTERN TAMPER_IRQHandler EXTERN RTC_IRQHandler EXTERN FLASH_IRQHandler EXTERN RCC_IRQHandler EXTERN EXTI0_IRQHandler EXTERN EXTI1_IRQHandler EXTERN EXTI2_IRQHandler EXTERN EXTI3_IRQHandler EXTERN EXTI4_IRQHandler EXTERN DMAChannel1_IRQHandler EXTERN DMAChannel2_IRQHandler EXTERN DMAChannel3_IRQHandler EXTERN DMAChannel4_IRQHandler EXTERN DMAChannel5_IRQHandler EXTERN DMAChannel6_IRQHandler EXTERN DMAChannel7_IRQHandler EXTERN ADC_IRQHandler EXTERN USB_HP_CAN_TX_IRQHandler EXTERN USB_LP_CAN_RX0_IRQHandler EXTERN CAN_RX1_IRQHandler EXTERN CAN_SCE_IRQHandler EXTERN EXTI9_5_IRQHandler EXTERN TIM1_BRK_IRQHandler EXTERN TIM1_UP_IRQHandler EXTERN TIM1_TRG_COM_IRQHandler EXTERN TIM1_CC_IRQHandler EXTERN TIM2_IRQHandler EXTERN TIM3_IRQHandler EXTERN TIM4_IRQHandler EXTERN I2C1_EV_IRQHandler EXTERN I2C1_ER_IRQHandler EXTERN I2C2_EV_IRQHandler EXTERN I2C2_ER_IRQHandler EXTERN SPI1_IRQHandler EXTERN SPI2_IRQHandler EXTERN USART1_IRQHandler EXTERN USART2_IRQHandler EXTERN USART3_IRQHandler EXTERN EXTI15_10_IRQHandler EXTERN RTCAlarm_IRQHandler EXTERN USBWakeUp_IRQHandler ;//同上, DCD WWDG_IRQHandler ; Window Watchdog DCD PVD_IRQHandler ; PVD through EXTI Line detect DCD TAMPER_IRQHandler ; Tamper DCD RTC_IRQHandler ; RTC DCD FLASH_IRQHandler ; Flash DCD RCC_IRQHandler ; RCC DCD EXTI0_IRQHandler ; EXTI Line 0 DCD EXTI1_IRQHandler ; EXTI Line 1 DCD EXTI2_IRQHandler ; EXTI Line 2 DCD EXTI3_IRQHandler ; EXTI Line 3 DCD EXTI4_IRQHandler ; EXTI Line 4 DCD DMAChannel1_IRQHandler ; DMA Channel 1 DCD DMAChannel2_IRQHandler ; DMA Channel 2 DCD DMAChannel3_IRQHandler ; DMA Channel 3 DCD DMAChannel4_IRQHandler ; DMA Channel 4 DCD DMAChannel5_IRQHandler ; DMA Channel 5 DCD DMAChannel6_IRQHandler ; DMA Channel 6 DCD DMAChannel7_IRQHandler ; DMA Channel 7 DCD ADC_IRQHandler ; ADC DCD USB_HP_CAN_TX_IRQHandler ; USB High Priority or CAN TX DCD USB_LP_CAN_RX0_IRQHandler ; USB Low Priority or CAN RX0 DCD CAN_RX1_IRQHandler ; CAN RX1 DCD CAN_SCE_IRQHandler ; CAN SCE DCD EXTI9_5_IRQHandler ; EXTI Line 9..5 DCD TIM1_BRK_IRQHandler ; TIM1 Break DCD TIM1_UP_IRQHandler ; TIM1 Update DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare DCD TIM2_IRQHandler ; TIM2 DCD TIM3_IRQHandler ; TIM3 DCD TIM4_IRQHandler ; TIM4 DCD I2C1_EV_IRQHandler ; I2C1 Event DCD I2C1_ER_IRQHandler ; I2C1 Error DCD I2C2_EV_IRQHandler ; I2C2 Event DCD I2C2_ER_IRQHandler ; I2C2 Error DCD SPI1_IRQHandler ; SPI1 DCD SPI2_IRQHandler ; SPI2 DCD USART1_IRQHandler ; USART1 DCD USART2_IRQHandler ; USART2 DCD USART3_IRQHandler ; USART3 DCD EXTI15_10_IRQHandler ; EXTI Line 15..10 DCD RTCAlarm_IRQHandler ; RTC Alarm through EXTI Line DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend ;//同上 AREA |.text|, CODE, READONLY ;//定义代码段 ; Reset Handler Reset_Handler PROC ;过程的开始 ;//Rset_Handler的实现 利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰 EXPORT Reset_Handler [WEAK] ;//在外部没有定义该符号时导出该符号,见HELP中[WEAK] IMPORT __main ;//导入符号,__main为 运行时库提供的函数;完成堆栈,堆的初始话 LDR R0, =__main ;//等工作,会调用下面定义的__user_initial_stackheap; BX R0 ;//跳到__main,进入C的世界 ENDP ;过程的结束 ALIGN ; User Initial Stack & Heap IF :DEF:__MICROLIB ;//如果使用micro lib,micro lib 描述见armlib.chm EXPORT __heap_base EXPORT __heap_limit ;//只导出几个定义 ELSE ;//如果使用默认C运行时库 IMPORT __use_two_region_memory EXPORT __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 ;//OK ,完了 http://blog.youkuaiyun.com/chehlcy/archive/2010/01/09/5164472.aspx http://files.ourdev.cn/bbs_upload134190/files_11/ourdev_495775.txt ====================================================================== Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main LDR R0, =__main BX R0 ENDP 这段代码什么意思。 有2个地方不理解 一:PROC ENDP 二: [WEAK] 什么意思 ------------------------------------------------------------------------------- 一:PROC为子程序开始,ENDP为子程序结束 二:[weak]的意思就是弱。 怎么弱呢?如果你在其他地方写一个同名函数,比如Reset_handler, 你写的这个函数就可以取代它这个函数了。 语法格式: EXPORT 标号 {[WEAK]} EXPORT 伪指令用于在程序中声明一个全局的标号,该标号可在其他的文件中引用。 EXPORT可用 GLOBAL 代替。标号在程序中区分大小写, [WEAK] 选项声明其他的同名标号优先于该标号被引用。 使用示例: AREA Init , CODE , READONLY EXPORT Stest ;声明一个可全局引用的标号Stest…… END
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北海冥鱼未眠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值