单片机启动流程分析 您所在的位置:网站首页 mk60n512vmd100 单片机启动流程分析

单片机启动流程分析

#单片机启动流程分析| 来源: 网络整理| 查看: 265

一 单片机启动流程概述

单片机上电后一直到准备好C语言运行环境并跳转到main函数执行总共经历了5个步骤: 1.内核初始化; 2.强制PC指针指向中断向量表的复位中断向量执行复位中断函数; 3.在复位中断函数中调用 SystemInit 函数,初始化时钟,配置中断向量表等 4.调用 __main 函数完成全局/静态变量的初始化和重定位工作,初始化堆栈和库函数 5.跳转到main函数中执行

二 内核初始化

在单片机上电后首先会进行一系列内核的初始化,关于这部分工作我们只需要了解即可,在内核初始化的过程中主要做了以下几件事情:

1.内核复位和NVIC寄存器部分清零; 2.内核设置堆栈:内核从向量表0地址读出堆栈地址,并设置主堆栈指针(SP_main); 3.设置PC和LR寄存器 a. LR设置未初始复位值0xFFFF FFFF b. 单片机的内部硬件机制自动将PC指针定位到中断向量表的复位中断向量出,把复位中断函数Reset_Handler的地址赋值给PC指针,然后跳转执行Reset_Handler。

三 复位中断函数 Reset_Handler

在内核复位的最后一步,将PC指针指向了复位中断向量,而复位中断服务函数中的内容才是我们真正需要关心的内容。查看IAR环境中的* .s 单片机汇编启动文件有以下一段内容:

Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit ;加载SystemInit的地址到寄存器R0中 BLX R0 ;跳转R0中的地址执行(执行SystemInit函数) LDR R0, =__main ;加载SystemInit的地址到寄存器R0中 BX R0 ;跳转R0中的地址执行(执行__main函数) ENDP

上面的代码就是Reset_Handler的中断服务函数,可以看到在服务中断函数中先使用 IMPORT声明了两个函数 __main,SystemInit,然后顺序跳转执行SystemInit和**__main**函数。下面我们再来了解一下这两个函数具体干了些什么事情: SystemInit 函数:

在system_stm32f4xx.c文件中我们可以看到该函数的定义,该函数主要干了以下两件事情: 1.初始化时钟:SYSCLK,HCLK,PCLK2 and PCLK1 prescalers 2.配置中断向量表:中断向量表的定位是在 Flash 还是 SRAM,是否需要偏移) 注意:可以通过system_stm32f4xx文件中的宏定义修改系统时钟频率(通过设置锁相环的相关系数),中断向量表的地址(位于SRAM还是Flsah,是否偏移,偏移地址多少等参数)

__main()函数(在IAR中是 __iar_program_start ):

该函数被封装进了编译器的库中,所以不同的IDE该函数的名称有所区别,但所实现的功能大致类似:

1.完成全局变量/静态变量/常量的初始化和重定位工作: a. 跳转进入__scatterload_rt2函数:通过设置四个寄存器来配置待copy内容(静态变量、全局变量、常量)的的加载域和运行域,设置待copy内容的大小,为后续__scatterload_cpy()函数服务。 b. 跳转进入__scatterload_cpy函数,完成静态变量、全局变量、常量的从flash到SRAM的重定位。 c. 跳转进入__scatterload_zeroinit函数,完成未初始化的全局变量的初始化。

2.初始化堆栈(这里指程序栈)和库函数: 跳转进入__user_steup_stackheap函数:调用**__user_libspac__user_libspace**为C库保持了静态数据。这是一个96字节,0初始化的数据块,该块由C库创建。在C库初始化期间可以用来当做临时栈。再调用 __user_initial_stackheap 用户的初始化堆栈函数,实现用户的堆栈的配置,调用 _fp_init 和 __rt_fp_status_addr (C库函数) 两个函数调用实现浮点运算的支持。

3.程序的跳转,进入main()函数: 跳转进入用户的main函数

注意:

未初始化和初始值为零的全局变量,静态变量一般在RAM中, 初始值不为零的全局变量/静态变量 一般在FLASH中。因为Flash不能随机写(只能写0,不能写1),所以一般会在程序运行之前将初始值不为零的全局变量重定位到RAM中。全局变量和常量的地址在编译时都已经被分配好了(所以能够在 .map 文件中看到), 而局部变量则是程序运行时在栈中创建的,栈空间大小可以在IDE中设置。单片机启动时,不需要用将代码从ROM搬移到RAM ,而 ARM 则需要。单片机程序执行的过程分三个步骤:取执行->分析指令->执行指令。取指令的任务是:根据 PC的值从程序存储器读出指令,送到指令寄存器。然后分析执行执行。这样单片机就从内部程序存储器去代码指令,从 RAM 存取相关数据。要知道RAM取数的速度是远高于ROM的,但是单片机因为本身运行频率不高,所以从ROM取指令慢并不影响。而ARM不同,CPU运行的频率高,远大于从 ROM读写的速度,所以一般有大型的操作系统时,都需要将代码部分拷贝到RAM中再执行。


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有