Keil启动文件详解

转载:(3条消息) Keil 启动文件详解_xieyuhang727的博客-CSDN博客_keil的启动文件

1. 启动文件详解
1.1 启动文件的主要任务
    启动文件会完成以下五件事:

初始化堆栈指针 SP=__initial_sp
初始化PC指针 PC=Reset_Handler
初始化中断向量表
配置系统时钟
调用C库函数__main()初始化用户堆栈,从而最终调用main函数去到C世界
1.2 启动文件中的汇编指令
    汇编指令可以通过keil->help->uVision Help->搜索中查找,启动文件中的汇编指令如下:

1.3 启动代码讲解
1.3.1 栈的初始化


    此处开辟栈的大小为0x00000400(1KB), 名字为STACK, NOINIT即不初始化,READWRITE表示可读可写,ALIGN=3,表示2^3=8字节对齐。栈的作用是用于局部变量,函数调用,函数形参等开销。栈是在SRAM中开辟的,因此栈的大小不能超过SRAM。如果局部变量很多,或者函数调用很深,可能需要增大栈的大小。

    标号__initial_sp紧挨着SPACE语句放置,表示栈的结束地址,即栈顶的指针,栈是由高向低生长的。

1.3.2 堆的初始化


    与栈的初始化类似。不同的是__heap_base表示堆的起始地址,__heap_limit表示堆的结束地址,堆是由下向上生长的,和栈的生长方向相反。堆主要用来动态内存的分配,malloc()函数就是从堆里面分配内存,这个在STM32里面用的比较少。

1.3.3 向量表初始化


    首先定义了一个数据段,名字叫RESET,只读,并声明了__Vectors、Vectors_End和__Vectors_Size这三个标号具有全局属性,可供属性外部的文件调用。当内核响应了一个发生的异常后,对应的异常服务例程就会执行ISR,找到ISR的入口地址,内核使用了“向量表查表机制”。向量表在地址空间中的位置是可以设置的,通过NVIC中的一个重定位寄存器指向向量表的地址。在复位后,该寄存器的值为0。因此,在地址0(在flash地址0)处必须包含一张向量表,用于初始时的异常分配。这个向量表的头是MSP,第二个才是Reset。

__Vectors为向量表起始地址,__Vectors_End为向量表结束地址,两个相减即算出向量表的大小
在向量表中,DCD分配一个内存,并且以ISR的入口地址初始化他们

1.3.4 复位程序


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hETA05F4-1575439728535)(B1AAD5E21B954D348E83C881B999DD57)]

    定义一个名为|.text|的代码段,可读。复位子程序是系统上电后第一个执行的程序,调用SystemInit函数初始化系统时钟,然后调用C库__mian,然后调用main函数去C世界。

    ==SystemInit()==是一个标准的库函数,在system_stm32f7xx.c这个库文件中定义。主要作用是配置系统时钟,这里调用这个函数后,F767的系统时钟被配置成16M。

    __main是一个标准C库函数,主要作用是初始化用户堆栈,最终调用main函数取C世界,这就是为什么我们写的程序都有一个main函数的原因。如果我们在这里不调用__main,那么程序最终就不会调用我们C文件里面的main,但是也可以自己定义main,然后在systeminit之后直接调用。

介绍几个常用的指令:

1.3.5 中断服务程序
    启动文件中已经写好了所有的中断服务函数,但是只是占个位置,具体的实现需要在C代码中定义相同名字的函数。如果没有定义相关C函数,就会用默认的启动文件中的ISR,进入无限循环。

1.3.6 用户堆栈初始化

    ALIGN,对指令或者数据存放的地址进行对齐,后面会跟着一个立即数,如果没有的话,默认4字节对齐。

首先判断是不是定义了__MICROLIB,如果定义了则赋予标号__initial_sp(栈顶地址)、__heap_base(堆起始地址)、__heap_limit(堆结束地址)全局属性,可以供外部文件调用。
如果没有定义__MICROLIB,则默认使用C库,然后初始化用户堆栈大小,这部分有C库函数__main来完成,当初始化完堆栈之后,就调用main函数去到C世界。
1.4 系统启动流程
系统上电
从0x00000000处取出MSP
从0x00000004处取出PC的初始值,这个值就是复位向量Reset_Handler,LSB必须是1
跳转到复位向量,执行Reset_Handler函数
执行C库的__main()函数
跳转到我们定义的main函数


注:这和传统的ARM架构不同,传统的ARM架构总是从0地址开始执行第一条指令。他们的0地址总是一条跳转指令。但是在CM3/4中,在0地址处提供的是MSP的初始值,然后紧跟着是向量表中的函数地址,向量表的第一个条目指向复位向量,即Reset_Handler函数。

因为CM3使用的是向下生长的满栈,所以MSP的初始值必须是满堆栈内存的莫地址加1。例如:如果我们的堆栈区域在0x20007c00~0x20007fff之间,那么MSP的初始值就必须是0x20008000。
向量表跟最在MSP之后。要注意CM3/4是在Thumb态下执行的,所以向量表中的每个数据都必须把LSB置1(也就是奇数)。正是因为这个原因,图14-3中使用0x101来表示0x100地址。
在进入C世界之间初始化MSP时必须的,因为如果还没初始化好MSP就来了NMI或者Hardfault。MSP初始化好后就已经为他们的服务例程准备好了堆栈。
 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值