STM32 时钟树配置快速入门
layout: post
tags: [STM32]
comments: true
文章目录
为什么要了解时钟树?
最近项目开发的时候,外部时钟源是16MHz
,结果配置错了系统时钟,STM32F103
的系统时钟频率最高为72MHz
,错误地配置到了144MHz
,但是AHB
总线时钟又正确地配置到72MHz
,最终导致了以下几种情况:
- 程序会意外跑飞,然后进入
Hard fault
,甚至不知道发生了什么,就出现这样的错误; - 数据意外错误,
int32
负数乘法的时候,第30位数据异常;
以上的问题,较难排查,而且给人一种芯片不稳定的错觉,对的,没错,这就是超频的代价,高速行驶的汽车,更容易翻车,所以,对于芯片的时钟配置有一个全面的了解,有着弥足轻重的作用。
树的根
先看一下这张从网上扒来的图,说到树,不由自主想到了二叉树,设备树,森林里的树,而时钟树,也不例外,和这些树一样,都有根,有叶子,做一下简单的类比;
根是树汲取营养的地方,是树赖以生存的一个部位;
而时钟树的根就是时钟输入源,用于产生系统的时钟节拍,即系统时钟;
系统时钟源:
- 高速内部时钟
HSI
,8MHz
; - 高速外部时钟
HSE
,4MHz
–25MHz
; - 锁相环时钟
PLL
;
常用的配置方案例如:选用外部时钟HSE
,频率为8MHz
,经过锁相环时钟,PLL
进行9倍频,则系统时钟频率:
SysClock = 8MHz*9 = 72Mhz
或者使用外部时钟HSE
,频率为16MHz
,则经过锁相环时钟,PLL
2分频,然后9倍频,则系统时钟频率:
SysClock = 16MHz/2*9 = 72Mhz
可见,PLL
时钟源的使用很灵活,可以灵活运用;
标准库的时钟配置
从STM32
标准库的启动文件中可以发现,在main()
运行前,已经运行了SystemInit()
函数,代码如下,IDE是MDK
,代码如下,具体可以参考
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
标准库是默认按照外部高速时钟频率为8MHz
进行配置的,SystemInit()
函数原型位于system_stm32f10x.c
,具体的调用关系如下,具体源码可以参考标准库;
SystemInit()
-->SetSysClock()
-->SetSysClockTo72()
在函数SetSysClock()
通过宏定义选择系统所需要配置的时钟频率;
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
SetSysClockTo72();
#endif
/* If none of the define above is enabled, the HSI is used as System clock
source (default after reset) */
}
函数SetSysClockTo72
默认定义系统时钟为72MHz
#define SYSCLK_FREQ_72MHz 72000000
初始化后系统的状态:
时钟 | 频率 |
---|---|
SYSCLK | 72MHz |
AHB | 72MHz |
PCLK1 | 36MHz |
PCLK2 | 72MHz |
PLL | 72MHz |
外部时钟源16M
SetSysClockTo72
如果外部时钟源的频率是16M
,需要进行哪些修改?
根据源码可以知,最终在SetSysClock
中进行修改即可,因为要配置到72M
的系统时钟频率,则直接进入函数SetSysClockTo72()
进行修改;
SetSysClockTo72
源码如下;或者跳过源码直接看patch
文件;
/**
* @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2
* and PCLK1 prescalers.
* @note This function should be used only after reset.
* @param None
* @retval None
*/
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;
/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------*/
/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}
/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
RCC_CFGR_PLLMULL9);
#else
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
#endif
patch
需要修改两个地方:
stm32f10x.h
中HSE_VALUE
的值;system_stm32f10x.c
中SetSysClockTo72(void)
函数的PLL
配置;
patch
如下所示;
diff --git a/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/stm32f10x.h b/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/stm32f10x.h
index 8bf7624..e0ad316 100644
--- a/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/stm32f10x.h
+++ b/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/stm32f10x.h
@@ -116,7 +116,9 @@
#ifdef STM32F10X_CL
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#else
- #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
+// #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
diff --git a/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c b/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c
index 71efc85..4ff040a 100644
--- a/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c
+++ b/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c
@@ -1053,7 +1053,7 @@ static void SetSysClockTo72(void)
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
- RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
+ RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLXTPRE_HSE_Div2);
#endif /* STM32F10X_CL */
/* Enable PLL */
这样就完成了基本配置的修改。
其他细节
- RTC的时钟来源:
LSE
,LSI
,LSE的128分频
- 独立看门狗IWDGCLK的时钟来源:
LSI
- APB1总线的时钟,最大到36M
- APB2总线的时钟,最大到72M
- APB,APB1,APB2为外设提供时钟。
STM32 时钟树配置快速入门的更多相关文章
- STM32—时钟树(结合系统时钟函数理解)
时钟树的概念: 我们可以把MCU的运行比作人体的运行一样,人最重要的是什么?是心跳! 心脏的周期性收缩将血液泵向身体各处.心脏对于人体好比时钟对于MCU,微控制器(MCU)的运行要靠周期性的时钟脉冲来 ...
- STM32入门系列-STM32时钟系统,STM32时钟树
时钟对于单片机来说是非常重要的,它为单片机工作提供一个稳定的机器周期从而使系统能够正常运行.时钟系统犹如人的心脏,一旦有问题整个系统就崩溃.我们知道STM32属于高级单片机,其内部有很多的外设,但不是 ...
- CodeIgniter框架——数据库类(配置+快速入门)
CodeIgniter用户指南——数据库类 数据库配置 入门:用法举例 连接数据库 查询 生成查询结果 查询辅助函数 Active Record 类 事务 表格元数据 字段元数据 自定义函数调用 查询 ...
- Linux下时钟框架实践---一款芯片的时钟树配置
关键词:时钟.PLL.Mux.Divider.Gate.clk_summary等. 时钟和电源是各种设备的基础设施,整个时钟框架可以抽象为几种基本的元器件:负责提供晶振 Linux内核提供了良好的CC ...
- STM32 TIM1高级定时器配置快速入门
layout: post tags: [STM32] comments: true 文章目录 layout: post tags: [STM32] comments: true 重点内容 时基单元 计 ...
- STM32 TIM 多通道互补PWM波形输出配置快速入门
platform:stm32f10xxx lib:STM32F10x_StdPeriph_Lib_V3.5.0 前言 在做三相逆变的时候,需要软件生成SVPWM波形,具体的算法需要产生三对互补的PWM ...
- 【python】pycharm常用配置快速入门。
俗话说,工欲善其事必先利其器.当我们想从事一门新的语言的时候,最重要的是熟悉其常用的编辑器的配置.刚好这两天在学习python,网上看到一篇比较好的文章,转载过来自己学习一下.感谢:https://s ...
- STM32时钟树
STM32的时钟系统 相较于51单片机,stm32的时钟系统可以说是非常复杂了,我们现在看下面的一张图: 上图说明了时钟的走向,是从左至右的从时钟源一步步的分配给外设时钟.需要注意的是,上图左侧一共有 ...
- Prometheus入门教程(三):Grafana 图表配置快速入门
文章首发于[陈树义]公众号,点击跳转到原文:https://mp.weixin.qq.com/s/sA0nYevO8yz6QLRz03qJSw 前面我们使用 Prometheus + Grafana ...
随机推荐
- 文件密码忘记了怎么办,教你如何使用Python破解密码
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:轻松学编程小梁 PS:如有需要Python学习资料的小伙伴可以加点击下 ...
- MySQL 归纳总结
1.MySQL存储引擎 主要使用的就是两个存储引擎,分别是InnoDB和MyISAM. InnoDB InnoDB是MySQL的默认存储引擎.InnoDB采用MVCC来支持高并发,并且实现了四个标准的 ...
- Django系列操作
每次用到都去百度找....找的还不行~~得自己改~~耗时耗力虽然不难~~~直接贴代码记录下方便自己用~~~~ Django之分页 定义成一个块,直接引用到对应的位置即可... <div clas ...
- 【题解】P1291 百事世界杯之旅 - 期望dp
P1291 [SHOI2002]百事世界杯之旅 声明:本博客所有题解都参照了网络资料或其他博客,仅为博主想加深理解而写,如有疑问欢迎与博主讨论✧。٩(ˊᗜˋ)و✧*。 题目描述 "--在 \ ...
- 如何将dotnet core webapi发布到docker中…
如何将dotnet core webapi发布到docker中 今天想起来撸一下docker,中途还是遇到些问题,但是这些问题都是由于路径什么的导致不正确,在这儿还是记录下操作过程,今天是基于wind ...
- Java封装 概述
封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式.好处:隐藏实现细节,提供公共的访问方式提高了代码的复用性提高安全性 封装原则:将不需要对外提供的内容都隐藏起来把属性隐藏,提供公共方法对其访 ...
- Java面试系列第3篇-HashMap相关面试题
HashMap是非线程安全的,如果想要用线程安全的map,可使用同步的HashTable或通过Collections.synchronizeMap(hashMap)让HashMap变的同步,或者使用并 ...
- C/C++,被誉为“最经典的编程语言”,不仅是因为编程入门需要学?
计算机诞生初期,用机器语言或汇编语言编写程序; 第一种高级语言FORTRAN诞生于1954年; BASIC语言(1964)是由FORTRAN语言的简化而成的是为初学者设计的小型高级语言; C语言是19 ...
- beego rel/reverse
用户可以发布多个文章 对用户来说是一对多 对文章来说是多对一 用户是主表 文章是用户的从表 rel用在从表中,给主表结构体设置主键,也就是文章表对应用户表的外键 reverse用在主表中,指定主表与从 ...
- weblogic补丁升级详细步骤,18.7.17补丁更新
weblogic打补丁 到weblogic官网下载补丁包 对应的补丁包 如: p22248372_1036012_Generic.zip 一 安装补丁步骤 1.登录linux的weblogic用户 ...