返回首页  设为首页  加入收藏  今天是:
网站首页电脑主板电脑cpu电脑内存电脑硬盘电脑显卡电脑电源显示器电脑配件电脑维修
相关文章
 Cortex-M启动流程详解(Keil)
 佛山内存ssd
 SIGGRAPH 节省50%内存占用浙…
 一文搞懂物理内存组织的体系…
 「专升本信息技术」信息技术…
 台式电脑CPU温度过高怎么办
 电脑cpu温度高怎么解决
 电脑cpu温度过高怎么处理
 电脑cpu温度过高的三种解决方…
 电脑cpu温度过高几种常用处理…
 意外!5000元买块显卡玩游戏…
 为VR而生!AMD RX 6000显卡全…
 三路视频输出接口迪兰最强HD…
 AMD RX 6000显卡全系普及USB…
 RTX 4050什么时候发布上市 显…
 RTX4070ti显卡什么水平 支持…
 究竟什么是满血显卡和残血显…
 Steam Deck配置相当于什么显…
 机械革命新款蛟龙5游戏本上架…
 NVIDIA显卡驱动程序5258505 …
 收藏帖:财务管理106条经典公…
 roi计算公式
 KE科日光伏网
 ROE计算公式
 焦点新闻-焦点新闻-99-电子工…
 酷睿13电脑如何选从6000到20…
 真正的傻瓜式一键破解冠道中…
 超薄电脑显示器厂家-弘缘顾客…
 超薄电脑显示屏
 2023年最佳手机排名:苹果、…
 内存最新资讯-快科技
 蝉联榜首5天16GB大内存版本销…
 DDR5内存超频破纪录 频率高达…
 愉快买买买:喜迎16G内存跌破…
 Steam Deck能连电视吗 能插内…
 宏碁(acer) X34GS 34英寸N…
 三星于CES重磅发布新款玄龙骑…
 国庆特别科普:超宽屏显示器…
 宏碁(acer) X34GS 34英寸N…
 CES 2023:一篇文章看展!24…
 科普文从计算机相关的散热接…
 怎么看cpu风扇转速
 全方位的系统散热!下吹式CPU…
 台式电脑散热器和风扇有什么…
 怎样选合适的CPU风扇?满满的…
 【你问我答】第3期:5000预算…
 显卡、硬盘、内存……买一台…
 3种不值得买的二手硬件!买了…
 网购二手手机卖家虚假标注“…
 网吧老板的最爱 名牌主板套装…
专题栏目
网络
您现在的位置: 电脑评测网 >> 电脑内存 >> 正文
高级搜索
Cortex-M启动流程详解(Keil)
作者:佚名 文章来源:本站原创 点击数: 更新时间:2023/1/22 13:34:18 | 【字体:

  奶茶妹何雅诗对于我们常用的桌面操作系统而言,我们在开发应用时,并不关心系统的初始化,绝大多数应用程序是在操作系统运行后才开始运行的,操作系统已经提供了一个合适的运行环境,然而对于嵌入式设备而言,在设备上电后,所有的一切都需要由开发者来设置,这里处理器是没有堆栈,没有中断,更没有外围设备,这些工作是需要软件来指定的,而且不同的CPU类型、不同大小的内存和不同种类的外设,其初始化工作都是不同的。本文将以STMF103(基于Cortex-M3)为例进行讲解。

  在开始正式讲解之前,你需要了解ARM寄存器、汇编以及反编译相关的知识,这些可以参考笔者博文。

  下面我们就来具体看一下用户从Flash启动STM32的过程,主要讲解从上电复位到main函数的过程。主要有以下步骤:

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

  首先要讲一下STM32的启动模式,因为启动模式决定了向量表的位置,STM32有三种启动模式:

  以0x08000000 对应的内存为例,则该块内存既可以通过0x00000000 操作也可以通过0x08000000 操作,且都是操作的同一块内存。

  2)系统存储器(System Memory)启动:系统储存器指的是STM32的内置ROM,选择该启动模式后,内置ROM的起始地址将被重映射到0x00000000地址,代码在此处开始运行。ROM中有一段出厂预置的代码,这段代码起到一个桥的作用,允许外部通过UART/CAN或USB等将代码写入STM32的内置Flash中。这段代码也被称为ISP(In System Programing)代码,这种烧录代码的方式也被称为ISP烧录。

  一般来说,我们选用这种启动模式时,是为了从串口下载程序,因为在厂家提供的ISP程序中,提供了串口下载程序的固件,可以通过这个ISP程序将用户程序下载到系统的Flash中。

  以0x1FFFFFF0对应的内存为例,则该块内存既可以通过0x00000000 操作也可以通过0x1FFFFFF0操作,且都是操作的同一块内存。

  3)片上SRAM启动:从内置SRAM启动(0x2000 0000-0x3FFFFFFF),既然是SRAM,自然也就没有程序存储的能力了,这个模式一般用于程序调试。SRAM 只能通过0x20000000进行操作,与上述两者不同。从SRAM 启动时,需要在应用程序初始化代码中重新设置向量表的位置。该方法是在STM32的内置SRAM中启动,选择该启动模式后,内置SRAM的起始地址将被重映射到0x00000000地址,代码在此处开始运行。这种模式由于烧录程序过程中不需要擦写Flash,因此速度较快,适合调试,但是掉电丢失。

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

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

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

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

  定义子程序,与ENDP成对使用,表示子程序结束 同义词 FUNCTION

  编译器指令,对指令或数据存放地址进行对齐(一般跟一个立即数,缺省为4字节)

  栈的作用是用于局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部SRAM 的大小。当程序较大时,需要修改栈的大小,不然可能会出现的HardFault的错误。

  第33行:表示开辟栈的大小为 0X00000400(1KB),EQU是伪指令,相当于C 中的 define。这个 “指令” 并不会生产二进制程序代码,也不会引起变量空间分配。

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

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

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

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

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

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

  上述向量表可以在《Reference manual》中找到的,笔者这里只截取了部分。

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

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

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

  第149行:这是一条汇编指令,表示从存储器中加载SystemInit到一个寄存器R0的地址中。R0~R3 寄存器通常用于函数入参出参或子程序调用。

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

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

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

  值得注意的是,这里的__main和C语言中的main()不是一样东西,__main是C lib中的函数,也就是在Keil中自带的;而main()函数是C的入口,main()会被__main调用。

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

  这部分没啥好说的,和服务程序类似的,只需要注意‘B .’语句,B表示跳转,这里跳转到一个‘.’,即表示无线 堆栈初始化

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

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

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

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

  根据BOOT引脚确定了启动方式后,处理器进行的第二大步就是开始从0x00000000地址处开始执行代码,而该处存放的代码正是Bootloader。

  Bootloader,也可以叫启动文件,每一种微控制器(处理器)都必须有启动文件,启动文件的作用便是负责执行微控制器从“复位”到“开始执行main函数”中间这段时间(称为启动过程)所必须进行的工作。最为常见的51,AVR或MSP430等微控制器当然也有对应启动文件,但开发环境往往自动完整地提供了这个启动文件,不需要开发人员再行干预启动过程,只需要从main函数开始进行应用程序的设计即可。同样,STM32微控制器,无论是MDK还是IAR开发环境,ST公司都提供了现成的直接可用的启动文件。

  启动文件中首先会定义堆栈,定义中断/异常向量表,而其中只实现了复位的异常处理函数Reset_Handler,该函数其主要功能除了初始化时钟,FPU等,还

  我们知道烧录的镜像文件中包含只读代码段.text,已初始化数据段.data和未初始化的或者初始化为0的数据段.bss。代码段由于是只读的,所以是可以一直放在Flash中,CPU通过总线去读取代码执行就行,但是.data段和.bss段由于会涉及读写为了,为了更高的读写效率是要一定搬到RAM中执行的,因此Bootloader会执行很重要的一步,就是会在RAM中初始化.data和.bss段,搬移或清空相应内存区域。

  当启动方式选择的是从内置Flash启动的时候,代码依旧是在Flash中执行,而数据则会被拷贝到内部SRAM中,该过程是由Bootloader完成的。Bootloader在完成这些流程之后,就会将代码交给main函数开始执行用户代码。

  当系统复位后,处理器首先读取向量表中的前两个字(8 个字节),第一个字存入 MSP,第二个字为复位向量,也就是程序执行的起始地址。

  初始化SP、PC紧接着就初始化向量表,如果感觉看HEX文件抽象,我们看看反汇编文件吧。

  是不是更容易些,是不是和《Reference manual》中的向量表对应起来了。其实看反汇编文件更好理解STM32的启动流程,只是有些抽象。

  细心的朋友可能发现,PC=0x08000145的地址是没有对齐的。然后在反汇编文件中却是这样的:

  这里是硬件自动对齐到 0x08000145,并执行SystemInit函数初始化系统时钟。

  SetSysClock()函数主要配置的时钟系数,笔者使用的MCU是STM32F103ZE,因此对应的时钟配置参数如下。

  默认是没有开启VECT_TAB_SRAM,则从FLASH中启动,VTOR 寄存器存放的是中断向量表的起始地址,在IAP升级会修改这里的偏移量,后面讲解IAP升级在细讲吧。

  执行指令LDR R0, =__main,然后就跳转到__main程序段运行,当然这里指标准库的__main函数。

  这段代码是个循环(BCC 0x0800016e),实际运行时候循环了两次。第一次运行的时候,读取“加载数据段的函数”的地址并跳转到该函数处运行(注意加载已初始化数据段和未初始化数据段用的是同一个函数);第二次运行的时候,读取“初始化栈的函数”的地址并跳转到该函数处运行。

  MCU上电后从0x0800 0000处读取栈顶地址并保存,然后从0x0800 0004读取中断向量表的起始地址,这就是复位程序的入口地址,接着跳转到复位程序入口处,初始向量表,然后设置时钟,设置堆栈,最后跳转到C空间的main函数,即进入用户程序。

电脑内存录入:admin    责任编辑:admin 
  • 上一个电脑内存:

  • 下一个电脑内存: 没有了
  •  
     栏目文章
    普通电脑内存 Cortex-M启动流程详解(Keil) (01-22)
    普通电脑内存 佛山内存ssd (01-22)
    普通电脑内存 SIGGRAPH 节省50%内存占用浙大、快手等提出量… (01-22)
    普通电脑内存 一文搞懂物理内存组织的体系结构与内存模型 (01-22)
    普通电脑内存 「专升本信息技术」信息技术基础知识习题(1) (01-22)
    普通电脑内存 内存最新资讯-快科技 (01-21)
    普通电脑内存 蝉联榜首5天16GB大内存版本销量占比80%12GB+… (01-21)
    普通电脑内存 DDR5内存超频破纪录 频率高达11136MHz (01-21)
    普通电脑内存 愉快买买买:喜迎16G内存跌破200元 (01-21)
    普通电脑内存 Steam Deck能连电视吗 能插内存卡吗? (01-21)
    普通电脑内存 Microsoft Defender 在 Win10 中导致系统高内… (01-21)
    普通电脑内存 玩csgo卡顿不流畅怎么解决 (01-21)
    普通电脑内存 MIUI 9开发版发布时间公布 小米MIUI9正式发布 (01-21)
    普通电脑内存 元年科技:打造数字化转型的核心引擎—首款世… (01-21)
    普通电脑内存 MIUI10公测开发版更新内容大全 三种MIUI10升级… (01-21)
    普通电脑内存 手机上的内存融合技术是什么?有用吗? (01-20)
    普通电脑内存 Windows 7系统最低需1GB内存1GHz CPU128MB内存… (01-20)
    普通电脑内存 锐龙R7 5800X3D支持多大的内存 是什么架构? (01-20)
    普通电脑内存 电脑内存介绍及安装指南 (01-20)
    普通电脑内存 电脑内存条的作用是什么 电脑内存条作用说明介… (01-20)