stm32揭秘

stm32上电完成的操作

  1. 定义堆栈空间、指针
  2. 定义并初始化中断向量表
  3. 初始化中断处理程序
  4. 初始化内存堆栈空间
指令作用
EQU定义字符常量,相当于C语言的 define
AREA汇编一个新的代码段或数据段
SPACE分配内存空间
PRESERVE8当前文件堆栈需按照 8 字节对其
EXPORT声明全局属性,可被外部文件使用
DCD以字为单位分配内存,要求4字节对齐,并初始化这些内存
PROC定义子程序,与 ENOP 成对使用,表示子程序结束
WEAK弱定义,如果外部文件声明了一个标号,则优先使用外部文件定义的标号,如果外部文件没有定义,则使用当前位置的标号
IMPORT声明标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似
B跳转到一个标号
END到达文件的末尾,文件结束
IF,ELSE,ENDIF汇编条件分支语句
LDR从存储器中加载字到一个寄存器中
BL跳转到由寄存器/标号给出的地址,并把跳转前的下条指令地址保存到 LR
BLX跳转到由寄存器给出的地址,并根据寄存器的LSE确定处理器的状态,还要把跳转前的下条指令地址保存到LR
BX跳转到由寄存器/标号给出的地址,不用返回

上电初始化后的内存布局

1.初始化栈信息

; Amount of memory (in bytes) allocated for Stack
Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp
  • 初始化栈:栈用于保存临时变量如形参、局部变量,根据程序大小制定即可,此处为1KB。
  • AREA: 告诉汇编器开辟一个新的代码段或者数据段
  • STACK:表示分配的空间为栈
  • ALIGN=3:表示栈空间按照2^3字节对齐
  • SPACE: 用于分配一个一定大小的内存空间,以字节为单位,这里指定的大小为Stack_size
  • __initial_sp:在SPACE之后,表示分配空间的开始地址,对于栈来说,自上向下生长,因此开始地址为高址。
    在这里插入图片描述
    观察编译后生成的map文件内存空间分配无误。

2.初始化堆

与栈空间分配相同的视线过程

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

初始化堆:堆是为程序员分配的一片空间,为程序员malloc和free使用,此处为512KB。

3.初始化中断向量表

中断向量表中对应每个设备中断的中断处理程序的入口地址(即函数名),通过调用函数名执行中断处理程序(这也是非Linux中断处理程序没有参数和返回值的体现之一),中断向量表的中断处理函数通常都为无执行内容的弱函数,支持程序员员重写。
弱函数的目的是为了防止重复定义的函数在编译器编译阶段报错,优先选择.c文件的函数执行。

(1)创建中断向量表数据段

中断向量表每个中断向量为4B,每个元素为中断处理函数,设备中断向量号为x的中断处理函数通过[__Vectors+vec_nr*4]遍历。

; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size
__Vectors       DCD     __initial_sp               ; Top of Stack                            
                DCD     Reset_Handler              ; Reset Handler
                ……
                DCD     I2C1_EV_IRQHandler         ; I2C1 Event
                DCD     I2C1_ER_IRQHandler         ; I2C1 Error
                DCD     I2C2_EV_IRQHandler         ; I2C2 Event
                ……
__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors
  • 定义名为RESET的数据段,只读;
  • __Vectors:中断向量表数组
  • __Vectors_End:中断向量表数组结束地址
  • __Vectors_Size:中断向量表数组大小,=__Vectors_End-__Vectors
    上文为堆栈分配的空间均位于SRAM中,不占用代码空间,从这个数据段开始才是stm32代码空间的起始位置。定义了中断向量表相关的变量;定义并初始化了栈顶位置(__initial_sp)以及15个内核异常处理函数的入口地址,接下来是外部中断。
(2)创建中断向量表部分中断处理程序代码段
(2.1)定义中断代码段
AREA    |.text|, CODE, READONLY
(2.2)复位中断处理程序

初始化外设接口、PLL时钟倍频;跳转执行main函数

; Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit		;初始化嵌入式闪存接口、PLL并更新;系统核心时钟变量
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP
(2.3)中断处理程序

真正的中断服务函数需要在外部的.c文件中实现,这里只是占位,是把中断和与之对应中断服务函数绑定了。当开启某个中断后,没有写对应的中断服务函数或者函数名有误,当中断来临时程序还是跳转到启动文件预先写好的中断服务函数中,在这个函数中无限循环。

Default_Handler PROC
                ;优先查找外部c文件定义的中断处理程序
                EXPORT  WWDG_IRQHandler            [WEAK]
                ……
                EXPORT  I2C1_EV_IRQHandler         [WEAK]
                EXPORT  I2C1_ER_IRQHandler         [WEAK]
                EXPORT  I2C2_EV_IRQHandler         [WEAK]
                EXPORT  I2C2_ER_IRQHandler         [WEAK]
                EXPORT  SPI1_IRQHandler            [WEAK]
                EXPORT  SPI2_IRQHandler            [WEAK]
                EXPORT  USART1_IRQHandler          [WEAK]
                EXPORT  USART2_IRQHandler          [WEAK]
                EXPORT  USART3_IRQHandler          [WEAK]
                ……
                ;汇编文件定义的中断处理程序
                WWDG_IRQHandler
                I2C1_EV_IRQHandler
                I2C1_ER_IRQHandler
                I2C2_EV_IRQHandler
                I2C2_ER_IRQHandler
                SPI1_IRQHandler
                SPI2_IRQHandler
                USART1_IRQHandler
                USART2_IRQHandler
                USART3_IRQHandler
                ……
                B       .  ;B表跳转到一个标号,"."表无限循环
                ENDP
                ALIGN

4.堆栈初始化

;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
                 IF      :DEF:__MICROLIB             
                 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则将栈顶地址和堆的起始、结束地址export出去,microlib会进行堆栈初始化的操作,若是没有使用,则堆栈初始化时会使用__user_initial_stackheap函数。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值