STM32_启动流程详解

这篇具有很好参考价值的文章主要介绍了STM32_启动流程详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

最近在学习IAP远程OTA升级单片机固件程序,发现自己对单片机的启动流程还不是那么了解,就总结整理一下吧。


启动流程概述

  • 1.内核初始化;
    • 1.内核复位和NVIC寄存器部分清零;
    • 2.内核设置堆栈:内核从向量表0地址读出堆栈地址,并设置主堆栈指针(SP_main)
    • 3.设置PC和LR寄存器
      • a. LR设置未初始复位值0xFFFF FFFF
      • b. 单片机的内部硬件机制自动将PC指针定位到中断向量表的复位中断向量处,把复位中断函数Reset_Handler的地址赋值给PC指针,然后跳转执行Reset_Handler。
  • 2.强制PC指针指向中断向量表的复位中断向量执行复位中断函数;
  • 3.在复位中断函数中调用 SystemInit 函数,初始化时钟配置中断向量表
  • 4.调用 __main 函数完成全局/静态变量的初始化和重定位工作,初始化堆栈和库函数
  • 5.跳转到main函数中执行

复位中断函数详解

上面内核初始化的最后一步,是把复位中断函数Reset_Handler的地址赋值给PC指针,然后跳转执行复位中断处理函数,我们来看一下在复位中断里内核都做了哪些操作。
我们随便打开一个标准库工程的启动文件,都能找到下面这段代码:

; Reset handler                     //程序注释(汇编中;表示注释)
Reset_Handler    PROC               //定义了一个子程序:Reset_Handler
                 EXPORT  Reset_Handler             [WEAK]   //EXPORT  表明此函数可供启动模块调用
     IMPORT  __main               //IMPORT 表明函数定义在外部,链接时需要去寻找
     IMPORT  SystemInit            
                 LDR     R0, =SystemInit    //将SystemInit地址加载到R0寄存器
                 BLX     R0                 //跳转到R0执行SystemInit程序
                 LDR     R0, =__main        //将__main地址加载到R0寄存器
                 BX      R0                 //跳转到R0执行_main程序
                 ENDP                       //表明程序结束

根据代码我们可以看出,复位中断主要是调用了SystemInit__main 这两个函数,下面我们再来详细介绍下这两个函数都做了什么工作。

SystemInit函数详解

利用跳转功能,我们可以看到SystemInit()函数的代码部分:

/**
  * @brief   设置微控制器系统
  *         初始化嵌入式Flash接口、PLL,并且更新SystemCoreClock 变量
  * @note   此功能仅能在复位后使用.
  * @param  None
  * @retval None
  */
void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   
  
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL
  /* Reset PLL2ON and PLL3ON bits */
  RCC->CR &= (uint32_t)0xEBFFFFFF;

  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x00FF0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;      
#else
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
    
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 

  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  /* Configure the Flash Latency cycles and enable prefetch buffer */
  SetSysClock();

#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
}

根据上面的代码,我们可以看出,SystemInit()主要做了两件事:

  • 1、初始化时钟:SYSCLK,HCLK,PCLK2 PCLK1 预分频器等
  • 2、配置中断向量表:中断向量表的定位是在 Flash 还是 SRAM,以及是否需要偏移

注意:

  • 可以通过system_stm32f1xx文件中的宏定义修改系统时钟频率(通过设置锁相环的相关系数),中断向量表的地址(位于SRAM还是Flsah,是否偏移,偏移地址多少等参数)
  • 函数内含VTOR寄存器(即中断向量偏移)设置:SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; 产品IAP由BootLoader跳转到app程序时,需设置中断向量偏移。

__main函数详解

__main 其实不是我们定义的,当编译器编译时,只要遇到这个标号就会定义这个函数,该函数的主要功能是:负责初始化栈、堆,配置系统境,并在最后跳转到用户自定义的main函数,从此来到C的世界。
所以在不同的IDE该函数的名称也有所不同,但所实现的功能大同小异:

  • 完成全局变量/静态变量/常量的初始化和重定位工作
    • a. 跳转进入__scatterload_rt2函数:通过设置四个寄存器来配置待copy内容(静态变量、全局变量、常量)的的加载域和运行域,设置待copy内容的大小,为后续__scatterload_cpy()函数服务。
    • b. 跳转进入__scatterload_cpy函数,完成静态变量、全局变量、常量的从flash到SRAM的重定位。
    • c. 跳转进入__scatterload_zeroinit函数,完成未初始化的全局变量的初始化。
  • 初始化堆栈(这里指程序栈)
    • 跳转进入__user_steup_stackheap函数:调用 __user_libspac__user_libspace 为C库保持了静态数据。这是一个96字节,0初始化的数据块,该块由C库创建。在C库初始化期间可以用来当做临时栈。再调用 __user_initial_stackheap 用户的初始化堆栈函数,实现用户的堆栈的配置,调用 _fp_init 和 __rt_fp_status_addr (C库函数) 两个函数调用实现浮点运算的支持。
    • 如果在”魔法棒“—”Target“中编译勾选了”Use Micro_lib“,程序则采用单区存放堆栈的方式;否则,采用双区存储的方式,分别初始化堆区、栈区。
  • 程序跳转,进入main()函数,执行用户代码

最后,总结下STM32从Flash的启动流程:
1、初始化堆栈指针。 单片机复位后从0x0800 0000处读取栈顶地址并保存。
2、初始化PC指针。 从0x0800 0004读取中断向量表的起始地址(复位中断入口地址),接着跳转到复位程序
3、初始向量表,然后设置时钟,设置堆栈。
4、最后跳转到C空间的main函数,即进入用户程序。
STM32_启动流程详解,STM32,stm32,嵌入式硬件

附录

stm32单片机的存储器映像

类型 起始地址 存储器 用途
ROM 0x0800 0000 程序存储器Flash 存储C语言编译后的程序代码
0x1FFF F000 系统存储器 存储BootLoader,用于串口下载
0x1FFF F800 选项字节 存储一些独立于程序代码的配置参数
RAM 0x2000 0000 运行内存SRAM 存储运行过程中的临时变量
0x4000 0000 外设寄存器 存储各个外设的配置参数
0xE000 0000 内核外设寄存器 存储内核各个外设的配置参数

中断向量表的映射

BOOT启动方式主要有三种,主闪存存储器启动、系统存储器启动、内置SRAM启动,BOOT1和BOOT0在芯片复位时的电平状态决定了芯片复位后从哪个区域开始执行程序。

注:启动模式只决定程序烧录的位置,加载完程序之后会有一个重映射(映射到0x00000000地址位置)。所以说STM32上电复位以后,代码区都是从0x00000000开始的,三种启动模式只是将各自存储空间的地址映射到0x00000000中。

对应的BOOT引脚状态及启动地址如下图:

BOOT1 BOOT0 启动模式 启动地址 说明
X 0 主闪存存储器Flash 0x0800 0000 中断向量表定位于FLASH区,主闪存被选为启动区域,最常用,用户代码。同时复位后PC指针位于0x2000000处
0 1 系统存储器 0x1FFF F000 系统存储器被选为启动区域,程序功能由厂家设置。中断向量表定位于内置Bootloader区,此时可通过串口下载程序的二进制文件到flash区
1 1 内置SRAM 0x2000 0000 内置SRAM被选为启动区域,中断向量表定位于SRAM区,同时复位后PC指针位于0x2000000处

这篇写的很好,可以看一下:
链接: 【STM32】为什么STM32的Flash地址要设置到0x08000000文章来源地址https://www.toymoban.com/news/detail-766084.html

到了这里,关于STM32_启动流程详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 嵌入式毕设分享 stm32 RFID智能仓库管理系统(源码+硬件+论文)

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月20日
    浏览(69)
  • STM32串口通信详解(嵌入式学习)

    时钟信号在电子领域中是指用于同步和定时电路操作的周期性信号。它在数字系统和通信系统中起着至关重要的作用,用于协调各个组件之间的数据传输和操作。 时钟信号有以下几个重要的方面: 频率:时钟信号的频率是指单位时间内信号周期的数量。它通常以赫兹(Hz)为

    2024年02月09日
    浏览(67)
  • STM32的中断系统详解(嵌入式学习)

    中断是处理器中的一种机制,用于响应和处理突发事件或紧急事件。当发生中断时,当前正在执行的程序会被暂时中止,处理器会跳转到中断处理程序(也称为中断服务例程),对中断事件进行处理。处理完中断后,处理器再返回到被中断的程序继续执行。 中断可以分为内部

    2024年02月12日
    浏览(69)
  • STM32的定时器详解(嵌入式学习)

    想要了解STM32的时钟系统 点击这里跳转——》STM32的时钟系统(嵌入式学习) 建议先看看时钟树如何配置 点击这里跳转——》STM32的时钟树配置(嵌入式学习) 跳转——》STM32的时钟基础详解(嵌入式学习) 跳跳转——》STM32的时钟源详解(嵌入式学习) SysTick又称滴答定时

    2024年02月13日
    浏览(67)
  • 单片机STM32看门狗详解(嵌入式学习)

    单片机STM32的看门狗(Watchdog)是一种硬件定时器,用于监控系统的运行状态并在出现故障或死锁时采取措施以恢复正常操作。看门狗的主要功能是定期检查系统是否正常运行,并在系统出现问题时触发复位操作。 STM32系列单片机通常配备了内置的看门狗定时器(通常称为独立

    2024年02月13日
    浏览(61)
  • 嵌入式STM32 单片机 GPIO 的工作原理详解

    STM32的 GPIO 介绍 GPIO 是通用输入/输出端口的简称,是 STM32 可控制的引脚。GPIO 的引脚与外部硬件设备连接,可实现与外部通讯、控制外部硬件或者采集外部硬件数据的功能。 以 STM32F103ZET6 芯片为例子,该芯片共有 144 脚芯片,包括7个通用目的的输入/输出口(GPIO)组,分别为

    2024年02月20日
    浏览(48)
  • stm32嵌入式实验考核

    STM32 实验考核题目 1. 利用 STM32 小板实现:控制外接 LED 灯每隔 3 秒钟亮暗变换,同 时在 PC 机上显示 MCU 的计时时间,MCU 的初始时间由 PC 机 方设置。 2. 利用 STM32 小板实现:利用导线外接 GPIO 口模拟 2 个按键输入, 根据输入组合的四种情况,分别控制三色灯四种流水灯效果

    2024年02月03日
    浏览(49)
  • 嵌入式——新建STM32工程(标准库)

    目录 一、初识标准库 1.CMSIS标准及库层级关系 2.库文件介绍 (1)Libraries文件夹 ①CMSIS文件夹 ②STM32F10x_Std_Periph_Driver文件夹 ③ 在用库建立一个完整的工程时,还需要添加stm32f10x_it.c、 stm32f10x_conf.h 和 system_stm32f10x.c文件 (2)Project文件夹 (3)Utilities文件夹 3.库各文件之间的关

    2024年01月23日
    浏览(55)
  • STM32的时钟系统(嵌入式学习)

    时钟是指用于计量和同步时间的装置或系统。时钟是嵌入式系统的脉搏,处理器内核在时钟驱动下完成指令执行,状态变换等动作,外设部件在时钟的驱动下完成各种工作,例如:串口数据的发送、AD转换、定时器计数等。因此时钟对于计算机系统是至关重要的,通常时钟系

    2024年02月16日
    浏览(47)
  • 嵌入式 STM32 通讯协议--MODBUS

    目录 一、自定义通信协议 1、协议介绍 2、网络协议 3、自定义的通信协议  二、MODBUS通信协议 1、概述 2、MODBUS帧结构  协议描述 3、MODBUS数据模型   4、MODBUS事务处理的定义 5、MODBUS功能码  6、功能码定义   7、MODBUS数据链路层 8、MODBUS地址规则  9、MODBUS帧描述 10、MODBUS两种

    2024年02月11日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包