微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 硬件工程师文库 > 简析STM32的启动过程

简析STM32的启动过程

时间:03-18 来源:网络整理 点击:

  当前的嵌入式应用程序开发过程里,C语言已成为了绝大部分场合的最佳选择。如此一来main函数似乎成为了理所当然的起点——因为C程序往往从main函数开始执行。但一个经常会被忽略的问题是:微控制器(单片机)上电后,是如何寻找到并执行main函数的呢?很显然微控制器无法从硬件上定位main函数的入口地址,因为使用C语言作为开发语言后,变量/函数的地址便由编译器在编译时自行分配,这样一来main函数的入口地址在微控制器的内部存储空间中不再是绝对不变的。相信读者都可以回答这个问题,答案也许大同小异,但肯定都有个关键词,叫"启动文件",用英文单词来描述是"Bootloader"。

  无论性能高下,结构简繁,价格贵贱,每一种微控制器(处理器)都必须有启动文件,启动文件的作用便是负责执行微控制器从"复位"到"开始执行main函数"中间这段时间(称为启动过程)所必须进行的工作。最为常见的51,AVR或MSP430等微控制器当然也有对应启动文件,但开发环境往往自动完整地提供了这个启动文件,不需要开发人员再行干预启动过程,只需要从main函数开始进行应用程序的设计即可。

  关于"启动模式"

  话题转到STM32微控制器,无论是keil uvision4还是IAR EWARM开发环境,ST公司都提供了现成的直接可用的启动文件,程序开发人员可以直接引用启动文件后直接进行C应用程序的开发。这样能大大减小开发人员从其它微控制器平台跳转至STM32平台,也降低了适应STM32微控制器的难度(对于上一代ARM的当家花旦ARM9,启动文件往往是第一道难啃却又无法逾越的坎)。 相对于ARM上一代的主流ARM7/ARM9内核架构,新一代Cortex内核架构的启动方式有了比较大的变化。ARM7/ARM9内核的控制器在复位后,CPU会从存储空间的绝对地址0x000000取出第一条指令执行复位中断服务程序的方式启动,即固定了复位后的起始地址为0x000000(PC =0x000000)同时中断向量表的位置并不是固定的。而Cortex-M3内核则正好相反,有3种情况:

  1、 通过boot引脚设置可以将中断向量表定位于SRAM区,即起始地址为0x2000000,同时复位后PC指针位于0x2000000处;

  2、 通过boot引脚设置可以将中断向量表定位于FLASH区,即起始地址为0x8000000,同时复位后PC指针位于0x8000000处;

  3、 通过boot引脚设置可以将中断向量表定位于内置Bootloader区,本文不对这种情况做论述;

  Cortex-M3内核规定,起始地址必须存放堆顶指针,而第二个地址则必须存放复位中断入口向量地址,这样在Cortex-M3内核复位后,会自动从起始地址的下一个32位空间取出复位中断入口向量,跳转执行复位中断服务程序。对比ARM7/ARM9内核,Cortex-M3内核则是固定了中断向量表的位置而起始地址是可变化的。

  细说STM32的启动过程

  下面就从ST的启动文件说起,由于库中的startup_stm32f10x_md.s与编译环境有关,所以针对的是库中的

  STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\TrueSTUDIO路径下的文件进行分析。

  system_stm32f10x.c

  SystemInit():在"startup_stm32f10x_xx.s"文件中被调用,功能是设置系统时钟(包括时钟源,PLL系数,AHB/APBx的预分频系数还有 flash的设定),这个函数会在系统复位之后首先被执行。文件中默认的一些设置:允许HSE(外部时钟),FLASH(允许预取缓冲区,设置2个等待周 期),PLL系数为9,开启PLL并选择PLL输出作为时钟源(SYSCLK),后续设置SYSCLK = HCLK = APB2 = 72MHz,APB1 = HCLK/2 = 36MHz,HCLK即AHB的时钟。

  SystemCoreClockUpdate():在系统时钟HCLK变化的时候调用,以更新一个全局变量SystemCoreClock,这个变量可以为应用程序使用,必须保证正确。默认不调用这个函数,因为SystemCoreClock默认被设置为设定的频率了(72MHz)

  另外,下面这种设置寄存器的方法值得借鉴,先用位名清除相应的位,再进行设置,例如:

  #define RCC_CFGR_PLLSRC ((uint32_t)0x00010000) /*!《 PLL entry clock source */

  #define RCC_CFGR_PLLXTPRE ((uint32_t)0x00020000) /*!《 HSE divider for PLL entry */

  #define RCC_CFGR_PLLMULL ((uint32_t)0x003C0000) /*!《 PLLMUL[3:0] bits (PLL mulTIplicaTIon factor) */

  #define RCC_CFGR_PLLSRC_HSE ((uint32_t)0x00010000) /*!《 HSE clock selected as PLL entry clock source */

  #define RCC_CFGR_PLLMULL9 ((uint32_t)0x001C0000) /*!《 PLL input clock*9 */

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top