首页 > 其他分享 >【STM32】STM32启动流程

【STM32】STM32启动流程

时间:2023-12-14 23:13:23浏览次数:39  
标签:__ 初始化 启动 流程 程序 STM32 地址

概述

从上电复位到main函数的过程主要由以下步骤:

1.初始化堆栈指针SP=_initial_sp,初始化PC指针=Reset_Handler

2.初始化中断向量表

3.配置系统时钟

4.调用C库函数_main初始化用户堆栈,然后进入main函数

1.STM32的启动模式

STM32的启动模式决定了向量表的位置,STM32有三种启动模式:

(1)主闪存存储器(Main Flash):

当STM32内置的Flash启动(0x0800 0000 - 0x0807FFFF),一般我们使用JTAG或者SWD模式下载程序时,就是下载到这个Flash里面,重启后也直接从这启动程序, 以0x08000000 对应的内存为例,则该块内存既可以通过0x00000000 操作也可以通过0x08000000 操作,且都是操作的同一块内存。

(2)系统存储器(System Memory)启动:

从系统存储器启动( 0x1FFFF000 - 0x1FFF F7FF),这种模式启动的程序功能是由厂家设置的。一般来说,我们选用这种启动模式时,是为了从串口下载程序,因为在厂家提供的ISP程序中,提供了串口下载程序的固件,可以通过这个ISP程序将用户程序下载到系统Flash中。以0x1FFFFFF0对应的内存为例, 则该块内存既可以通过0x00000000 操作也可以通过0x1FFFFFF0操作,且都是操作的同一块内存。

(3)片上SRAM启动:

从内置SRAM启动( 0x2000 0000-0x3FFFFFFF),既然是SRAM, 自然也就没有程序存储的能力了,这个模式一般用于程序调试。SRAM 只能通过0x20000000进行操作,与上述两者不同。从SRAM 启动时,需要在应用程序初始化代码中重新设置向量表的位置。

用户可以通过设置BOOT0和BOOT1的引脚电平状态,来选择复位后的启动模式。如下图所示:

image

启动模式只决定程序烧录的位置,加载完程序之后会有一个重映射,映射到 0x00000000地址位置,真正产生复位信号的时候,CPU还是从开始位置执行。

STM32上电复位以后,代码区都是从0x00000000开始的,三种启动模式只是将各自存储空间的地址映射到0x00000000中。

2.STM32的启动文件分析

启动过程主要由汇编完成,因此STM32的启动的大部分内容都是在启动文件里。不管使用Std库还是HAL库,启动文件都差不多

2.1堆栈定义

1.栈(stack)

栈的作用是用于局部变量,函数调用,函数形参等的开销,STM32上电复位以后,代码区都是从0x00000000开始的,三种启动模式只是将各自存储空间的地址映射到0x00000000中。

image

第35行:表示开辟栈的大小为 0X00000400(1KB),EQU是伪指令,相当于C 中的 define。

第37行:开辟一段可读可写数据空间,ARER 伪指令表示下面将开始定义一个代码段或者数据段。此处是定义数据段。ARER 后面的关键字表示这个段的属性。段名为STACK,可以任意命名;NOINIT 表示不初始化;READWRITE 表示可读可写,ALIGN=3,表示按照 8 字节对齐。

第38行:SPACE 用于分配大小等于 Stack_Size连续内存空间,单位为字节。

第39行: __initial_sp表示栈顶地址。栈是由高向低生长的。

2.堆(heap)

堆主要用来动态内存的分配,像 malloc()函数申请的内存就在堆中。

image

开辟堆的大小为 0X00000200(512 字节),名字为 HEAP,NOINIT 即不初始化,可读可写,8字节对齐。__heap_base 表示对的起始地址,__heap_limit 表示堆的结束地址。

2.2 向量表

向量表是一个WORD( 32 位整数)数组,每个下标对应一种异常,该下标元素的值则是该 ESR 的入口地址。向量表在地址空间中的位置是可以设置的,通过 NVIC 中的一个重定位寄存器来指出向量表的地址。在复位后,该寄存器的值为 0。因此,在地址 0 (即 FLASH 地址 0)处必须包含一张向量表,用于初始时的异常分配。

值得注意的是这里有个另类: 0 号类型并不是什么入口地址,而是给出了复位后 MSP 的初值,后面会具体讲解。

image

image

第55行:定义一块代码段,段名字是RESET,READONLY 表示只读。

第56-58行:使用EXPORT将3个标识符申明为可被外部引用,声明 __Vectors、__Vectors_End 和__Vectors_Size 具有全局属性。

第60行:__Vectors 表示向量表起始地址,DCD 表示分配 1 个 4 字节的空间。每行 DCD 都会生成一个 4 字节的二进制代码,中断向量表 存放的实际上是中断服务程序的入口地址。当异常(也即是中断事件)发生时,CPU 的中断系统会将相应的入口地址赋值给 PC 程序计数器,之后就开始执行中断服务程序。在60行之后,依次定义了中断服务程序的入口地址。

第138行:__Vectors_End 为向量表结束地址。

第139行:__Vectors_Size则是向量表的大小,向量表的大小是通过__Vectors 和__Vectors_End 相减得到的。

2.3 复位程序

复位程序是系统上电后执行的第一个程序,复位程序也是中断程序,只是这个程序比较特殊,因此单独提出来讲解。

image

第145行:定义了一个服务程序,PROC表示程序的开始。

第146行:使用EXPORT将Reset_Handler申明为可被外部引用,后面WEAK表示弱定义,如果外部文件定义了该标号则首先引用该标号,如果外部文件没有声明也不会出错。这里表示复位程序可以由用户在其他文件重新实现,这种写法在HAL库中是很常见的。

第147-148行:表示该标号来自外部文件,SystemInit()是一个库函数,在system_stm32f1xx.c中定义的,__main 是一个标准的 C 库函数,主要作用是初始化用户堆栈,这个是由编译器完成的,该函数最终会调用我们自己写的main函数,从而进入C世界中。

第149行:这是一条汇编指令,表示从存储器中加载SystemInit到一个寄存器R0的地址中。

第150行:汇编指令,表示跳转到寄存器R0的地址,并根据寄存器的 LSE 确定处理器的状态,还要把跳转前的下条指令地址保存到 LR。

第151行:和149行是一个意思,表示从存储器中加载__main到一个寄存器R0的地址中。

第152行:和150稍微不同,这里跳转到至指定寄存器的地址后,不会返回。

第152行:和150稍微不同,这里跳转到至指定寄存器的地址后,不会返回。

2.4 中断服务程序

我们平时要使用哪个中断,就需要编写相应的中断服务程序,只是启动文件把这些函数留出来了,但是内容都是空的,真正的中断复服务程序需要我们在外部的 C 文件里面重新实现,这里只是提前占了一个位置罢了。

image

这部分没啥好说的,和服务程序类似的,只需要注意‘B .’语句,B表示跳转,这里跳转到一个‘.’,即表示无限循环。

2.5 堆栈初始化

堆栈初始化是由一个IF条件来实现的, MICROLIB的定义与否决定了堆栈的初始化方式。

这个定义是在Options->Target中设置的。

image

如果没有定义__MICROLIB , 则会使用双段存储器模式,且声明了__user_initial_stackheap 具有全局属性,这需要开发者自己来初始化堆栈。

image

这部分也没啥讲的,需要注意的是,ALIGN表示对指令或者数据存放的地址进行对齐,缺省表示4字节对齐。

2.6 其他

image

第50行:PRESERVE8 用于指定当前文件的堆栈按照 8 字节对齐。

第51行:THUMB 表示后面指令兼容 THUMB 指令。现在 Cortex-M 系列的都使用 THUMB-2 指令集,THUMB-2 是 32 位的,兼容 16 位和 32 位的指令,是 THUMB 的超集。









参考文章:

[深入剖析STM32]STM32 启动流程详解 - 知乎 (zhihu.com)

标签:__,初始化,启动,流程,程序,STM32,地址
From: https://www.cnblogs.com/Wangzx000/p/17902410.html

相关文章

  • 创建一个Redis集群的启动命令并启动
    第一步:进入到存放集群的目录里cd/opt/cluster如下图[红线圈中的目录]:第二步:在此目录创建sh文件[示例为start.sh],并打开编辑vimstart.sh第三步:在文件中,写入要执行的所有Redis端口命令`redis-server/opt/cluster/6001/redis.confredis-server/opt/cluster/6002/redis.c......
  • Scrum项目管理流程及免费敏捷工具
    ​项目启动: 团队明确项目愿景、目标和范围,确定项目范围和优先级,并建立团队以及开展初步计划。制定产品待办事项清单(ProductBacklog): 定义项目所需功能、任务和需求列表,并按优先级排序。Sprint计划会议: 团队根据产品待办事项清单,从中选择并确认需要在当前迭代(Sprint)中......
  • STM32在CTF中的应用和快速解题
    题目给的是bin文件,基本上就是需要我们手动修复的固件逆向。如果给的是hex文件,我们可能需要使用MKD进行动态调试主要还是以做题为目的详细的可以去看文档:https://pdf1.alldatasheet.com/datasheet-pdf/view/201596/STMICROELECTRONICS/STM32F103C8T6.htmlSVD文件下载:https://gi......
  • window10下ubuntu系统安装docker服务启动不起来问题排查解决。
    https://blog.csdn.net/VeryLost/article/details/128611800 因为最新版的ubuntu系统使用了iptables-nft,而WSL2不支持导致的。需要使用如下命令修改信息:root@username:/#update-alternatives--configiptablesThereare2choicesforthealternativeiptables(providing......
  • SpringBoot中项目启动及定时任务缓存数据库常用数据至内存变量并转换后高频调用
    场景定时任务中需要获取数据库中数据进行数据转换成需要的格式并进行后续的业务处理。数据库中的数据更新频率不高。可将数据库中数据在项目启动后读取一遍数据,然后再通过定时任务定时查询数据库更新数据。实现数据库缓存的方式有多种,比如以下:SpringBoot中通过自定义缓存注解......
  • Delphi Android程序启动过程
    文章转载于不得闲大师的文章,源文链 https://www.cnblogs.com/DxSoft/p/4460236.html Delphi的Android程序是原生的程序,也就是NativeActivity。那么就需要先看一下NativeActivity的原理,在AndroidManifest.xml文件里面指定入口activity为nativeactivity,这样应用程序一启动,jav......
  • 利用CRM优化LTC流程——企业客户管理的新模式探讨
     在现代商业环境下,将潜在客户转化成实际销售是公司成功的基石之一。而CRM管理系统是完成LTC的有效工具。本文将向您介绍LTC是什么?公司怎样企业如何通过CRM实现这一流程的?LTC(从线索到现金)是企业运营管理中的一个重要概念,包括从获取销售线索到提供解决方案、签署商业合同、进行......
  • php底层代码执行流程
    PHP在底层(C语言层面)的代码执行流程可以大致分为以下几个步骤:解析器初始化:当PHP服务启动时,会调用解析器(ZendEngine)的初始化函数进行初始化,包括各种全局变量的初始化,内存池的初始化。文件读取和解析:解析器会读取并解析PHP文件,将其转换为语法树,并将其中的函数和变量信息保......
  • 万界星空科技MES系统中的生产调度流程
     MES系统生产调度的目标是达到作业有序、协调、可控和高效的运行效果,作业计划的快速生成以及面向生产扰动事件的快速响应处理是生产调度系统的核心和关键。为了顺利生成作业计划,需要为调度系统提供完整的产品和工艺信息,MES系统生成作业计划后以友好的界面进行呈现,制造执行过程......
  • 流程控制
    流程控制可以通过控制语句实现更丰富的逻辑以及更强大的功能。几乎所有编程语言都有流程控制语句,功能也都基本相似。其流程控制方式有顺序结构分支结构循环结构这里最简单最常用的就是顺序结构,即语句从上至下一一执行。序是由语句构成,而流程控制语句是用来......