STM32 单片机启动流程

STM32 单片机启动流程

刚接触ARM的cortex-m系列单片机时,被告知一切都从main() 函数开始,要将程序写在main()函数中。而仿真时也貌似是从main() 函数开始的,以STM32F103为例。

在这里插入图片描述

后来了解到全局变量是在main()函数之前初始化的。MDK默认情况下勾选下面选项,跳过了启动的汇编部分代码,直接进入了main() 函数.
在这里插入图片描述

实际起始位置

在这里插入图片描述

在cortex-m系列中,中断向量表存放在 Flash 开始部分,Flash中第一个字存放栈顶指针,第二个字存放复位中断服务函数入口地址,其他中断服务函数入口地址依次存放在Flash中。

在这里插入图片描述

MCU上电后,会将Flash中的第一个字加载到R13 MSP寄存器中,第二个字加载到R15 PC寄存器中。

在这里插入图片描述

从上图可以看出ARM规定了M3,M4内核要从地址0x0000 0000读取中断向量表,而STM32设置Flash地址到0x0800 0000怎么办?

STM32将地址0x0800 0000开始的内容重映射到首地址0x0000 0000中,这样就解决了从0x0000 0000读取中断向量表的问题。
下图可以看出STM32F105实际读出的0x0000 0000和0x0800 0000内容一样
在这里插入图片描述

R13:栈顶指针寄存器SP

SP寄存器有两个,MSP或者PSP,PSP是为了RTOS特意设置的,如果使用RTOS,则在RTOS的任务中就是使用的PSP,在中断服务函数中则使用MSP。如果不使用RTOS,则默认一直使用MSP。

在这里插入图片描述

在MCU中,RAM只是负责暂存数据,真正的运算是在寄存器中完成的,例如要对两个变量进行加法运算,就需要将两个变量的值从RAM中取出存入寄存器中,然后操作寄存器进行计算,最后将计算结果存入RAM中。因此常说的在进入子函数或者中断服务函数时需要保存现场,其实也就是保存寄存器中的值,将寄存器值PUSH在栈中。

在这里插入图片描述

SP寄存器指向栈顶地址,因此随着PUSH和POP,SP寄存器会跟着自动变化。

在这里插入图片描述

MSP寄存器存放栈顶指针,栈中存放局部变量、函数参数以及进入子函数、中断服务函数前寄存器的值,当从子函数或者中断服务函数中跳出时,会从栈中POP寄存器值,也就是恢复现场,确保程序可以正常执行。平时尽量不让使用递归就是为了防止多次调用自身,多次保存现场导致栈溢出。

在这里插入图片描述

入栈和出栈操作由编译器自动生成代码,但是入栈时默认只会将R0-R3入栈,如果中断服务函数过于复杂,则编译器也会将R4-R11入栈,这也就是为什么中断服务函数尽量简短的原因之一。

在这里插入图片描述

R15:程序计数寄存器PC

PC寄存器指向当前的程序地址。如果修改它的值,就能改变程序的执行流(很多高级技巧就在这里面)
在这里插入图片描述
上电时将中断向量表中的第二个字加载到PC寄存器中,也就是让程序跳转到复位中断服务函数中。
在这里插入图片描述
在这里插入图片描述
不过复位中断服务函数是一个汇编函数。

在这里插入图片描述

复位中断服务函数中调用了SystemInit()函数,该函数主要作用是设置中断向量表的偏移地址。也就是说中断向量表位置是可变的,当使用BOOT后,就需要在APP修改该偏移地址。
在这里插入图片描述

接着复位中断服务函数跳转到__main()函数中,__main()和我们平时说的main()函数是有区别的。

在这里插入图片描述
RAM掉电会丢失数据,在上电后,RAM中的数据是不确定的,在运行main()函数之前需要将RAM中的数据初始化,也就是下图左边到右边的过程,将flash中的RW数据加载到RAM中,并将RAM中的ZI段数据进行初始化操作。MDK中__main()函数帮我们自动完成了这个操作,也就是所谓的准备C语言环境,C语言环境准备好之后会跳到 main() 函数。
在这里插入图片描述
最后,其实还少说了一个,在上电后会根据boot0,boot1 的状态确定自举空间的位置,如果从系统存储器自举(系统bootLoad,出厂时,官方固化在单片机中的一段代码,用户无法修改的。在STM32中,常用的串口下载,DFU就是系统bootLoad中的功能),系统bootLoad执行完毕后才是我们上面说的哪些,文章中的图大部分来自《Cortex-M3 权威指南》
在这里插入图片描述

  • 64
    点赞
  • 314
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
优秀的处理器配合好的开发工具和工具链成就了单片机的辉煌,这是单片机开发者辛勤劳动的结果。也正因为此,ARM的工具链工程师和CPU工程师强强联手,日日夜夜不停耕耘为ARM7TDMI设计出了精练、优化和到位的内部结构,终于成就了ARM7TDMI的风光无限的辉煌。新的ARMCortex-MB处理器在破茧而出之后,就处处闪耀着ARM体系结构激动人心的新突破。它是基于最新最好的32为ARMv7架构,支持高度成功的Thumb-2指令集,并带来了很多前卫崭新的特性。在它优秀,强大的同时,编程模型也更清爽,因而无论你是新手还是骨灰级玩家都会对这样秀外慧中的小尤物爱不释手。根据ARM的统计,2010年全部Cortex-MMCU出货量为1.44亿片,2008年~2011年第一季度,STM32累计出货量占Cortex-MMCU出货量的45%。也就是说,两个Cortex-M微控制器中有一个就来自ST。”很多市场分析机构也ARM的强劲增长表示认可。2007年在3264bitMCU及MPU架构中,ARM所占市场份额为13.6%,而2010年已经占了23.5%击败了PowerArchitecture,成为市场占有率最多的架构。Cortex-n3内核是ARM公司整个Cortex内核系列中的微控制器系列(M)内核还是其他两个系列分别是应用处理器系列(A)与实时控制处理系列(R),这三个系列又分别简称为A、R、M系列。当然,这三个系列的内核分别有各自不同的应用场合。Cortex-MB内核是为满足存储器和处理器的尺寸对产品成本影响很大的广泛市场和应用领域的低成本需求而专门开发设计的。主要是应用于低成本、小管脚数和低功耗的场合,并且具有极高的运算能力和极强的中断响应能力。Cortex-M3处理器采用纯Thumb2指令的执行方式,这使得这个具有32位高性能的ARM内核能够实现8位和16位的代码存储密度。核心门数只有3K,在包含了必要的外设之后的门数也只有60K,使得封装更为小型,成本更加低廉。Cortex-n3采用了ARMV7哈佛架构,具有带分支预测的3级流水线,中断延退最大只有12个时钟周期,在末尾连锁的时候只需要6个时钟周期。同时具有1.25DMIPS/MHZ的性能和0.19MW/MHZ的功耗。     社会对基于ARM的嵌入式系统开发人员的高需求及给予的高回报,催生了很多的培训机构,这也说明嵌入式系统的门槛较高,其主要原因有以下几点。ARM本身复杂的体系结构和编程模型,使得我们必须了解详细的汇编指令,熟悉ARM与Thumb状态的合理切换,才能理解Bootloader并对操作系统进行移植,而理解Bootloader本身就比较困难,因而对于初学者来说Bootloader的编写与操作系统的移植成了入门的第一道难以逾越的门槛2、ARM芯片,开发板及仿真器的高成本,这样就直接影响了嵌入式开发的普及,使得这方面人才增长缓慢;3、高校及社会上高水平嵌入式开发人员的短缺,现实问题使得我们的大学生和公司职工在入门的道路上困难重重,很多人也因此放弃;培训机构的高费用,虽然有高水平的老师指导,但是高费用就是一道关口,进去的人也只是在短短的几天时间里匆匆了解了一下开发过程,消除了一些畏惧心理而己,修行还是得依靠自己;5、好的开发环境需要资金的支持,也直接影响了入门的进度。基于Cortex-m3内核的ARM处理器的出现,在优秀的Kei开发工具的支持下,可以自动生成启动代码,省去了复杂的Bootloader的编写。Thumb-2指令集的使用,使得开发人员不用再考虑ARM状态与Thumb状态的切换,节省了执行时间和指令空间,大大减轻了软件开发的管理工作。处理器与内存尺寸的减少,大大降低了成本,使得芯片及开发板的价格得以在很大程度降低。Cortex-M3内核通过把中断控制器、MPU及各种调试组件等基础设施的地址固定很大程度上方便了程序的移植。源代码是公开的库函数,使得我们可以摒弃晦涩难懂的汇编语言,在不需要了解底层寄存器的操作细节的情况下,用C语言就可以完成我们需要的功能。所有这些特点使得我们学习ARM处理器的门槛得以降低。同时建议大家尽量去用固件库。而不是避开固件库自己写代码。因为在实际的项目中,代码成百上千个,不可能都自己来写,调用固件库中的函数来完成,才是可行的方案。当然我们在深入的情况下,透彻理解寄存器的操作是必要的,也是得的,高效编程也必须在这方面努力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值