【STM32】STM32内存映射以及启动过程(超详细过程)

这篇具有很好参考价值的文章主要介绍了【STM32】STM32内存映射以及启动过程(超详细过程)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、内存映射

1、内存映射图

下图是 STM32F103xCDE 型号的内存映射图。

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

2、内存划分

由于 STM32 是 32 位,且其地址总线也为 32 根,所以其理论能够寻找的地址大小为 4GB

从上图可以看出,左边的地址从 0x0000 0000 ~ 0xFFFF FFFF 的 4GB 是 STM32 理论分配的地址空间,STM32 实际上的空间大小 远远小于 4GB 的。4GB 中又划分出了 8 个块,一块占 512MB,分别作为 代码区、SRAM区、外设区、FSMC1区、FSMC2区、FSMC寄存器区、未使用区、Cortex-M3内部外设区。

3、存储器映射

映射其实就是对应的意思。事实上存储器本身并不具备地址,将芯片理论上的地址分配给存储器,这就是存储器映射。STM32 的所有片内外设其实都是存储器,所以所有的这些存储器都需要被映射。

理论上地址起始就是门牌号,存储中的每个字节就是房间,存储器生产出来后,这些房间是没有地址的(门牌号),映射的过程其实就是将这些门牌号分配给这些房间,分配好后,每个门牌号只能访问自己的房间,没有被分配的地址就是保留地址,所谓保留地址的意思就是,没有对应实际存储空间。

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

STM32 片内的 FLASH 分成两部分:主存储块、信息块。

  • 主存储块
    • 主Flash:用于存储程序,我们写的程序一般存储在这里。
  • 信息块
    • 系统存储器(系统FLASH):存放在系统存储器自举模式下的启动程序(BootLoader),当使用 ISP 方式加载程序时,就是由这个程序执行。这个区域由芯片厂写入 BootLoader,然后锁死,用户是无法改变这个区域的
    • 选项字节:存储芯片的配置信息及对主存储块(主Flash)的保护信息。

STM32F103VET6 芯片的主Flash 的内存空间范围是 0x0800 0000 ~ 0x0807 FFFF,共 512KB。

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

4、寄存器映射

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

在 block2 外设区,也就是地址从 0x4000000 ~ 0x5FFFFFF 这块区域,设计的是片上外设,它们以四个字节为一个单元,共32bit,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。可以找到每个单元的起始地址,然后通过C语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,聪明的工程师就根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

5、地址重映射

自举(bootstrap)计算机设备使用硬件加载的程序,用于初始化足够的软件来查找并加载功能完整的操作系统。也用来描述加载自举程序的过程。什么是单片机的自举,单片机的自举就是单片机的启动

而众所周知,单片机在每次上电时都是从 0 地址开始执行,那么这就存在一个问题,我们下载程序时是将代码放在 主Flash ,其地址为 0x0800 0000 ~ 0x0807 FFFF,起始地址并不在 0 地址,那单片机要如何找到代码并执行呢?

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

在地址划分的区域可以看出,0x0000 0000 ~ 0x0007 FFFF 这块区域的功能是专门进行地址重映射的,而要进行重映射的区域取决于 BOOT 引脚,通过 BOOT1 和 BOOT0 引脚的电平值,可以选择将0x0000 0000 ~ 0x0007 FFFF 映射到不同的存储器上
这就解释了为什么我们在 keil 中设置好程序的下载地址为 0x8000000,但是单片机上电是确实从 0 开始执行。是因为我们在硬件上设置了 BOOT0=0,BOOT1=X,从而导致了主FLASH 区被映射到了0x0000 0000 ~ 0x0007 FFFF(512KB),故而代码是下载到 0x80000000 往后的存储空间中,却说运行又是从 0x00000000 地址运行的。

5.1 STM32启动模式

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

  • 主FLASH启动:将主 Flash 地址 0x0800 0000 映射到 0x0000 0000,这样代码启动之后就相当于从 0x08000000 开始。一般使用 JTAG 或者 SWD 模式下载程序时,就是下载到这个里面,重启后也直接从这启动程序。
  • 系统存储器启动:从系统存储器地址 0x1FFF F000 开始执行代码。系统存储器是芯片内部一块特定的区域,芯片出厂时在这个区域预置了一段 Bootloader,就是通常说的 ISP 程序。这个区域的内容在芯片出厂后没有人能够修改或擦除,即它是一个 ROM 区。启动的程序功能由厂家设置。系统存储器存储的其实就是 STM32 自带的 bootloader 代码。
  • 内置SRAM启动:将 SRAM 地址 0x20000000 映射到 0x00000000,这样代码启动之后就相当于从 0x20000000 开始。内置 SRAM,也就是STM32的内存,既然是SRAM,自然也就没有程序存储的能力了,这个模式一般用于程序调试。假如我只修改了代码中一个小小的地方,然后就需要重新擦除整个Flash,比较的费时,可以考虑从这个模式启动代码,用于快速的程序调试,等程序调试完成后,在将程序下载到SRAM中

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

6、程序烧录方式

6.1 ISP(串口烧录)

  • BOOT0 = 1,BOOT1 = 0
  • 启动地址:0x1FFF F000
  • 使用串口下载程序
  • 系统存储器(系统Flash)启动方式运行内置的 Bootloader,将程序写入主存储区(主Flash)
  • 重启后,需要再将 BOOT0 拉低,从主存储区(主Flash)启动程序

6.2 ICP(SWD/JTAG接口烧录)

  • BOOT0 = 0,BOOT1 = x
  • 启动地址:0x0800 0000
  • 使用 JTAG 或者 SWD 模式下载程序
  • 主闪存存储器(主Flash)启动方式,将程序在主存储区写入
  • 重启后也直接从这启动程序

6.3 IAP

IAP 的原理与上面两种有较大区别,这种方式将主存储区又分成了两个区域(根据实际需要由开发者自行分配),0x0800 0000 起始处的这部分,存储一个开发者自己设计的 Bootloader 程序,另一部分存储真正需要运行的 APP 程序

单片机的 Bootloader 程序,其主要作用就是给单片机升级。在单片机启动时,首先从 Bootloader 程序启动,一般情况不需要升级,就会立即从 Bootloader 程序跳转到存储区另一部分的 APP 程序开始运行

假如 Bootloader 程序时,需要进行升级(比如APP程序运行时,接收到升级指令,可以在 flash 中的特定位置设置一个标志,然后触发重启,重启后进入 Bootloader 程序,Bootloader 程序根据标志位就能判断是否需要升级),则会通过某种方式(比如通过 WIFI 接收升级包,或借助另一块单片机接收升级包,Bootloader 再通过串口或 SPI 等方式从另一块单片机获取升级包数据)先将接收到的程序写入存储区中存储 APP 程序的那个位置,写入完成后再跳转到该位置,即实现了程序的升级
stm32内存映射,STM32,stm32,单片机,嵌入式硬件

二、启动过程

STM32 的片内 RAM 分为如下几个段:

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

1、概括

启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:

  1. 初始化堆栈指针 SP=_initial_sp
  2. 初始化 PC 指针=Reset_Handler
  3. 初始化中断向量表
  4. 配置系统时钟
  5. 调用 C 库函数 _main 初始化用户堆栈,从而最终调用 main 函数去到 C 的世界

2、栈初始化

// #define Stack_Size      0x00000400
Stack_Size      EQU     0x00000400
// STACK:段名;NOINIT:不初始化;READWRITE:可读可写;ALIGN=3:2^3,即 8 字节对齐
                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
// 栈的结束地址,即栈顶地址,需要保存栈顶的地址
__initial_sp
  • EQU宏定义的伪指令,相当于等于,类似与 C 中的 define。
  • AREA:告诉汇编器汇编一个新的代码段或者数据段
  • SPACE:用于分配一定大小的内存空间,单位为字节。这里指定大小等于 Stack_Size。

3、堆初始化

// #define Heap_Size       0x00000200
Heap_Size       EQU     0x00000200
// HEAP:段名;NOINIT:不初始化;READWRITE:可读可写;ALIGN=3:2^3,即 8 字节对齐
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
// 堆的起始地址
__heap_base
Heap_Mem        SPACE   Heap_Size
// 堆的结束地址
__heap_limit

                PRESERVE8
                THUMB
  • PRESERVE8:指定当前文件的堆栈按照 8 字节对齐。
  • THUMB:表示后面指令兼容 THUMB 指令。THUBM 是 ARM 以前的指令集,16bit,现在 Cortex-M 系列的都使用 THUMB-2 指令集,THUMB-2 是 32 位的,兼容 16 位和 32 位的指令,是 THUMB 的超集。

4、初始化向量表

4.1 开辟向量表空间

// RESET:段名;DATA:包含数据,不包含指令;READONLY:只读
AREA    RESET, DATA, READONLY
/* 声明 __Vectors、__Vectors_End 和 __Vectors_Size 这三个标号具有全局属性,
可供外部的文件调用 */
EXPORT  __Vectors
EXPORT  __Vectors_End
EXPORT  __Vectors_Size
  • EXPORT声明一个标号可被外部的文件使用,使标号具有全局属性。如果是 IAR 编译器,则使用的是 GLOBAL 这个指令。

4.2 初始化向量表

// __Vectors:向量表起始地址
__Vectors       DCD     __initial_sp               ; 栈顶地址
                DCD     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

                // 外部中断开始
                DCD     WWDG_IRQHandler            ; Window Watchdog
                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                
				// 限于篇幅,中间代码省略
				
                DCD     DMA2_Channel2_IRQHandler   ; DMA2 Channel2
                DCD     DMA2_Channel3_IRQHandler   ; DMA2 Channel3
                DCD     DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
// __Vectors_End:向量表结束地址
__Vectors_End
// 获得向量表大小
__Vectors_Size  EQU  __Vectors_End - __Vectors

向量表从 FLASH 的 0 地址(0x0800 0000)开始放置,以 4 个字节为一个单位,地址 0(0x0800 0000)存放的是栈顶地址,0x04 存放的是复位程序的地址,以此类推。从代码上看,向量表中存放的都是中断服务函数的函数名,可我们知道 C 语言中的函数名就是一个地址。

  • DCD分配一个或者多个以字为单位的内存,以四字节对齐,并要求初始化这些内存。在向量表 中,DCD 分配了一堆内存,并且以 ESR 的入口地址初始化它们。

4.3 复位中断程序初始化

// .text:段名;DATA:包含机器指令;READONLY:只读
AREA    |.text|, CODE, READONLY
                
// Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP

复位子程序是系统上电后第一个执行的程序,调用 SystemInit 函数初始化系统时钟,然后调用 C
库函数 _mian,最终调用 main 函数去到 C 的世界。

  • WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部文件没有声明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,这里并不是唯一的。
  • IMPORT表示该标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似。这里表示 SystemInit 和 __main 这两个函数均来自外部的文件。
    • SystemInit() :标准库函数,在 system_stm32f10x.c 这个库文件总定义。主要作用是配置系统时钟,这里调用这个函数之后,单片机的系统时钟配被配置为72M。
    • __main:标准的 C 库函数,主要作用是初始化用户堆栈,并在函数的最后调用 main 函数去到 C 的世界。这就是为什么我们写的程序都有一个 main 函数的原因。

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

4.4 其他中断程序初始化

/* 初始化默认中断程序(无限循环) */
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  TAMPER_IRQHandler          [WEAK]
                EXPORT  RTC_IRQHandler             [WEAK]
// 限于篇幅,中间代码省略
DMA2_Channel1_IRQHandler
DMA2_Channel2_IRQHandler
DMA2_Channel3_IRQHandler
DMA2_Channel4_5_IRQHandler
                B       .
                ENDP
                ALIGN
  • B跳转到一个标号。这里跳转到一个‘.’,即表示无限循环。
  • PROC:过程(子程序)的开始。
  • ENDP:过程(子程序)的结束。
  • ALIGN:对指令或者数据存放的地址进行对齐,后面会跟一个立即数。缺省表示 4 字节对齐。

4.5 用户堆栈初始化

/* 用户栈和堆初始化, 由 C 库函数 _main 来完成 */
				 // 这个宏在 KEIL 里面开启
				 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 ,如果定义了这个宏则赋予标号 __initial_sp(栈顶地址)、
__heap_base(堆起始地址)、__heap_limit(堆结束地址)全局属性,可供外部文件调用。然后堆栈的初始化就由 C 库函数 _main 来完成
如果没有定义 __MICROLIB,则才用双段存储器模式,且声明标号 __user_initial_stackheap 具有全局属性,让用户自己来初始化堆栈

stm32内存映射,STM32,stm32,单片机,嵌入式硬件

  • IF,ELSE,ENDIF:汇编的条件分支语句,跟C 语言的if ,else 类似。
  • END:文件结束

参考资料:
https://zhuanlan.zhihu.com/p/511268958
https://zhuanlan.zhihu.com/p/367821312文章来源地址https://www.toymoban.com/news/detail-516541.html

到了这里,关于【STM32】STM32内存映射以及启动过程(超详细过程)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32启动过程浅析

    MDK编译过程文件(11种) .o:可重定向对象文件,每个.c、.s文件编译后都生成一个.o文件 .axf:可执行对象文件,由.o文件链接生成,仿真的时候需要用到此文件 .hex:INTEL Hex格式文件,用于下载到MCU运行,由.axf转换而来 .map:连接器生成的列表文件,对分析程序存储占用情况

    2024年02月20日
    浏览(23)
  • STM32引脚定义表以及重映射的使用方法

    首先STM32的引脚图: 1. 表格颜色: 橙色是电源相关引脚。 蓝色是最小系统相关的引脚 绿色是IO口,功能这些引脚。 2. 类型: S代表电源,I代表输入,O代表输出,IO代表输入输出 3.I/O 口电平( 表示它能容忍的的电压 ): FT 是代表能容忍5v电压。 没有FT就代表只能容忍3.3V电压

    2024年02月07日
    浏览(33)
  • 【10】STM32·HAL库开发-MAP文件解析 | STM32启动过程

    该篇文章参考资料为: STM32 MAP文件浅析.pdf STM32 启动文件浅析.pdf Cortex-M3权威指南(中文).pdf   MDK编译会产生一些中间文件,在之前新建MDK工程时使其输出到了【Output】文件夹,总共有11种,如下表所示: MAP文件是MDK编译代码后,产生的集程序、数据及IO空间的一种映射列表

    2024年02月16日
    浏览(25)
  • 单片机 STM32启动文件详解(汇编语言解析)

    以前讲了固件库,从ST官网下载的固件库里面,有许多的启动文件(汇编语言写的.s文件) 启动文件 说明 startup_stm32f10x_ld.s Low Density 小容量 startup_stm32f10x_md.s Medium Density 中容量 startup_stm32f10x_hd.s High Density 高容量 startup_stm32f10x_xl.s Extra Large Density 超大容量 startup_stm32f10x_cl.s Con

    2023年04月25日
    浏览(41)
  • stm32启动过程(以F1为例)

    M3/M4/M7等内核复位后,做的第一件事: 从地址 0x0000 0000 处取出 堆栈指针 MSP 的初始值,该值为栈顶地址 从地址 0x0000 0004 处取出 程序计数器指针 PC 的初始值,该值是复位向量(Reset_Hander) 通过BOOT0和BOOT1两个引脚的输入选择启动模式 在系统复位后,sysclk的第4个上升沿,BOO

    2023年04月19日
    浏览(19)
  • 【嵌入式学习笔记】嵌入式基础9——STM32启动过程

    程序段交叉引用关系(Section Cross References):描述各文件之间函数调用关系 删除映像未使用的程序段(Removing Unused input sections from the image):描述工程中未用到被删除的冗余程序段(函数/数据) 映像符号表(Image Symbol Table):描述各符号(程序段/数据)在存储器中的地址、类

    2024年02月15日
    浏览(63)
  • 为什么STM32设置Flash地址0x08000000而不是0x00000000?STM32的启动过程

    在MDK编译程序设置ROM和RAM地址时候发现: IROM1为片上程序存储器,即片上集成的Flash存储器,对该处理器Flash大小为512KB,即0x80000 地址区间为0x8000000~0x0807FFFF IRAM1为片上数据存储器,即片上集成的SRAM存储器,对该处理器RAM大小为64KB,即0x10000 地址区间为0x20000000~0x20010000 这里问

    2024年01月16日
    浏览(37)
  • MATLAB /Simulink 快速开发STM32(使用st官方工具 STM32-MAT/TARGET),以及开发过程

    配置好环境以后就是开发: stm32cube配置芯片,打开matlab添加ioc文件,写处理逻辑,生成代码,下载到板子中去。 配置需要注意事项: STM32CUBEMAX6.5.0 + MABLAB2022B+keilV5.2 Matlab生成的代码CTRL+B 其中关键的配置有哪些,如图: untitledtest_stm32是matlab生成的代码

    2024年02月14日
    浏览(36)
  • STM32启动详细流程分析(一)

      大家不妨设想一下,cpu 的工作是什么,cpu 是没有主观意识的,它只会按照特定的指令执行相应的操作,用专业术语来说就是: 取指 - 译码 - 执行 ,译码和执行肯定是在 cpu 内部进行操作的,并且前提是已经取到了指令。那现在问题来了,指令在哪? cpu上电复位后执行的第

    2024年02月12日
    浏览(28)
  • STM32内存分配以及堆栈、变量、代码等的存储位置理解与分析

    文中不足之处,欢迎各位同仁批评指正!         STM32的程序存储器、数据存储器、寄存器和输入输出端口被组织在同一个4GB的线性地址空间内, 地址范围为0x0000 0000至0xFFFF FFFF。其中FLASH为ROM类型,储存的数据掉电不易失;RAM中存储的数据掉电易失。以STM32F103系列为例,最多

    2024年02月03日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包