当前位置: 首页 > article >正文

STM32文件详解

STM32文件详解

  • 启动文件
    • 打开MDK
    • 栈空间开辟
    • 堆空间开辟
    • 中断向量表
    • 复位程序
    • 对于 weak 的理解
    • 对于_main 函数的分析
    • 中断程序
    • 堆栈初始化
    • 系统启动流程
  • 时钟树
    • 时钟源
    • 时钟配置函数
    • 时钟初始化配置函数

启动文件

启动文件的方式

1、初始化堆栈指针 SP = _initial_sp
2、初始化程序计数器指针 PC = Reset_Handler
3、设置堆和栈的大小
4、初始化中断向量表
5、配置外部 SRAM 作为数据存储器(可选)
6、配置系统时钟,通过调用 SystemInit 函数(可选)
7、调用 C 库中的 _main 函数初始化用户堆栈,最终调用 main 函数

在这里插入图片描述

打开MDK

MDK->Help->uVision Help,
在这里插入图片描述

栈空间开辟

在这里插入图片描述

堆空间开辟

在这里插入图片描述
PRESERVE8:指示编译器按照 8 字节对齐。
THUMB:指示编译器之后的指令为 THUMB 指令

中断向量表

在这里插入图片描述
在这里插入图片描述

__Vectors 为向量表起始地址, __Vectors_End 为向量表结束地址,__Vectors_Size 为向量表大小,>__Vectors_Size = __Vectors_End - __Vectors。

复位程序

接下来是定义只读代码段

在这里插入图片描述

复位子程序代码
在这里插入图片描述
利用 PROC、ENDP 这一对伪指令把程序段分为若干个过程,使程序的结构加清晰。

对于 weak 的理解

weak 顾名思义是“弱”的意思,在汇编中,在函数名称后面加[WEAK]来表示,而在 C 语言中,在函数名称前面加上__weak 修饰符来表示,这样的函数我们称为“弱函数”。
被[WEAK]或__weak 声明的函数,我们可以在自己的文件中重新定义一个同名函数, 最终编译器编译的时候,会选择我们定义的函数,如果我们没有重新定义这个函数,那么编译器就会执行[WEAK]或__weak 声明的函数,并且编译器不会报错

对于_main 函数的分析

_main 代码是编译器自动创建的,因此无法找到_main 代码。
程序经过汇编启动代码,执行到__main()后,负责初始化堆栈,完成库函数的初始化,最后自动跳转向 main()函数。

中断程序

在这里插入图片描述

堆栈初始化

ALIGN指指令或数据的存放地址进行对齐,一般需要跟一个立即数
勾选了 Use MicroLIB 就代表定义了__MICROLIB 这个宏。
接下来进行堆栈空间初始化,堆是从低到高生长,栈是从高到低生长,是两个互相独立 的数据段,并且不能交叉使用。
Use MicroLIB
MicroLIB 是 MDK 自带的微库,是缺省 C 库的备选库,MicroLIB 进行了高度优化使得其代码变得很小,功能比缺省 C 库少。MicroLIB 是没有源码的,只有库。

系统启动流程

在这里插入图片描述

时钟树

在这里插入图片描述
一个简化的 STM32F1 时钟系统。图中已经把我们主要关注几处标注出来。
A 部分表示其它电路需要的输入源时钟信号;
B 为一个特殊的振荡电路“PLL”,由几个部分构成;
C 为我们重点需要关注的 MCU 内的主时钟“SYSCLK”;AHB 预分频器将 SYSCLK 分频或不分 频后分发给其它外设进行处理,包括到 F 部分的 Cortex-M 内核系统的时钟。
D、E 部分别为定时器等外设的时钟源 APB1/APB2。
G 是 STM32 的时钟输出功能,其它部分等我们学习到再详细探讨。

时钟源

对于 STM32F1,输入时钟源(Input Clock)主要包括 HSI,HSE,LSI,LSE。其中,从时钟频率来分可以分为高速时钟源和低速时钟源,其中 HSI、HSE 高速时钟,LSI 和 LSE 是低速时钟。
从来源可分为外部时钟源和内部时钟源,外部时钟源就是从 外部通过接晶振的方式获取时钟源,其中 HSE 和 LSE 是外部时钟源;其他是内部时钟源,芯片上电即可产生,不需要借助外部电路。

时钟配置函数

SYSCLK(系统时钟) =72MHz
AHB 总线时钟(HCLK=SYSCLK) =72MHz
APB1 总线时钟(PCLK1=SYSCLK/2) =36MHz
APB2 总线时钟(PCLK2=SYSCLK/1) =72MHz
PLL 主时钟 =72MHz

时钟初始化配置函数

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 函数开始通过条件编译,先复位 RCC 寄存器,同时通过设置 CR 寄存器的 HSI 时钟使能位来打开 HSI 时钟。

  1. 时钟控制寄存器(RCC_CR)
  2. 时钟配置寄存器(RCC_CFGR)
  3. 时钟中断寄存器(RCC_CIR)
  4. APB2 外设复位寄存器(RCC_APB2RSTR)和APB1 外设复位寄存器

默认情况下如果 CR 寄存器复位, 是选择 HSI 作为系统时钟,这点大家可以查看 RCC->CR 寄存器相关位描述可以得知,当低两位配置为 00 的时候(复位之后),会选择 HSI 振荡器为系统时钟。

在 system_stm32f10x.c 文件的开头就有对此宏定义,系统默认的宏定义是72MHz

#define SYSCLK_FREQ_72MHz 72000000

如果你要设置为 36MHz,只需要注释掉上面代码

#define SYSCLK_FREQ_36MHz 36000000 

http://www.kler.cn/a/451797.html

相关文章:

  • 将Minio设置为Django的默认Storage(django-storages)
  • 强力巨彩租赁屏技术更新,适用多种户外应用场景
  • 【MinIO系列】MinIO Client (mc) 完全指南
  • 绩效考核试题
  • vue3标签中的ref属性如何使用$refs获取元素
  • JAVA开发入门学习七- 数组
  • 从 GitLab.com 到 JihuLab.com 的迁移指南
  • leetcode之hot100---19删除链表的第N个节点(C++)
  • GitLab 将停止为中国区用户提供服务,60天迁移期如何应对? | LeetTalk Daily
  • 【NLP高频面题 - 高效微调篇】什么是提示微调?
  • 全国硕士研究生入学考试(考研)备考要点之备考原则
  • GMV 含义
  • 【R语言遥感技术】“R+遥感”的水环境综合评价方法
  • 接口请求中调试可以看到Origin,其具体的作用
  • 【文档搜索引擎】缓冲区优化和索引模块小结
  • 框架专题:设计模式
  • mvn install:install-file jar 打入本地仓库
  • 虚拟机桥接模式
  • Spark和Hive的联系
  • 【视觉惯性SLAM:SLAM中常用的数学基础知识】
  • BOM清单在制造企业运营中的全方位作用解析
  • 高并发处理 --- Caffeine内存缓存库
  • 【每日学点鸿蒙知识】私仓搭建、resources创建文件夹、hvigor如何动态设置版本、SM3摘要算法、SP存储报错等
  • 【MySQL】7.0 入门学习(七)——MySQL基本指令:帮助、清除输入、查询等
  • mysql的存储碎片
  • PHP后执行php.exe -v命令报错并给出解决方案