STM32 中级
前言
仍然是学习自野火F407网课。
启动文件详解
作用:
- 初始化堆栈指针 SP=_initial_sp
- 初始化 PC 指针 =Reset_Handler
- 初始化中断向量表
- 配置系统时钟
- 调用 C 库函数 _main 初始化用户堆栈,从而最终调用 main 函数去到 C 的世界
栈:局部变量,函数定义,函数形参等。
Stack_Size EQU 0x00000400 ; 设置栈大小,EQU 相当于宏定义
AREA STACK, NOINIT, READWRITE, ALIGN=3 ; AREA 用于定义新代码段,数据段。这里定义了一个段叫 STACK,不初始化,可读可写,按3字节对齐
Stack_Mem SPACE Stack_Size ; 分配内存空间
__initial_sp ; 初始化堆栈,指向栈底(高地址)
栈的大小不能超过内部 SRAM 的大小。如果编写的程序比较大,定义的局部变量很多,那么就需要修改栈的大小。如果某一天,你写的程序出现了莫名奇怪的错误,并进入了硬 fault 的时候,这时你就要考虑下是不是栈不够大,溢出了。
堆:动态分配的,需要的空间就比栈小一些。
Heap_Size EQU 0x00000200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8 ; 堆栈按8字节对齐
THUMB ; 标明后面指令为 THUMB 指令
向量表:32位的整形数组,包含许多异常 ESR 的入口地址。
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
; 后跟向量表
程序一开始从 Reset 开始。
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK] ; WEAK 是弱定义,意思是如果外部文件也定义了 Reset_Handler 则优先使用外部文件的。所以我们自己定义中断函数的时候就会覆盖。不过其实这里面大多数 Handler 只是空函数
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit ; 初始化系统时钟
BLX R0
LDR R0, =__main ; 这个并不是我们自己写的 main 函数,而是c库中的函数,需要勾选 use microLib 引入。初始化一些局部变量,且跳转到我们的 main 函数
BX R0
ENDP
系统时钟详解
前面介绍过在 SystemInit 里对系统时钟进行了配置,这节课主要是分析其具体原理。
我们需要选择系统时钟的时钟源,并且把系统时钟作为一些外设的时钟使用。
野火教程图片示例如下:
时钟源选择
我自己的流程图如下,系统时钟的时钟源选择:
HSE:外部高速时钟信号。
HSI:高速内部时钟。一般常用的还是 HSE,精度更高,HSI 一般用于 HSE 故障时临时启动直至 HSE 启动成功。
PLL:锁相环,对时钟信号倍频。图中 HSE 分频后/MN/P 得到 PLLCLK。为什么不直接把晶振做的频率很高,而是用锁相环倍频?因为高频晶振更容易被外界干扰影响。*
首先对于锁相环部分时钟,我们从晶振输入(需要使能 HSE),分频,锁相环倍频,得到 PLLCLK 锁相环时钟。
然后SysCLK 系统时钟的时钟源,我们可以选择 HSI HSE SysCLK,这里我们选择 SysCLK。
RCC_CR 高16位配置 HSE,低位配置 HSI。
RCC_CR 最后一位 ON 用于启用时钟,RCC_CFGR 中的 SW01 用于选择 HSI HSE PLL。
锁相环
锁相环相比直接用 HSI HSE 作为时钟源,优势在于可以倍频。
PLLSRC 选择锁相环的时钟源是 HSE 还是 HSI。
PLLM 分频因子,PLLN 倍频因子,PLLP 又是一个分频。P 是系统时钟用,Q 是一些外设比如 USB OTG 用,R 在 407 中没有使用。
我们开发板配置是 SYSCLK = 25MHz / M:25 * N:336 / P:2=168MHz ,也可以改变分频因子值,168 是最大值。
外设时钟配置
AHB 预分频器:分频之后得到 AHB 总线时钟。AHB 为外设,定时器,内核提供时钟。
APB 预分频器:在 AHB 预分频后进一步预分频。APB 为 APB 上的外设提供时钟。
RCC_CFGR 中 HPRE,PPRE12 代表 AHB1,APB12 的分频选择。
RTC:为芯片内部的 RTC 提供时钟,时钟源可以是 HSE LSE LSI。
看门狗:LSI 提供。
MCO:时钟可以作为输出。比如外接一个摄像头,可以用 MCU 内的时钟。
I2S:音频信号。可由外部时钟或 PLL 提供。
以太网 PHY:开发板上没有 PHY 物理接口收发器芯片,因此由外部源作时钟。