005 - STM32学习笔记 - 启动代码

005 - STM32学习笔记 - 启动代码

常用汇编指令

指令名称作用
EQU给数字常量取一个符号名,相当于C语言中的#define
AREA汇编一个新的代码段或者数据段;
SPACE分配内存空间;
PRESERVE8当前文件栈需要按照8字节对齐;
EXPORT声明一个具有全局属性的标号,可被外部文件访问;
DCD以字为单位分配内存,要求按照4字节对齐,并初始化这些内存;
PROC定义子程序,与ENDP成对使用,ENDP表示子程序结束;
WEAK若定义,如果外部声明了该指令修饰的标号,则优先使用外部声明的标号,如果外部没有声明,也不会出错。
IMPORT声明标号来自外部文件,与C语言中的extern关键字类似
B跳转指令,即跳转到一个标号;
ALIGN编译器对指令或者数据的存放地址进行对齐,一般需要跟一个立即数,默认表示按照4字节对齐;
END达到文件的末尾,表示文件结束;
IF,ENSE,ENDIF汇编条件分支语句,与C语言中的if...else...类似
;注释符,与C语言中//类似

启动代码

看一下startup_stm32f4429_439xx.s文件前面的copyright内容

;******************** (C) COPYRIGHT 2016 STMicroelectronics ********************
;* File Name          : startup_stm32f429_439xx.s
;* Author             : MCD Application Team
;* @version           : V1.8.0
;* @date              : 09-November-2016
;* Description        : STM32F429xx/439xx devices vector table for MDK-ARM toolchain. 
;*                      This module performs:
;*                      - Set the initial SP											初始化指针sp
;*                      - Set the initial PC == Reset_Handler							 初始化指针pc
;*                      - Set the vector table entries with the exceptions ISR address		初始化向量终端表
;*                      - Configure the system clock and the external SRAM/SDRAM mounted  	配置系统时钟
;*                        on STM324x9I-EVAL boards to be used as data memory  
;*                        (optional, to be enabled by user)
;*                      - Branches to __main in the C library (which eventually				调用C库
;*                        calls main()).
;*                      After Reset the CortexM4 processor is in Thread mode,
;*                      priority is Privileged, and the Stack is set to Main.

STM32启动代码由汇编编写,会在系统上电后执行,可以认为启动代码就是整个系统启动的引导程序,功能主要分如下几个:

  1. 初始化栈指针SP = _initial_sp
  2. 初始化PC指针 = Rest_Handler ;
  3. 初始化中断向量表;
  4. 配置系统时钟;
  5. 调用C库函数_main初始化用户栈,从而真正转到C的main函数中。

1、栈

Stack_Size      EQU     0x00000400	;给0x00000400这个立即数一个别名Stack_Size,从名字上可以看出来这是给栈分配空间为1KB,如果不够的话可以修改这里

                AREA    STACK, NOINIT, READWRITE, ALIGN=3 ;栈名称为STACK,NOINIT为不初始化,READWRIT:可读写,ALIGN=3,表示已2^3(8)字节对齐
Stack_Mem       SPACE   Stack_Size		;指定了内存大小等于Stack_Size
__initial_sp						  ;标号__initial_sp紧挨着SPACE放置,表示栈的结束地址,及栈顶地址

打开map文件可以看到关于栈的相关信息
在这里插入图片描述

2、堆

Heap_Size       EQU     0x00000200	;给0x00000200这个立即数一个别名Heap_Size,从名字上可以看出来这是给栈分配空间为512B,如果不够的话可以修改这里

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3 ;堆名称为HEAP,NOINIT为不初始化,READWRIT:可读写,ALIGN=3,表示已2^3(8)字节对齐
__heap_base								;堆的起始地址
Heap_Mem        SPACE   Heap_Size		  ;指定对的内存大小等于Heap_Size
__heap_limit							;堆的结束地址

                PRESERVE8				 ;指定当前文件的堆按照8字节对齐
                THUMB					;后面指令兼容THUMB指令

3、向量表

; 重映射向量表
                AREA    RESET, DATA, READONLY		;定义数据段,名称为RESET,只读模式,
                EXPORT  __Vectors				   ;声明可被外部访问的标号
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size	
;这里我自己理解就类似于一个数组,__Vectors是数组的起始地址,__Vectors_End是数组结束地址,__Vectors_Size在最后做了计算,是起始地址与结束地址的差值
;向量表中记录了系统所有中断向量地址,当内核响应了发生的异常(中断或事件)后,对应的异常服务例程就会执行,所以这里的向量表就是为异常服务机制提供入口地址
__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     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     WWDG_IRQHandler                   ; Window WatchDog                                        
                DCD     PVD_IRQHandler                    ; PVD through EXTI Line detection                        
                DCD     TAMP_STAMP_IRQHandler             ; Tamper and TimeStamps through the EXTI line            
                DCD     RTC_WKUP_IRQHandler               ; RTC Wakeup through the EXTI line                       
                DCD     FLASH_IRQHandler                  ; FLASH                                           
                DCD     RCC_IRQHandler                    ; RCC                                             
                DCD     EXTI0_IRQHandler                  ; EXTI Line0                                             
                DCD     EXTI1_IRQHandler                  ; EXTI Line1                   
			   ;由于篇幅原因,中间就删掉了
                DCD     SPI4_IRQHandler                   ; SPI4
                DCD     SPI5_IRQHandler                   ; SPI5
                DCD     SPI6_IRQHandler                   ; SPI6
                DCD     SAI1_IRQHandler                   ; SAI1
                DCD     LTDC_IRQHandler                   ; LTDC
                DCD     LTDC_ER_IRQHandler                ; LTDC error
                DCD     DMA2D_IRQHandler                  ; DMA2D
                                         
__Vectors_End			;这里表示向量表的结束地址

__Vectors_Size  EQU  __Vectors_End - __Vectors		;计算向量表的容量并赋值给__Vectors_Size

4、复位程序

                AREA    |.text|, CODE, READONLY		;定义了名称为.text的代码段,只读
; Reset handler定义名为Reset_Handler的子程序
Reset_Handler    PROC
				;导入Reset_Handler子程序,这里用WEAK修饰表示弱定义,优先定义外部定义的程序,如果没有,也不会报错,
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit				;表示SystemInit函数来自外部
        IMPORT  __main					;表示__main函数来自外部

                 LDR     R0, =SystemInit	;将SystemInit加载到R0寄存器中
                 BLX     R0					;跳转到R0给出的地址
                 LDR     R0, =__main		;将__main加载到R0寄存器中
                 BX      R0					;跳转到R0给出的地址
                 ENDP					   ;程序结束

SystemInit是标准库函数,在system_stm32f4xx.c中定义,主要是用来配置系统时钟,我现在用的F429的开发板,在调用SystemInit后,会将系统时钟配置到180MHz。

__main是个标准C库函数,但是这里要主义的是,这个main不是我们在C语言中的main函数,__main作用是初始化用户栈,完成后在最后调用main转到C语言中。

5、中断服务程序

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

NMI_Handler     PROC									;定义了NMI_Handler中断子程序
                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]         
                EXPORT  RTC_WKUP_IRQHandler               [WEAK]                     
                EXPORT  FLASH_IRQHandler                  [WEAK]                                         
                EXPORT  RCC_IRQHandler                    [WEAK]                                            
                EXPORT  EXTI0_IRQHandler                  [WEAK]                                            
              ;篇幅省略
                EXPORT  LTDC_ER_IRQHandler                [WEAK]
                EXPORT  DMA2D_IRQHandler                  [WEAK]

WWDG_IRQHandler                                                       
PVD_IRQHandler                                      
TAMP_STAMP_IRQHandler                  
;篇幅省略  
LTDC_IRQHandler                   
LTDC_ER_IRQHandler                 
DMA2D_IRQHandler                  
                B       .				;跳转到.,在这里.表示无限循环
                ENDP

这里需要注意的是,使用中断的时候,应为是弱定义的中断服务子程序,因此会优先调用外部定义的服务程序,当我们在外部没有编写配套的中断服务子程序或者编写的服务子程序与启动文件中的程序名不一致时,系统会自动跳转到启动文件中默认的中断服务子程序中,B .然后就在此处无限循环,程序就卡死到这里了

6、用户堆与栈的初始化

                ALIGN		;用来指定符号的对齐方式,默认按照4字节对齐
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
                 IF      :DEF:__MICROLIB	;这里会判断是否定义了__MICROLIB,即表示是否使用MicroLib库,可以看仙女棒中是否勾选
                 EXPORT  __initial_sp		;如果使用MicroLib库,则给__initial_sp、__heap_base、__heap_limit给全局属性,可以让外部文件调用
                 EXPORT  __heap_base
                 EXPORT  __heap_limit
                 ELSE
                 ;如果没有使用MicroLib库,则使用双段存储器模式,并且声明__user_initial_stackheap全局属性,由用户自行初始化堆栈
                 IMPORT  __use_two_region_memory	
                 EXPORT  __user_initial_stackheap
                 ;以下就是没有使用MicroLib库,由用户自行初始化堆栈的程序
__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

配置使用MircroLib库

配置使用MircroLib库

本节内容中需要主要,后续使用的中断的时候,一定要检查中断服务子程序是否写错或者未定义,否则很容易出现中断服务程序无限循环的情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/22507.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

k8s pv pvc的介绍|动态存储|静态存储

k8s pv pvc的介绍|动态存储|静态存储 1 emptyDir存储卷2 hostPath存储卷3 nfs共享存储卷4 PVC 和 PVNFS使用PV和PVC 4 搭建 StorageClass NFS,实现 NFS 的动态 PV 创建 1 emptyDir存储卷 当Pod被分配给节点时,首先创建emptyDir卷,并且只要该…

详解c++STL—函数对象

目录 1、函数对象 1.1、函数对象概念 1.2、函数对象的使用 2、谓词 2.1、谓词概念 2.2、一元谓词 2.3、二元谓词 3、内建函数对象 3.1、理解内建函数对象 3.2、算术仿函数 3.3、关系仿函数 3.4、逻辑仿函数 1、函数对象 1.1、函数对象概念 概念: 重载…

编译原理个人作业--第六章——基于 编译原理 国防工业出版社 第三版

2 对表达式((a)(b)) (1) 按照表6.4属性文法构造抽象语法树 (2) 按6.17翻译模式构造表达式抽象语法树 5(1) 下列文法对整型常数、实型常熟世家加法运算符 生成表达式,当两个整型数相加,结果为整形,否则结果为实型 E → E T ∣ T E\r…

面试技术点

一、对热修复、插件化、模块化、组件化有一定研究。 1、模块化 将共享部分或业务模块抽取出来形成独立module。 2、组件化 基于模块化,核心思想是角色的转换,在打包时是library,分离独立的业务组件如微信朋友圈。 3、热修复和插件化种类、…

电力系统机组组合优化调度(IEEE14节点、IEEE30节点、IEEE118节点)(Matlab代码实现)

💥💥💥💞💞💞欢迎来到本博客❤️❤️❤️💥💥💥 📝目前更新:🌟🌟🌟电力系统相关知识,期刊论文&…

Java并发编程-synchronized

目录 1. synchronized在jdk 1.6中的优化 1.1 锁消除 1.2 锁粗化 1.2 锁升级/锁膨胀 1.2.1 锁升级原理 1.2.2 自适应自旋锁 2. synchronized实现原理 3. synchronized和Lock的对比 1. synchronized在jdk 1.6中的优化 在JDK1.5的时候,Doug Lee推出了ReentrantLock,lock的…

chatgpt赋能Python-python_os拷贝文件

Python os拷贝文件 – 从简介到实现 Python os库是一个经常使用的工具,它是Python的标准库,提供了与操作系统进行交互的函数和方法。其中,os拷贝文件是其常用的功能之一,可以用来实现文件备份、文件复制等等操作。接下来&#xf…

windows sever服务器安装系统新手版

混在learnsite群里已经有几年了吧,但是只有一段时间用了别人现成的一个iso版本还比较老,这次打算自己弄一个,一开始打算linux下弄,结果系统都装完了发现人家说learnsite在linux下有点bug没解决好,只能win下再弄&#x…

Vue+uniapp桃源婚恋交友APP 安卓小程序 nodejs java python

小程序框架:uniapp 小程序开发软件:HBuilder X 开发模式:混合开发本文先提出了开发基于小程序的桃源婚恋交友APP系统的背景意义,然后通过功能性和非功能性分析阐述本系统的需求,然后进行系统设计。技术实现部分选择Jav…

据不可靠消息,ST的新一代机皇正式命名为STM32V8系列,搭载Cortex-M85内核

根据以往的传统单片机命名方式: C0, L0, G0, F0 > Cortex-M0内核 F1, L1 > Corterx-M3内核 F2, F3 > Corterx-M3/M4 F4,G4,L4, L4 > Cortex-M4内核 L5,U5, H5 > Cor…

web安全第一天 ,域名,dns

第一天 什么是域名?域名就是网络地址 在hhtp之后的就是域名 域名在哪里注册呢 国内注册商有很多,在网络上搜索一下阿里云万网就可以注册 什么是二级域名和多级域名 域名通常都是www.开头 ,而www.被称为顶级域名,在搜索的时候…

部门来了个测试开发,听说是00后,上来一顿操作给我看呆了...

公司新来了个同事,听说大学是学的广告专业,因为喜欢IT行业就找了个培训班,后来在一家小公司实习半年,现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍,服务器缩减一半,性能反而提升4倍&#xff01…

深度学习量化总结(PTQ、QAT)

背景 目前神经网络在许多前沿领域的应用取得了较大进展,但经常会带来很高的计算成本,对内存带宽和算力要求高。另外降低神经网络的功率和时延在现代网络集成到边缘设备时也极其关键,在这些场景中模型推理具有严格的功率和计算要求。神经网络…

5月份招了个00后测试堪称卷王之王,让人崩溃...

前段时间公司新来了个同事,听说大学是学的广告专业,因为喜欢IT行业就找了个培训班,后来在一家小公司干了三年,现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍,服务器缩减一半,性能反而提升4倍&am…

c++虚函数详解(多态特性)

1.c多态的概念 多态是c的特征之一 多态的分类:静态多态(静态联编)、动态多态(动态联编) 静态多态(静态联编):函数入口地址 是在 编译阶段 确定(运算符重载、函数重载&…

使用go语言构建区块链 Part4.事务1

英文源地址 简介 事务是比特币的核心, 区块链的唯一目的是以安全可靠的方式存储交易, 因此在交易创建后没有人可以修改. 今天我们开始实现事务, 但由于这是一个相当大的主题, 我将它分成两部分: 在这一部分中, 我们将实现事务的通用机制, 在第二部分中, 我们将研究细节. 此外…

【Go语言从入门到实战】基础篇

Go语言从入门到实战 — 基础篇 First Go Program 编译 & 运行 基本程序结构 应用程序入口 package mainimport "fmt"func main() {fmt.Println("Hello World") }退出返回值 package mainimport ("fmt""os" )func main() {fmt.Pr…

Unity3D :使用 UXML 实例作为模板

推荐:将 NSDT场景编辑器 加入你的3D工具链 3D工具集: NSDT简石数字孪生 使用 UXML 实例作为模板 您可以将现有 UXML 文档实例化为 UXML 文档中的模板作为模板实例,类似于预制件 在 Unity 中工作。 使用 UXML 文档作为模板 要将项目中的现有…

MySQL高级篇——覆盖索引、前缀索引、索引下推、SQL优化、主键设计

导航: 【Java笔记踩坑汇总】Java基础进阶JavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线MySQL高级篇设计模式牛客面试题 目录 8. 优先考虑覆盖索引 8.1 什么是覆盖索引? 8.1.0 概念 8.0.1 覆盖索引情况下,“不等于”…

Fourier分析入门——第4章——频率域

目录 第 4 章 频率域(The Frequency Domain) 4.1 频谱分析(Spectral Analysis) 4.2 物理单位(Physics units) 4.3 笛卡尔坐标形式与极坐标形式对比 4.4 频谱分析的复数形式 4.5 复数值Fourier系数 4.6 复数值的和三角的Fourier系数之间的关系 4.7 2维或多维离散Fouri…