【单片机开发】MCU三种启动方式(Boot选择)[主Flash/系统存储器(BootLoader)/嵌入式SRAM]

news2024/12/26 11:51:05

目录

参考资料:

利用 Boot 选择不同的启动方式:

单片机的存储结构(主 FLASH/系统存储器/嵌入式 SRAM):

1. Cortex-M 内核芯片——启动原理:

1.1. 启动流程:

1.2. 根据单片机的存储器映射和架构图:启动空间必须在代码区域(0x0000 0000 ~ 0x1FFF FFFF)

1.3. 地址映射原理: 存储器别名(memory alias)“技术

1.3.1. 举例

1.3.2. 引出一个问题:为什么可以从其他地址读 0x0000 0000 的中断向量表

1.3.3. 那么新的问题来:(怎么规定/配置内存重映射)

1.3.4. 问题:既然设置到0x0800 0000这么麻烦,为什么不直接使用0x0000 0000?

2. 根据不同的启动方式:会将配置的启动地址(主 FLASH/系统存储器/嵌入式 SRAM)映射到 0x0000 0000(系统中断向量表) 上

2.1. 从系统存储器(System Memory)启动:

2.2. 从主 Flash(Main Flash Memory)启动:这个是平时使用最多的方式,将程序下载到STM32内部Flash,然后从Flash启动。

【不是问题的问题】为什么STM32的Flash地址要设置到0x08000000 - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!

2.3. 从嵌入式 SRAM 启动(内部 SRAM):【比较好奇】

2.3.1. 为什么可以从 SRAM 启动:

至于为什么STM32还能从SRAM启动,ST官方资料https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf中的3.4节 给出的说明是:

请注意:从SRAM启动与在SRAM中运行代码是两个不同的概念。

2.3.2. 为什么需要从SRAM启动【应用】

2.3.3. 从 SRAM 启动:

实现原理:

实现步骤:MCU的三种启动方式 - EdgeAI Lab

2.3.4. 【补充】在 SRAM 中运行代码:

实现步骤:在SRAM中运行代码 - EdgeAI Lab


参考资料:

MCU的三种启动方式 - EdgeAI Lab

立芯嵌入式的视频

在SRAM中运行代码 - EdgeAI Lab

【不是问题的问题】为什么STM32的Flash地址要设置到0x08000000 - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!

还有一些在标题附近

利用 Boot 选择不同的启动方式:

单片机的存储结构(主 FLASH/系统存储器/嵌入式 SRAM):

如上图所示,STM32内部:

  • 一共有两块物理存储设备
    • 内部 Flash
    • 内部 SRAM
  • 三块存储区域
    • Main Flash Memory ——正常单片机启动方式(0x0800 0000~0x0807 FFFF)
    • System Memory ——一般存有 BootLoader 程序(0x1FFF 0000~0x1FFF 7A0F)

一般系统存储器又叫 BootROM

    • SRAM ——比较特殊,在不想影响 FLASH 程序下调试可用(0x2000 0000)

一般调试用,因为断电后数据会消失

    • 这三块存储区域也就是STM32的三个启动空间。

1. Cortex-M 内核芯片——启动原理:

1.1. 启动流程:

【不是问题的问题】为什么STM32的Flash地址要设置到0x08000000 - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!

  1. M3,M4内核芯片上电复位后,要固定从0x0000 0000地址读取中断向量表
  2. 获取复位中断服务程序的入口地址后,进入复位中断服务程序
  • 其中0x0000 0000是栈顶地址0x0000 0004存的是复位中断服务程序地址

1.2. 根据单片机的存储器映射和架构图:启动空间必须在代码区域(0x0000 0000 ~ 0x1FFF FFFF)

存储器指可以存储数据的设备(FLASH/SRAM/ROM),本身没有地址信息,对存储器分配地址的过程称为存储器映射

  • 单片机默认启动方式:
    • Cortex®-M3 CPU上电后(开始找中断向量表)
      • 默认从0x0000 0000地址处取得栈顶地址(MSP)
      • 通过ICode bus从0x0000 0004地址处取得PC的值(复位向量)
      • 然后开始执行代码(进入复位中断服务程序)
  • 因为ICode bus只能访问代码区域(0x0000 0000 ~ 0x1FFF FFFF),所以启动空间必须在代码区域

【ICode 总线】

1.3. 地址映射原理 存储器别名(memory alias)“技术

1.3.1. 举例

  • STM32内部Flash就位于代码区域(采用从主 FLASH 启动方式),并且通过“ 存储器别名(memory alias)“技术

代码区域——(0x0000 0000 ~ 0x1FFF FFFF)

主 FLASH——(0x0800 0000~0x0807 FFFF)

    • 可以将STM32的Main Flash Memory的地址空间0x0800 0000 ~ 0x0801 FFFF映射到0x0000 0000 ~ 0x0001 FFFF,对于System memory也是同样的道理。所以STM32可以从Main Flash Memory和System memory启动。

1.3.2. 引出一个问题:为什么可以从其他地址读 0x0000 0000 的中断向量表

  • 既然ARM规定了M3,M4内核要从地址0x0000 0000读取中断向量表,而STM32设置Flash地址到0x0800 0000怎么办?

  • 解决方法:
    • STM32支持了个内存重映射功能,将地址0x0800 0000开始的内容重映射到首地址0x0000 0000中,这样就解决了从0x0000 0000读取中断向量表的问题。

1.3.3. 那么新的问题来:(怎么规定/配置内存重映射)

  • 你怎么保证0x08000 0000首地址存的就是中断向量表,我们不可以随意设置吗?
  • 解决方法:
    • 保证中断向量表存到0x0800 0000,这个涉及到分散加载的一个小知识
    • 以MDK为例:
      • 如果大家看xxx.S启动文件,里面通过AREA定义了一个名叫RESET的段,这段存的就是中断向量表。
; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size
      • 这个名字很重要,MDK对应的xxx.sct分散加载里面通过下面这句将这个RESET段放在了0x0800 0000优先存储。
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM2 0x24000000 0x00080000  {  ; RW data
   .ANY (+RW +ZI)
  }
}
      • 这样我们就解决了0x0800 0000首地址存储中断向量表,一旦程序开始运行后,我们就可以随意设置中断向量表的位置了。
      • 比如想将中断向量表存到内部SRAM,我们就可以操作寄存器SCB->VTOR 重新安排,然后将0x0800 0000的内容复制到设置的地址内即可。【上电启动后,改为从内部 SRAM 启动】

1.3.4. 问题:既然设置到0x0800 0000这么麻烦,为什么不直接使用0x0000 0000?

  • 因为我们需要从不同的地址启动,以达到不同的启动程序(BootLoader 程序/正常 APP 应用程序)
  • M3、M4 内核:

  • M7 内核

2. 根据不同的启动方式:会将配置的启动地址(主 FLASH/系统存储器/嵌入式 SRAM)映射到 0x0000 0000(系统中断向量表) 上

2.1. 从系统存储器(System Memory)启动:

System Memory中是ST预置的bootloader程序,用于通过串口下载用户程序到Flash。

一般系统存储器启动的话会存放 BootLoader 程序

程序下载完毕后,重新将启动模式设置为 “从Flash启动” ,然后开机运行用户程序。

【BootLoader】当选择系统存储器启动,从 0x0000 0000 跳转至对应地址启动(映射),

我们可以提前在系统存储器写入 BootLoader 程序(各种通信接口)的,然后以该方式启动

此时用 IAP 下载工具烧录程序,单片机执行 BootLoader 程序,会以对应的通信接口返回指定数据,符合通信要求后(收发特定数据)。

IAP 下载工具开始发送烧录程序(hex 文件),由单片机的 BootLoader 程序(利用对应通信接口)一一接收,然后逐个刷新到 Flash 上(Flash memory-主 Flash[0x0800 0000 - 0x0807 FFFF = 512KB 标定大小 ]),

一般出厂会自带 Boot 程序,一般系统存储器又叫 BootROM

2.2. 从主 Flash(Main Flash Memory)启动:这个是平时使用最多的方式,将程序下载到STM32内部Flash,然后从Flash启动。

【不是问题的问题】为什么STM32的Flash地址要设置到0x08000000 - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!

还是将 0x0800 0000 映射到 0x0000 0000(由 AHB 总线映射)

2.3. 从嵌入式 SRAM 启动(内部 SRAM):【比较好奇】

在SRAM中运行代码 - EdgeAI Lab

2.3.1. 为什么可以从 SRAM 启动:

至于为什么STM32还能从SRAM启动,ST官方资料https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf中的3.4节 给出的说明是:

STM32F10xxx微控制器实现了一个特殊的机制使得STM32不仅能够从Flash memory 和 System memory启动,也能够从SRAM启动。从内嵌SRAM启动:SRAM仅能在地址0x2000 0000处被访问。

STM32F10xxx microcontrollers implement a special mechanism to be able to boot also from SRAM and not only from main Flash memory and System memory.Boot from the embedded SRAM: SRAM is accessible only at address 0x2000 0000.

以上说明并不清楚,ST官方对此含糊其辞,从SRAM启动的具体细节无从知晓,但是通过实验我们发现:

  1. 将STM32设置为从SRAM启动(a. 配置启动模式引脚BOOT0=1,BOOT1=1;b. 并修改链接脚本将所有代码全部放入SRAM中
  2. 系统复位后PC指针总是指向0x2000 0108
  3. 所以我们在地址0x2000 0108插入设置SP指针和PC指针的指令就可以实现从SRAM启动了。

请注意:从SRAM启动与在SRAM中运行代码是两个不同的概念。
  • 从SRAM启动
    • 也属于在SRAM中运行代码,但不同的是程序下载到SRAM后,在MCU不断电的情况下,程序可以一直运行,并且按下复位键后可以重新运行。
  • 在SRAM中运行代码
    • 将所有的代码放到SRAM运行,此时MCU的启动模式可以是从Main Flash Memory启动
    • 将部分代码放到SRAM运行,此时MCU的启动模式可以是从Main Flash Memory启动
    • 关于在SRAM中运行代码,请参考这篇文章:在SRAM中运行代码 - EdgeAI Lab

2.3.2. 为什么需要从SRAM启动【应用】

可能的原因有以下几点(参考资料《ARM Cortex M3 & M4权威指南》15.7节MCU经典书籍 - EdgeAI Lab):

  1. 所使用的设备可能具有OTP ROM(仅可进行一次编程),因此在最终确定前,是不会将程序编程到芯片中的。
  2. 有些微控制器中没有内部Flash存储器,需要使用外部的存储器,在软件开发期间,可能会想用内部的SRAM进行测试。
  3. 对于产品测试或者特定方面的测试,不想改动Flash中现有的程序实现某些新功能的测试工作,此时可以将测试代码下载到SRAM中运行。【在 Flash 烧一次后,不想改变现有 Flash 程序,但是想调试,可以利用 SRAM 空间进行调试】
  4. 对于Flash存储器比较小的系统,可能想在启动阶段将程序从Flash复制到SRAM中以提高性能,并在SRAM中执行程序以达到最佳性能。
  5. 在 SRAM 中也是可以放一个小的 BootLoader 程序,也可以搞 IAP 下载【应用案例:Jlink 下载算法启动后跑到 SRAM 中

2.3.3. 从 SRAM 启动:

实现原理:
  • 还是将 0x2000 0000 映射到 0x0000 0000(由 AHB 总线映射)

实现步骤:MCU的三种启动方式 - EdgeAI Lab

拿 M3(F103C8T6,RAM大小为20K) 举例

  1. 修改启动模式

将引脚BOOT0,BOOT1都设置为1,将STM32配置为从SRAM启动。

  1. 设置中断向量表偏移

添加宏定义 VECT_TAB_SRAM

  • 该宏定义影响的代码:
// system_stm32f10x.c
// SystemInit()
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
  1. 修改启动代码

按照如下所示修改startup_stm32f10x_md.s文件

; 此处省略n行代码

; Vector Table Mapped to Address 0 at Reset
; 此处修改AREA    RESET, DATA, READONLY 为 AREA    RESET, CODE, READONLY
                AREA    RESET, CODE, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __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

                ; 此处省略n行代码

                DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend

; 下面是需要新添加的内容:
                DCD     0
                DCD     0
                DCD     0
                DCD     0
                DCD     0
                DCD     0
                DCD     0
                LDR       R0, =0x20000000
                LDR     SP,[R0]
                LDR     R0, =0x20000004 
                LDR       PC,[R0]
                ALIGN 4
; 以上是需要添加的代码

; 此处省略n行代码
  1. 修改链接脚本

按照下图所示方式,即可在Keil编辑器中打开链接脚本:

打开链接脚本文件后,将内容修改如下:

; 以STM32F103C8T6为例
; 从SRAM启动终端向量表(RESET段)必须位于启动空间的0地址
; InRoot$$Sections 必须位于root区域(执行地址与装载地址相同的区域)

LR_IROM1 0x20000000 0x00005000  { ;装载地址为SRAM首地址
  RW_IRAM1 0x20000000 0x00005000  { ;执行地址==装载地址
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
   .ANY (+RW +ZI)
  }
}
  1. 修改Keil中的Flash Download设置

因为是直接从SRAM启动并执行程序,不需要对Flash进行操作,所以把Flash相关操作全部去掉。


  • 以上就是完整的配置,现在编译项目并点击调试,就能看到程序成功在SRAM中运行了。
  • 关闭调试后,只要STM32不断电,SRAM中的程序就可以一直运行,并且按下复位键后程序会重新运行。

2.3.4. 【补充】在 SRAM 中运行代码:

实现步骤:在SRAM中运行代码 - EdgeAI Lab

我的原文笔记:https://www.yuque.com/u41716106/ni1clp/bhxgk39vmaev9p26?singleDoc#

《【个人理解】MCU三种启动方式(Boot选择)[主Flash/系统存储器(BootLoader)/嵌入式SRAM]》

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言(指针基础2练习)

利用指针变量将一个数组中的数据反向输出。 #include <stdio.h>void rev(int *arr, int size) {int *end arr size - 1;for (int *ptr end; ptr > arr; ptr--){printf("%-3d", *ptr);}printf("\n"); } void get(int arr[], int len) {for (in…

微信小程序web-view 嵌套h5界面 实现文件预览效果

实现方法&#xff1a;(这里我是在小程序里面单独加了一个页面用来下载预览文件) 安装 使用方法请参考文档 npm 安装 npm install weixin-js-sdk import wx from weixin-js-sdk预览 h5界面代码 <u-button click"onclick" type"primary" :loading"…

C—初阶调试

对你有帮助的话能否一键三连啊&#xff01;祝每个人心想事成&#xff01; 什么是Bug? 首先我们先了解一下日常口语中的“Bug”是什么 Bug可以理解为计算机程序错误&#xff0c;编程时的漏洞 调试及重要性 顾名思义&#xff0c;调试就是通过工具找出bug存在&#xff0c;找出…

vs打开unity项目 新建文件后无法自动补全

问题 第一次双击c#文件自动打开vs编辑器的时候能自动补全&#xff0c;再一次在unity中新建c#文件后双击打开发现vs不能自动补全了。每次都要重新打开vs编辑器才能自动补全&#xff0c;导致效率很低&#xff0c;后面发现是没有安装扩展&#xff0c;注意扩展和工具的区别。 解决…

中间件--MongoDB部署及初始化js脚本(docker部署,docker-entrypoint-initdb.d,数据迁移,自动化部署)

一、概述 MongoDB是一种常见的Nosql数据库&#xff08;非关系型数据库&#xff09;&#xff0c;以文档&#xff08;Document&#xff09;的形式存储数据。是非关系型数据库中最像关系型数据库的一种。本篇主要介绍下部署和数据迁移。 在 MongoDB 官方镜像部署介绍中&#xff…

基于大模型的 AI Agent 技术框架全解析

一、AI Agent 与大语言模型&#xff1a;智能时代的双璧合辉 &#xff08;一&#xff09;AI Agent&#xff1a;智能化浪潮的引领者 在科技迅猛发展的当下&#xff0c;AI Agent 作为一种能够自主感知环境、决策并行动的智能系统&#xff0c;正引领着智能化的新潮流。与传统智能系…

5.ABAP结构体和内表

总学习目录请点击下面连接 SAP ABAP开发从0到入职&#xff0c;冷冬备战-CSDN博客 目录 5.1.结构化数据对象 定义 如何引用结构化的数据对象 拷贝 实战练习 创建 拷贝 调试代码 5.2.内表 行类型 键 表种类 存取类型 表类型 如何在本地定义表类型 内表三种可能的…

3D 生成重建030-SV3D合成环绕视频以生成3D

3D 生成重建030-SV3D合成环绕视频以生成3D 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 论文提出了Stable Video 3D (SV3D)——一个用于生成围绕三维物体的高分辨率图像到多视角视频的潜在视频扩散模型。最近关于三维生成的文献提出了将二维生成模型应用于新视图合成…

中介者模式的理解和实践

一、中介者模式概述 中介者模式&#xff08;Mediator Pattern&#xff09;&#xff0c;也称为调解者模式或调停者模式&#xff0c;是一种行为设计模式。它的核心思想是通过引入一个中介者对象来封装一系列对象之间的交互&#xff0c;使得这些对象不必直接相互作用&#xff0c;从…

【蓝桥杯每日一题】砍竹子

砍竹子 2024-12-7 蓝桥杯每日一题 砍竹子 STL 贪心 题目大意 这天, 小明在砍竹子, 他面前有 nn 棵竹子排成一排, 一开始第 ii 棵竹子的 高度为 h i h_i hi​. 他觉得一棵一棵砍太慢了, 决定使用魔法来砍竹子。魔法可以对连续的一 段相同高度的竹子使用, 假设这一段竹子的高度为…

泷羽sec-burpsuite(5)app渗透测试(上) 学习笔记

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

从一个Bug谈前端响应拦截器的应用

一、问题场景 今天在开发商品管理系统时&#xff0c;遇到了一个有趣的问题&#xff1a;当添加重复的商品编号时&#xff0c;页面同时弹出了两条 "商品编号已存在" 错误提示&#xff1a; 这个问题暴露了前端错误处理机制的混乱&#xff0c;让我们从这个问题出发&…

量子变分算法---损失函数

引子 关于损失函数&#xff0c;我们知道在强化学习中&#xff0c;会有一个函数&#xff0c;用来表示模型每一次行为的分数&#xff0c;通过最大化得分&#xff0c;建立一个正反馈机制&#xff0c;若模型为最优则加分最多&#xff0c;若决策不佳则加很少分或者扣分。而在神经网络…

车间的图纸在传输过程的安全怎么保障?

车间的图纸在传输过程的安全保障&#xff0c;要从很多方面出发分析&#xff0c;本文从以下几点为大家列出几个&#xff0c;看看有没有你想知道的呢~ 1、采用先进的图纸加密软件 采用先进的加密算法对图纸进行加密处理&#xff0c;确保图纸文件在存储、传输和使用过程中的安全性…

MQTT消息服务器mosquitto介绍及说明

Mosquitto是一个开源的消息代理软件&#xff0c;支持MQTT协议&#xff08;消息队列遥测传输协议&#xff09;。MQTT是一种轻量级的发布/订阅消息传输协议&#xff0c;专为低带宽、不可靠网络环境下的物联网设备通信而设计。以下是关于Mosquitto服务器的一些介绍和说明&#xff…

想在iPad上远程操作安卓手机的APP,怎样实现iPad远程控制安卓?

学生党或互联网行业的打工人&#xff0c;人手连三台电子设备也很常见&#xff0c;手机、平板还有笔记本电脑一大堆&#xff0c;如果出门要全带上&#xff0c;背包压力也变大。 有没有想过用远程控制功能&#xff0c;让iPad远程控制安卓手机&#xff1f;这样做&#xff0c;出门就…

VBA高级应用30例应用在Excel中的ListObject对象:向表中添加注释

《VBA高级应用30例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…

Spring源码分析之Bean的实例化(createBeanInstance())

前言: 通过Spring源码分析之Bean的创建过程(createBean)-CSDN博客我们可以知道如果没有动态代理以及循环依赖的前提之下的话那么一个普通的单例Bean的创建后就是实例化,属性填充,初始化这三个步骤那么这篇文章的话我们就先说一下实例化也就是doCreateBean方法里面的createBeanI…

一次“okhttp访问间隔60秒,提示unexpected end of stream“的问题排查过程

一、现象 okhttp调用某个服务&#xff0c;如果第二次访问间隔上一次访问时间超过60s&#xff0c;返回错误&#xff1a;"unexpected end of stream"。 二、最终定位原因&#xff1a; 空闲连接如果超过60秒&#xff0c;服务端会主动关闭连接。此时客户端恰巧访问了这…

蓝桥杯准备训练(lesson5 ,c++)

单目操作符与第 2 章 C/C输⼊输出&#xff08;上&#xff09; 8. 单⽬操作符8.1 和--8.1.1 前置 和 后置8.1.2 前置-- 和 后置-- 8.2 和 - 第 2 章 C/C输⼊输出&#xff08;上&#xff09;1. getchar 和 putchar1.1 getchar()1.2 putchar() 2. scanf 和 printf2.1 printf2.1.1…