STM32启动详细流程之必备知识

1.前提准备与提示

1.1. 前提准备

阅读博客之前,你需要一些准备工作

F1参考手册,F1数据手册,F4参考手册,F4数据手册,Flymcu(串口下载软件),正点原子Alientek的原理图。

1.2. 提示

  • 本系列博客的讲述方式将严格按照引言中的流程
  • 本系列博客中会用到很多F4相关的资料(F1相关资料不全)
  • 基于问题的猜想可能是正确的也可能是错误的!!!
  • 博客中出现的资料都在前提准备中有提到,如果找不到可以联系我
  • 联系方式 QQ:2567434944
  • 实验前的必备知识你只需记住就行,不需要知道为什么,因为在验证猜想的过程中就会解释原因
  • 可以博客视频一起观看

2.问题

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

cpu上电复位后执行的第一步操作就是取指令

  • 问题1:指令存储在何处

我们在电脑上编写的程序最终是要烧写到芯片内部的FLASH中(此处特指STM32)

  • 问题2:如何将可执行文件烧写至FLASH上

STM32的启动方式有很多种,从主存FLASH启动,从system memory启动,从SRAM中启动。

  • 问题3:从SRAM中启动,为什么需要重新设置中断向量表

接下来,我们将围绕这三个问题进行解答

3.猜想

既然cpu上电复位后第一步操作就是取指令,那么这个指令肯定是存储在掉电不丢失的存储介质上(rom、flash)。

  • 猜想1:指令存储在掉电不丢失的存储介质上

我们最终生成的、cpu可以执行的可执行文件肯定是要通过某种外设将用户程序烧写到FLASH上,这一点肯定是毋庸置疑的,因为cpu与外围设备进行数据交互的时候是通过外设控制器来进行的。

  • 猜想2:通过某种外设将可执行文件烧写至FLASH上

STM32的FLASH基地址为0X0800 0000,SRAM基地址为0X2000 0000。可不可能是因为这两个存储介质的地址不同,所以才要重新设置中断向量表。

因为我们都知道,中断向量表的首地址就是程序的入口地址

  • 猜想3:可能与基地址有关

4.实验验证

4.1. 实验前必备知识

4.1.1. XIP设备

eXecute In Place,即芯片内执行,指应用程序可以直接在flash闪存内运行,不必再把代码读到系统RAM中。在我们的印象里,应用程序必须要从硬盘中加载到内存当中才可以被运行,但实际上应用程序是可以直接在flash闪存运行的,也就是说,cpu可以直接从flash中取出指令。对于STM32而言,它是有XIP设备的。

STM32F1内存图

如上图所示,FLASH、SYSTEM MEMORY、OPTION BYTES 都是STM32内部的XIP设备。

F1内存图信息不是很全,再看下F4的内存图。

STM32F4内存图:

我们可以看到,不论是F1还是F4,XIP设备都属于内存图中的BLOCK0区域内。

这样我们大概就知道了STM32内部的XIP设备在0x0000 0000 ~ 0x1FFF FFFF内。

上述的内存图是通过映射的方式将芯片的框图进行映射得到的,也就是说,上述这幅图是为了开发人员更好地面向芯片编程而抽象出来的一幅图。我们先来看下面这副图

STM32F1框图:

STM32F4框图:

对比两幅框图可以看出,F4比F1复杂很多,特别体现在外设上,架构还是差不多的。

红色箭头所指向的就是译码电路

如果你学过微机原理,那么你肯定知道,外设是通过译码电路连接到地址总线上,每一个外设都有其相对应的内存范围,当cpu发出的地址信息处于某一个外设的地址范围内,就选中了该外设,cpu就可以与该外设进行数据交互。

一个外设对应一个内存范围,那所有的外设结合起来,是不是就是对应一张图了。

4.1.2. STM32启动配置

在STM32F10xxx里,可以通过BOOT[1:0]引脚选择三种不同启动模式。

在系统复位后,SYSCLK的第4个上升沿, BOOT引脚的值将被锁存。用户可以通过设置BOOT1
和BOOT0引脚的状态,来选择在复位后的启动模式。

在启动延迟之后, CPU从地址0x0000 0000获取堆栈顶的地址,并从启动存储器的0x0000 0004指示的地址开始执行代码。 (这里先不验证,在之后的博客中会进行验证,但你需要记住,后面用的上)

因为固定的存储器映像,代码区始终从地址0x0000 0000开始(通过ICode和DCode总线访问),
而数据区(SRAM)始终从地址0x2000 0000开始(通过系统总线访问)。 Cortex-M3的CPU始终从ICode总线获取复位向量,即启动仅适合于从代码区开始(典型地从Flash启动)。 STM32F10xxx
微控制器实现了一个特殊的机制,系统可以不仅仅从Flash存储器或系统存储器启动,还可以从内置SRAM启动。

根据选定的启动模式,主闪存存储器、系统存储器或SRAM可以按照以下方式访问:

  • 从主闪存存储器启动:主闪存存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址(0x0800 0000)访问它,即闪存存储器的内容可以在两个地址区域访问, 0x0000
    0000或0x0800 0000。
  • 从系统存储器启动:系统存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的
    地址(互联型产品原有地址为0x1FFF B000,其它产品原有地址为0x1FFF F000)访问它。
  • 从内置SRAM启动:只能在0x2000 0000开始的地址区访问SRAM(当从内置SRAM启动,在应用程序的初始化代码中,必须使用NVIC的异常表和偏移寄存器,重新映射向量表到SRAM中)。

一般情况下都是从主闪存模式启动的,也就是用户代码被烧写到0x0800 0000地址处。

内嵌的自举程序 (Bootloader)

内嵌的自举程序存放在系统存储区,由ST在生产线上写入,用于通过可用的串行接口对闪存存储器进行重新编程,也就是这个自举程序在出厂的时候就已经固化了。大家可以想一下内嵌的自举程序的作用是什么?想不出来也没关系,后面会讲到。

如果想要详细了解这个自举程序到底干了什么,可以看下官方文档:

STM32 microcontroller system memory boot mode

4.1.3. 可执行文件的形成过程

STM32 | hex文件、bin文件、axf文件的区别?

大家可以看下这篇博文,写的还是挺不错的!描述了最终烧写到STM32中的可执行代码的形成过程。

4.1.4. 三种复位

  1. 硬件复位

顾名思义通过硬件给系统一个复位,比如在电路板上设计一复位电路,通过按下按键就可以给系统实现一个复位,而无论系统在执行什么样的程序
。复位后初始化一些配置芯片,硬件复位的作用区域一般是全局的。

2.软件复位

是通过软件给系统一个复位信号,如低电平或许是高电平(具体看系统设置)来实现复位操作
软件复位一般是一些块结构复位

上电复位

系统在上电的瞬间就执行复位操作, 上电复位里面包括硬件复位和软复位的操作,硬件复位和软复位是从上电复位里面的某点开始的启动操作
复位需要初始化CPU系统,包括CPU和内存等。

4.2. 验证猜想

4.2.1. 验证猜想1

对于猜想1,其实不需要验证。代码肯定是要存储在掉电不丢失的存储介质上,否则,每次重新上电都要重新烧写程序,这是与事实相反的。而在实验前必备知识中,我们了解到STM32内部的XIP设备,那不就是代码存储的地方吗?并且也在STM32启动方式中详细地描述了代码存储位置。

  • 如果从主FLASH启动,用户代码存储在0X 0800 0000
  • 如果从SYSTEM MEMORY启动,里面存储的是Bootloader,是芯片出厂的时候就已经固化好了的,可以从中读数据,但是不可以向其中写数据,它的作用就是:将用户程序通过可用的外设烧写到指定的地址处,然后启动STM32。
  • 如果从SRAM启动,用户代码存储在0X2000 0000

4.2.2. 验证猜想2

实验前的必备知识中已经大概地描述了最终烧写到STM32中的可执行文件的形成过程,现在我们需要验证的就是如何将可执行文件烧写到指定的存储设备中去(假设是FLASH,其实也可以是SRAM

我第一次使用Flymcu(串口下载软件的时候),我脑海里就有一个疑问,就是这个软件到底是怎样使得STM32将生成的代码烧写到内部FLASH上的。这真的是很不可思议!因为STM32上电复位后肯定是要执行代码的,可是我还没有给它代码呢,它怎么会运作呢?当时我真的很迷惑。

其实,STM32出厂的时候Bootloader(用于将用户程序下载到STM32内部指定地址处的固件(程序))就已经固化在了System Memory上了,可读写无效

从STM32启动配置一节中我们知道,可以通过对BOOT1和BOOT0引脚上高低电平的改变从而实现STM32启动方式的不同。

如上所说,Bootloader存储在Sytem Memory上,如果想要让Bootloader运行(将用户程序下载到指定内存地址处),那启动模式肯定是要选择以系统存储器的方式启动。

BOOT1 = 0 BOOT0 = 1 -> 系统存储器模式

因此,外部电路的设计的目的就是要能够达到能够对BOOT1和BOOT0引脚上高低电平改变的能力。

接下来,我们就以正点原子的原理图(探索者)为例,来看下STM32外部的电路到底是如何设计的,以及Flymcu到底是怎样控制BOOT1和BOOT0引脚上高低电平改变从而达到具有使得STM32从系统存储器启动的的神奇能力。

如上图所示,这就是正点原子探索者一键下载电路。

一键下载电路涉及到模电知识,下面这篇文章写的还不错,并且还描述了CH340G芯片引脚的作用和功能。

stm32一键下载电路

从上图我们可以知道,Flymcu肯定是通过usb线将数据或指令写入CH340G内(CH340 D+ CH340 D- )然后CH340G根据来自usb的指令进行相应的工作。

CH340G在此电路中的工作就两个:

  • 与STM32进行数据交互
  • 控制BOOT0和RESET高低电平的变化

特别注意:正点原子探索者BOOT0和BOOT1引脚默认都是接地

BOOT0、BOOT1是通过跳线帽和地进行连接的

现在我们知道了,控制BOOT1和BOOT0引脚上高低电平改变是CH340G的作用,而CH340G是严格按照来自Flymcu的指令进行的,所以,控制BOOT1和BOOT0引脚上高低电平改变的幕后黑手就是Flymcu。

注意:向FLASH中烧写程序不仅仅只有串口,由于硬件平台的限制,因此分析串口下载

问题来了,那Flymcu到底干了什么,它是如何将用户程序烧写的STM32内部指定地址处?

以跑马灯为例,看下Flymcu烧写程序过程中输出的信息。

  1. DTR电平置低:复位
  2. RTS电平置高:进入Bootloader
  3. 延时100ms :有谁能够告诉我为什么
  4. DTR电平置高:释放复位
  5. RTS维持高 :此时开始运行Bootloader
  6. 开始连接 :Flymcu要与STM32连接肯定是要发送特定的指令,并且当STM32接收到预先约定好的指令时,也会发送特定的回复。(和接头的性质差不多)

注意:STM32从Bootloader启动到能够与外部设备进行数据交互需要一定的时间,因此连接需要一定的时间

7.读出关于芯片相关的数据

8.读出选项字节

9.进行全片擦除,去除写保护,再次重启Bootloader(有大佬能告诉我为什么)

10.编写程序,从0x0800 0000处开始运行

上述的过程中,大家比较疑惑的地方就是,Flymcu发送给STM32的指令到底是什么,这个指令肯定是事先就确定好的,在这个文档中提及到了。

stm32 microcontroller system memory boot mode

这个手册中的内容大家可以自己详细地去看下,内容不多,我就粗略地说一下必要的知识点

  • 硬件连接需要(文档中的第35页)

通过串口与外部设备进行数据交互时STM32外部电路设计

通过DFU与外部设备进行数据交互时STM32外部电路设计

还有其他的连接方式,我想表述的意思就是:

Bootloader与外部设备进行数据交互的方式有很多种,不仅仅只有串口,只是由于硬件平台有限(正点原子只有通过串口下载的接口(调试接口除外))而根据不同的交互方式,STM32外部的电路设计又大不相同。

  • Bootloader启动流程

从启动流程中我们就可以得到Flymcu发送给STM32的特定连接指令为:0x7F

  • STM32F40xxx/41xxx devices bootloader version

通过版本信息中红色画线部分可以得知,当Bootloader接收到相应的命令之后,就会连续发送两个response。我们这个时候再看下Flymcu中的输出信息,

通过红色画线部分可以看出,Flymcu接收到两个来自Bootloader的信息。

此时,接头成功!!!!!

接头成功后肯定就可以进行数据交互了!!!

因此,我们最初的猜想是正确的:即STM32通过某种外设将可执行文件烧写至FLASH上(也可以是SRAM)

4.2.3. 验证猜想3

博客当中已经多次提及到,STM32不仅可以从FLASH上启动,还可以从SRAM上启动。

并且在STM32启动配置中有一个小提示:从SRAM中启动,需要重新设置中断向量表

中断向量表的设置是用户在用户程序中自己实现的!!!

要验证这个猜想,可以从SRAM中启动,但是不设置中断向量表,看一下会出现什么情况。

由于正点原子的电路设计(因为我使用的就是正点原子的探索者开发板),使得无法通过串口进行SRAM启动,只能通过调试接口下载程序。

注意:SRAM是掉电数据就会丢失的存储器介质,因此使用时(前提是已经掉电)要重新下载程序

从SRAM中启动的最主要的目的是用来调试程序,产品中的用户程序肯定都是存储在FLASH上的,不然每次掉电后用户程序都没了!!!

如何通过调试接口将用户程序下载到SRAM处,可以参考一下下面两篇博文

STM32内部SRAM调试程序

在SRAM中调试代码

假设你现在已经实现了能够通过调试接口将用户程序下载到SRAM处,那么接下来,我们来验证一下。如果没有重新设置中断向量表会出现什么结果。

提示:验证过程需要观看视频,文字无法解释清楚

第一次录视频,在某些地方表达不清楚!!!
SRAM启动时需要重新设置中断向量表

5.得出结论,总结归纳

对于最开始提出的三个猜想,现在可以得出结论:

  • 指令存储在掉电不丢失的存储介质上
  • STM32通过某种外设将可执行文件烧写至掉电不丢失的存储介质上
  • 中断向量表的首地址就是程序的入口地址

注意: 通过串口下载程序,实际上是Flymcu(上位机)与STM32内置的Bootloader进行数据交互,但两者直接需要特定的硬件环境(CH340G(USB转串口芯片))

注意: 内存图中的reserved有些是不使用,有些是不能用(有其他重要的作用:可读写忽略),不可以修改其值

看完这篇博客,你的脑海里必须得有一个流程的框架:

  1. 用户面向单片机编写用户代码(C,C++,ASM)
  2. 用户代码通过交叉编译工具链生成单片机可以执行的可执行文件(HEX,BIN,AXF)
  3. 上位机:各种烧写工具(不局限于Flymcu(因为Bootloader与外部设备进行数据交互不仅仅只是通过USART)))与单片机内部的Bootloader进行数据交互(目的是将可执行文件下载到指定的存储地址处)
  4. 将可执行文件下载到指定存储地址处,然后还会继续等待上位机的command,可以通过复位或上位机发送跳转到用户代码入口地址的命令执行用户程序

这个流程的框架总结一句话就是:

可执行程序 -> cpu执行第一条用户代码的流程

至于cpu执行第一条用户代码之后的流程后面的博客会详细说明,但毋庸置疑的是,这是一个重要转折点,在这个点之后执行的是你自己编写的代码,你比较熟悉这个过程,但是在这个点之前,对大部分人来说都是都是比较陌生的,但是但你对这个过程了解之后,会对你的知识体系有非常大的提升。

希望这篇博客对你有所帮助。

おすすめ

転載: blog.csdn.net/qq_46359697/article/details/114759405