0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

从上电到启动,带你拿捏单片机启动全流程

朱老师物联网大讲堂 2024-05-07 08:10 次阅读


从事嵌入式开发的伙伴可能会思考过一个问题,我们一般都是使用芯片厂商提供的驱动库和初始化文件,直接从main函数开始写程序,那么系统上电之后,程序怎么引导进main函数执行的呢?还有,系统上电之后RAM的数据是随机的,那么定义的全局变量的初始值又是怎么实现的呢?下面我将带着这两个问题,以Cortex-M架构为例,采用IAR EWARM作为编译工具链,从系统上电之后执行的第一条代码开始,梳理系统的启动过程,了解编译器在此期间所做的工作。其他的工具链,如Keil和GCC在系统初始化过程所做的工作也是相似的,但具体的实现有所差异。

一、启动文件

芯片厂商提供的启动文件,一般是采用汇编语言编写,少数用C语言。在启动文件中一般至少存在下面两个部分内容:向量表默认的中断和异常处理程序

向量表实际上是一个数组,放置在存储器的零地址,每个元素存储的是各个中断或异常处理程序的入口地址。以STM32F107芯片基于IAR工具的启动文件为例:

33a54eb2-0c06-11ef-9118-92fbcf53809c.png

文件的开头定义了一个名为__vector_table的全局符号,“DATA”的作用是在代码段中定义一个数据区,用作向量表。数据区的内容是使用DCD指令定义的32位宽度常量,除了第一个sfe(CSTACK)比较特殊以为,其他的常量都是异常和中断服务程序的地址(在编译时函数名会被替换成函数的入口地址)。sfe(CSTACK)是IAR汇编器段操作,用于获取段(section)的结束地址,在这里意欲何为呢?实际上这是获取堆栈基地址的操作。IAR在链接器脚本(*.icf)文件中定义堆栈,实际是定义了一个名为“CSTACK”的空闲块(block),如下图的脚本命令所示。所谓的块就是保留一段连续的地址空间,用来作为堆栈或者堆。当然,块也可以是用内容的,例如可以用来管理段,但不在今天的讨论范围。33bb593c-0c06-11ef-9118-92fbcf53809c.png我们知道Cortex-M架构的堆栈模型是满减栈,堆栈从高地址向低地址增长,因此堆栈的基地址是CSTACK的结束地址。向量表的第一个元素是栈基址这是由Cortex-M架构定义的。系统上电后硬件自动从向量表中获取,并设置主堆栈指针MSP,而不是像其他ARM架构,堆栈指针需要通过软件来设置。向量表中第二个元素是复位异常(Reset_Handler)的入口地址。系统上电后,硬件自动从__vector_table + 4的位置读取,并从读取到的地址开始执行。系统上电后CPU执行的第一条是Reset_Handler函数的第一条语句。33c8f0d8-0c06-11ef-9118-92fbcf53809c.png

上面的THUMB命令表示接下来的代码采用THUMB模式(Cortex-M只支持Thumb-2指令集);SECTION用于定义一个段,段名为“.ResetHandler”,段的类型是代码(CODE);REODER指示用给定的名称开启一个新的段;ROOT指示链接器,当段内的符号没有被引用,链接器也不可以丢弃这个段。

PUBWEAK是弱定义,如果用户在其他位置编写了中断处理函数,在连接时实际链接用户所编写的,启动文件中用汇编写的服务函数会忽略。之所以要在启动文件中以弱定义的方式编写全部的异常和中断服务函数,是为了防止用户在没有编写服务函数的情况下开启并触发了中断,导致系统的不确定。

二、系统初始化过程

在EWARM的工程Options > Debugger > Setup中将“Run to”勾选取消,这样在进入调试之后就会停第一条要执行的代码的位置:

341a0b6c-0c06-11ef-9118-92fbcf53809c.png

进入调试之后会停在启动文件Reset_Handler函数第一条汇编指令位置:

34286dc4-0c06-11ef-9118-92fbcf53809c.png

此时,通过寄存器观察窗口查看SP的值为0x20009820。通过链接时生成的map文件,查看CSTACK的地址范围,0x20009820正好是CSTACK的结束地址。有了MSP,C代码就能运行了。

34329664-0c06-11ef-9118-92fbcf53809c.png

ystemInit函数是芯片厂商根据ARM的CMSIS标准提供的一个系统基础配置函数,配置基础的时钟系统和向量表重定位等。这里的LDR是伪指令,它将SystemInit函数的地址加载到寄存器R0,实际上是通过PC偏移寻址来获取SystemInit的地址。

34426850-0c06-11ef-9118-92fbcf53809c.png3450cecc-0c06-11ef-9118-92fbcf53809c.png

从上面的图可以发现一个问题,在反汇编窗口可以观察到SystemInit的地址是0x20000150,但加载到R0寄存器后却是0x20000151。这是因为在使用跳转指令更新PC时,需要置PC的LSB为1,以表示THUMB模式,由于Cortex-M不支持ARM模式,因此LSB总是1。

执行完芯片厂商提供的SystemInit函数之后,跳转到__iar_program_start,这是IAR编译器提供的初始化代码的入口。

34719882-0c06-11ef-9118-92fbcf53809c.png

__iar_program_start首先会执行两个函数:__iar_init_core和__iar_init_vfp,可以完成一些CPU和FPU相关的初始化操作,在某些ARM架构打包好的运行时库会有这两个函数,用户也可以重写这两个函数来自己实现一些相关的操作。

之后,跳转到__cmain函数执行。在__cmain中调用了一个__low_level_init函数,该函数专门用于提供给用户编写一个初阶的初始化操作,它在全局变量初始化之前执行,例如可用在__low_level_init中初始化SDRAM,这样就可以将全局变量定义到SDRAM中使用。

347c34d6-0c06-11ef-9118-92fbcf53809c.png

__low_level_init可以在任意的C文件中编写,注意它的返回值,如果返回0,后续就会跳过变量初始化操作,正常一般都是返回1。

348992de-0c06-11ef-9118-92fbcf53809c.png

三、全局变量的初始化

此后进入到__iar_data_init3函数,在这里会完成所有具有初始值的全局/静态变量的赋值,以及零初始化全局/静态变量的清零操作,分别调用__iar_copy_init3和__iar_zero_init3,将保存在ROM区由链接器生成的变量初始值复制到变量的地址。注意,新的EWARM版本默认变量初始化操作可能会采用压缩算法,实际变量初始化调用的函数可能有区别。34b4b3ec-0c06-11ef-9118-92fbcf53809c.png

在全局变量未初始化之前,通过watch窗口可以看到,变量的值都是随机数。

34c207c2-0c06-11ef-9118-92fbcf53809c.png

在__iar_data_init3执行完成后,全部变量的初值赋值已经完成。

34cd1270-0c06-11ef-9118-92fbcf53809c.png

在__cmain函数的最后,跳转到用户的main函数,最终开始用户的代码执行。

34dc4286-0c06-11ef-9118-92fbcf53809c.png

四、总结

339b54ca-0c06-11ef-9118-92fbcf53809c.png

了解了编译器所提供的初始化过程和处理器架构,我们可以根据自己的需求定制系统的初始化。例如,在进入__iar_program_start之前,就可以执行必要的硬件初始化操作,可以用汇编写,也可以用C写。还可以手动控制变量的初始化操作,自己实现变量的初始化。甚至,完全不采用IAR编译器提供的初始化操作,自己从复位序列引导至main函数那也是可以的。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 芯片
    +关注

    关注

    453

    文章

    50387

    浏览量

    421783
  • 单片机
    +关注

    关注

    6032

    文章

    44514

    浏览量

    632949
  • 嵌入式
    +关注

    关注

    5068

    文章

    19014

    浏览量

    303230
收藏 人收藏

    评论

    相关推荐

    单片机复位和冷启动详细介绍

    单片机启动很简单,关,再上,正常复位后,就冷启动成功。单片机
    的头像 发表于 02-12 13:38 2w次阅读
    <b class='flag-5'>单片机</b>复位和冷<b class='flag-5'>启动</b>详细介绍

    浅析STM32单片机启动文件

    今天来总结的stm32基础知识是启动文件相关。要想对是stm32单片机有个深入的理解,那么启动文件就是一个绕不过去的坎。
    发表于 06-12 16:49 1941次阅读
    浅析STM32<b class='flag-5'>单片机</b>的<b class='flag-5'>启动</b>文件

    单片机启动代码

    带你来看看单片机启动代码!
    发表于 05-26 12:45

    单片机有时候上启动是为什么

    遇到有些国产 单片机有时候上启动的问题,一般出现的情况是LVR设置有问题,最常见是兼容3.3V 5V供电的MCU,有时候默认是5V配置,在3.3V可能出现上无法
    发表于 11-03 06:11

    单片机是如何启动

    接触单片机有几年的时间了,一直专注于如何在单片机上写一些应用,对单片机如何启动的知之甚少,惭愧惭愧。。。今天得空整理了一下,加深了对单片机
    发表于 11-03 08:58

    单片机是如何启动

    单片机启动过程是加后,先运行芯片内部固有程序(这个程序是用户访问不到也改写不了的),即启动代码。启动代码程序建立完运行环境后,会去读串口
    发表于 11-25 09:26

    RK3188 从上开始启动内核为止的过程是怎样去完成的

    如何获取RK3066的BootRom呢?有哪些步骤?RK3188从上开始启动内核为止的过程是怎样去完成的?
    发表于 02-18 07:11

    单片机启动代码详细资料说明

    对于熟悉电脑的伙伴们来说,BIOS(那个蓝色的界面)可能不会太陌生吧,这货就是电脑的启动代码。没有BIOS的电脑,那注定是一块板砖!BIOS主要是做一些开机前的准备工作,例如系统时间设定、启动顺序。。。扯远了!其实电脑本身就是从单片机
    发表于 07-29 17:36 0次下载
    <b class='flag-5'>单片机</b>的<b class='flag-5'>启动</b>代码详细资料说明

    单片机启动代码

    。。。扯远了!其实电脑本身就是从单片机而来,那么单片机也是有启动代码的,只是我们绝大部分情况不去关心它。启动代码究竟都干了些什么工作,为何需要它?想想你在c语言中用到了什么东西,而这些
    发表于 11-13 16:06 30次下载
    <b class='flag-5'>单片机</b>的<b class='flag-5'>启动</b>代码

    单片机启动过程

    启动过程简介单片机启动过程是加后,先运行芯片内部固有程序(这个程序是用户访问不到也改写不了的),即启动代码。
    发表于 11-17 10:21 8次下载
    <b class='flag-5'>单片机</b>的<b class='flag-5'>启动</b>过程

    单片机启动流程分析

    单片机启动流程概述单片机后一直到准备好C语言运行环境并跳转到main函数执行总共经历了5个步骤:1.内核初始化;2.强制PC指针指向
    发表于 11-17 11:36 10次下载
    <b class='flag-5'>单片机</b><b class='flag-5'>启动</b><b class='flag-5'>流程</b>分析

    STM32 单片机启动流程

    STM32 单片机启动流程刚接触ARM的cortex-m系列单片机时,被告知一切都从main() 函数开始,要将程序写在main()函数中。而仿真时也貌似是从main() 函数开始的,
    发表于 11-19 10:21 35次下载
    STM32 <b class='flag-5'>单片机</b><b class='flag-5'>启动</b><b class='flag-5'>流程</b>

    单片机启动过程

    启动过程简介单片机启动过程是加后,先运行芯片内部固有程序(这个程序是用户访问不到也改写不了的),即启动代码。
    发表于 11-19 12:06 55次下载
    <b class='flag-5'>单片机</b>的<b class='flag-5'>启动</b>过程

    单片机中程序和数据存放位置、与电脑内存和硬盘的类比,单片机和计算机程序启动流程对比

    单片机中程序和数据存放位置、与电脑内存和硬盘的类比,单片机和计算机程序启动流程对比
    发表于 11-26 17:51 14次下载
    <b class='flag-5'>单片机</b>中程序和数据存放位置、与电脑内存和硬盘的类比,<b class='flag-5'>单片机</b>和计算机程序<b class='flag-5'>启动</b><b class='flag-5'>流程</b>对比

    STM32的启动过程如何分析

    本文分析STM32单片机从上运行的过程,目的在于了解STM32单片机启动到运行的整个过程。
    的头像 发表于 02-10 10:48 1333次阅读
    STM32的<b class='flag-5'>启动</b>过程如何分析