单片机STM32的启动文件详解--学习笔记

  启动文件简介

  启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:

  1、初始化堆栈指针SP=_initial_sp

  2、初始化PC 指针=Reset_Handler

  3、初始化中断向量表

  4、配置系统时钟

  5、调用C 库函数_main 初始化用户堆栈,从而最终调用main 函数去到C 的世界

  查找ARM 汇编指令

  在讲解启动代码的时候,会涉及到ARM 的汇编指令和Cortex

内核的指令,剩下的ARM的汇编指令我们可以在MDK->Help->Uvision Help 中搜索到,以EQU 为例,检索如下:

  图1 ARM 汇编指令索引

  检索出来的结果会有很多,我们只需要看Assembler User Guide 这部分即可。下面列出了启动文件中使用到的ARM

汇编指令,该列表的指令全部从ARM Development Tools这个帮助文档里面检索而来。其中编译器相关的指令WEAK 和ALIGN

为了方便也放在同一个表格了。

  启动文件代码讲解

  1. Stack—栈

  开辟栈的大小为0X00000400(1KB),名字为STACK,NOINIT 即不初始化,可读可写,8(2^3)字节对齐。

  栈的作用是用于局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部SRAM

的大小。如果编写的程序比较大,定义的局部变量很多,那么就需要修改栈的大小。如果某一天,你写的程序出现了莫名奇怪的错误,并进入了硬fault

的时候,这时你就要考虑下是不是栈不够大,溢出了。

  EQU:宏定义的伪指令,相当于等于,类似与C 中的define。

  AREA:告诉汇编器汇编一个新的代码段或者数据段。STACK 表示段名,这个可以任意命名;NOINIT 表示不初始化;READWRITE

表示可读可写,ALIGN=3,表示按照2^3对齐,即8 字节对齐。

  SPACE:用于分配一定大小的内存空间,单位为字节。这里指定大小等于Stack_Size。标号__initial_sp 紧挨着SPACE

语句放置,表示栈的结束地址,即栈顶地址,栈是由高向低生长的。

  2. Heap 堆

  开辟堆的大小为0X00000200(512 字节),名字为HEAP,NOINIT 即不初始化,可读可写,8(2^3)字节对齐。__heap_base

表示对的起始地址,__heap_limit 表示堆的结束地址。堆是由低向高生长的,跟栈的生长方向相反。

  堆主要用来动态内存的分配,像malloc()函数申请的内存就在堆上面。这个在STM32里面用的比较少。

  1 PRESERVE8

  2 THUMB

  PRESERVE8:指定当前文件的堆栈按照8 字节对齐。

  THUMB:表示后面指令兼容THUMB 指令。THUBM是ARM以前的指令集,16bit,现在Cortex-M系列的都使用THUMB-2

指令集,THUMB-2 是32 位的,兼容16 位和32 位的指令,是THUMB 的超集。

  3. 向量表

  1 AREA RESET, DATA, READONLY

  2 EXPORT __Vectors

  3 EXPORT __Vectors_End

  4 EXPORT __Vectors_Size

  定义一个数据段,名字为RESET, 可读。并声明 __Vectors 、__Vectors_End 和__Vectors_Size

这三个标号具有全局属性,可供外部的文件调用。

  EXPORT:声明一个标号可被外部的文件使用,使标号具有全局属性。如果是IAR 编译器,则使用的是GLOBAL 这个指令。

  当内核响应了一个发生的异常后,对应的异常服务例程(ESR)就会执行。为了决定 ESR的入口地址,

内核使用了―向量表查表机制‖。这里使用一张向量表。向量表其实是一个WORD( 32 位整数)数组,每个下标对应一种异常,该下标元素的值则是该 ESR

的入口地址。向量表在地址空间中的位置是可以设置的,通过 NVIC 中的一个重定位寄存器来指出向量表的地址。在复位后,该寄存器的值为 0。因此,在地址 0

(即FLASH 地址0)处必须包含一张向量表,用于初始时的异常分配。要注意的是这里有个另类: 0 号类型并不是什么入口地址,而是给出了复位后 MSP

的初值。

  向量表

  __Vectors 为向量表起始地址,__Vectors_End 为向量表结束地址,两个相减即可算出向量表大小。

  向量表从FLASH 的0 地址开始放置,以4 个字节为一个单位,地址0 存放的是栈顶地址,0X04

存放的是复位程序的地址,以此类推。从代码上看,向量表中存放的都是中断服务函数的函数名,可我们知道C 语言中的函数名就是一个地址。

  DCD:分配一个或者多个以字为单位的内存,以四字节对齐,并要求初始化这些内存。在向量表中,DCD 分配了一堆内存,并且以ESR

的入口地址初始化它们。

  4. 复位程序

  复位子程序是系统上电后第一个执行的程序,调用SystemInit 函数初始化系统时钟,然后调用C 库函数_mian,最终调用main 函数去到C

的世界。

  WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部文件没有声明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,这里并不是唯一的。

  IMPORT:表示该标号来自外部文件,跟C 语言中的EXTERN 关键字类似。这里表示SystemInit 和__main

这两个函数均来自外部的文件。

  SystemInit()是一个标准的库函数,在system_stm32f10x.c

这个库文件总定义。主要作用是配置系统时钟,这里调用这个函数之后,单片机的系统时钟配被配置为72M。

  __main 是一个标准的C 库函数,主要作用是初始化用户堆栈,并在函数的最后调用main 函数去到C

的世界。这就是为什么我们写的程序都有一个main 函数的原因。

  LDR、BLX、BX 是CM4 内核的指令,具体作用见下表:

  5. 中断服务程序

  在启动文件里面已经帮我们写好所有中断的中断服务函数,跟我们平时写的中断服务函数不一样的就是这些函数都是空的,真正的中断复服务程序需要我们在外部的C

文件里面重新实现,这里只是提前占了一个位置而已。

  如果我们在使用某个外设的时候,开启了某个中断,但是又忘记编写配套的中断服务程序或者函数名写错,那当中断来临的时,程序就会跳转到启动文件预先写好的空的中断

  服务程序中,并且在这个空函数中无线循环,即程序就死在这里。

  B:跳转到一个标号。这里跳转到一个‘.’,即表示无线循环。

  6. 用户堆栈初始化

  1 ALIGN

  ALIGN:对指令或者数据存放的地址进行对齐,后面会跟一个立即数。缺省表示4 字节对齐。

  首先判断是否定义了__MICROLIB

,如果定义了这个宏则赋予标号__initial_sp(栈顶地址)、__heap_base(堆起始地址)、__heap_limit(堆结束地址)全局属性,可供外部文件调用。有关这个宏我们在KEIL

里面配置,具体见下图 。然后堆栈的初始化就由C 库函数_main 来完成。

  如果没有定义__MICROLIB , 则才用双段存储器模式, 且声明标号__user_initial_stackheap

具有全局属性,让用户自己来初始化堆栈。

  IF,ELSE,ENDIF:汇编的条件分支语句,跟C 语言的if ,else 类似

  END:文件结束

  stm32视频学习资料

  系统移植(告别裸奔)

  http://www.makeru.com.cn/live/1392_450.html?s=45051

  从单片机到嵌入式linux我们需要做什么

  http://www.makeru.com.cn/live/5413_1994.html?s=45051

  (stm32 USART串口应用)

  http://www.makeru.com.cn/live/1392_1164.html?s=45051

  PWM脉宽调制技术

  http://www.makeru.com.cn/live/4034_2146.html?s=45051

  基于STM32讲解串口操作

  http://www.makeru.com.cn/live/1758_490.html?s=45051

  (stm32直流电机驱动)

  http://www.makeru.com.cn/live/1392_1218.html?s=45051

  中断和异常处理机制

  http://www.makeru.com.cn/live/4034_2092.html?s=45051

  学习资料下载群:830802928

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容

  • 博客主页,欢迎访问:blog.spursgo.com 之前接触较多的是stm32F103单片机,在开始学习的时候,...
    沙子硅阅读 5,252评论 0 14
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 7,813评论 0 27
  • 计算机系统漫游 代码从文本到可执行文件的过程(c语言示例):预处理阶段,处理 #inlcude , #defin...
    willdimagine阅读 3,586评论 0 5
  • 原文地址:C语言函数调用栈(一)C语言函数调用栈(二) 0 引言 程序的执行过程可看作连续的函数调用。当一个函数执...
    小猪啊呜阅读 4,616评论 1 19
  • 王爽汇编全书知识点大纲 第一章 基础知识 机器语言 汇编语言的产生 汇编语言的组成 存储器 cpu对存储器的读写 ...
    2c3ba901516f阅读 2,419评论 0 1