1. 前言
本文将介绍MM32F3270系处理器的时钟系统,将分别以内部高速时钟HSI、外部高速时钟作为输入时钟源,经锁相环PLL分频和倍频后得到更高的系统时钟,本次代码将会从寄存器层次来配置,而不是使用MindSDK库。
2. 时钟树
我们先来认识下MM32F3270的时钟树:
我们将时钟树从【SYSCLK】即【系统时钟】处将这张图一分为二,左侧是时钟输入源以及时钟信号输出到MCO线;右侧是将系统时钟经过分频输出给USB和各总线、外设以及定时器。
我们可以看到,MM32F3270有四个时钟输入源:
- HSI——内部高速时钟;
- HSE——外部高速时钟;
- LSE——外部低速时钟;
- LSI——内部低速时钟;
这四个输入时钟皆可用于配置系统时钟SYSCLK,其中HSI和HSE还可以用作PLL的输入源,经过分频和倍频得到更高主频的系统时钟。当配置好系统时钟后,就可以分频配置USB、总线和外设的时钟了。
2.1 HSI配置系统时钟
- 如果SYSCLK选择以HSI作为系统时钟,那么,SYSCLK的值就是HSI经1/2/4/8/16/32/64/128倍分频后的值,最大只能达到HSI的时钟频率8MHz;
- 如果SYSCLK选择以PLL作为系统时钟,且PLL的输入时钟源来自于HSI,可以看到,是HSI经过1分频后输入到锁相环PLL单元的。也就是说,此时PLL的输入时钟就是HSI的8MHz,然后经PLL的倍频器PLLMUL及其分频器PLLDIV设置倍频系数和分频系数输出给SYSCLK;假设PLLMUL=30,PLLDIV=2,那么SYSCLK=PLLSRC/PLLDIV*PLLMUL=8MHz/2*30=120MHz;
2.2 HSE配置系统时钟
- 和HSI需经过一个分频器再输出给SYSCLK不同的是,当使用HSE直接作为SYSCLK的时钟源时,中间不需要分频,即HSE的时钟频率就是系统频率;
- 如果SYSCLK的时钟源是PLL且PLL的时钟源是HSE,那么HSE会经过一个固定分频系数的分频器2分频后输入给PLL,然后再经由PLL分频和倍频得到更高的系统时钟,假设HSE=8MHz,那么这个时候,PLLDIV就可以设置为1,而PLLMUL照样还是30,同样可以得到120MHz的系统时钟;
2.3 LSI配置系统时钟
可以看到,系统时钟还可以选择LSI作为时钟输入源,得到一个更低频的系统时钟。
2.4 时钟输出
2.4.1 USB时钟
从时钟树的分析可以看到,USB的时钟来自于PLL的输出时钟分频之后的时钟,它支持的最高时钟频率是48MHz,所以如果我们的PLL输出时钟被配置为系统时钟支持的最大时钟频率120MHz,那么USB的时钟最大只能是由PLL经过3分频之后的时钟40MHz;而想要USB工作在最大时钟频率,我们只能将PLL的输出时钟配置为96MHz,再经由2分频后输出给USB,这时候系统时钟的频率也只能达到96MHz。
2.4.2 总线时钟
MM32F3270的总线有以下几条:
- AHB总线:时钟是系统时钟SYSCLK经过AHB预分频器分频后产生的;
- APB1:时钟是AHB总线时钟经APB1预分频器分频后产生的;
- APB2:时钟是AHB总线时钟经APB2预分频器分频后产生的;
2.4.3 外设和定时器时钟
外设分为:
- AHB总线上的外设:时钟就是AHB总线的时钟;
- APB1总线上的外设:时钟就是APB1总线的时钟;
- ABP2总线上的外设:时钟就是APB2总线的时钟;
- ADC:时钟是APB2总线时钟经ADC预分频器分频后产生的;
- 高级定时器1和8:时钟是系统时钟SYSCLK经高级定时器预分频器分频后产生的;
定时器分为:
- 滴答定时器:滴答定时器的时钟可以来自于AHB总线时钟8分频后产生,也可以来自其它时钟源,将分为单独的一章节来介绍内核的滴答定时器;
- APB1总线上的定时器:如果APB1的预分频系数是1,那么APB1总线上的定时器的时钟就是APB1不分频后产生的时钟;而如果APB1的预分频系数不为1,那么此时APB1总线上的定时器时钟就是将APB1总线的时钟2倍频之后的时钟;
- APB2总线上的定时器:时钟分析和APB1总线上的定时器时钟类似;
2.4.4 MCO
MCO:微控制器时钟输出,可以将选择的时钟源输出到MCO引脚上,其来源可以是:
- PLL输出时钟2分频;
- HSI;
- HSE;
- LSE;
- SYSCLK;
- LSI;
2.4.5 RTC时钟
RTC的时钟来源有2:
- HSE经128分频后的时钟;
- LSE;
- LSI;
2.4.6 独立看门狗IWDG的时钟
IWDG的时钟只能来源于LSI。
3. 配置系统时钟
配置系统时钟除了配置RCC单元之外,还要配合内部FLASH特性和电源管理单元来设置。配合内部FLASH是因为读写内部flash的时候,如果主频过高,就要设置内部flash的预缓冲区和等待周期,目的是为了正常的从flash中读取指令和读写数据;配置电源管理单元则是MM32F3270这个处理器的要求,需要我们去遵从。
3.1 配置内部Flash的参数
- 使能内部Flash时钟
内部Flash是挂载再AHB总线上的,因而需要在AHB总线上使能Flash这个外设的时钟,通过查看RCC的AHB寄存器,可以看到是在RCC的AHB1ENR寄存器中使能内部Flash的时钟的:
我们需要将RCC_AHB1ENR的第13位写1:
1 | RCC->AHB1ENR |= (1u << 13u); // 使能FLASH外设 |
- 配置等待周期
在MM32F3270的用户手册中的第【2.3.1】小节有这样一段话:
这段话是中文就不多做解释了,来看一下官方给的系统时钟和Flash latency值之间的关系表:
所以从这个表中我们可以得到,如果要系统时钟工作在96MHz或者120MHz,Flash的latency值需要设置成4,而设置Flash的latency值是在Flash的ACR寄存器:
1 | FLASH->ACR |= (4<<0); // 设置Flash的等待周期 |
3.2 配置电源管理单元
此经验是阅读MM32F3270的手册,看到3.5.1章节PWR的CR1寄存器发现的:
所以在配置时钟前,还需要:
1 | PWR->CR1 &= ~(2<<14); |
3.3 配置HSI用作系统时钟
配置HSI用作系统时钟主要由两个步骤:
使能HSI;
- 配置时钟控制寄存器(RCC_CR)中的HSION 位为1,使能HSI;
- 等待时钟控制寄存器(RCC_CR)中的 HSIRDY 位被置位为 1,表示 HSI 稳定,可输出有效时
钟,此时才可被选择使用作为系统时钟或外设时钟源。
系统时钟源选择HSI;
- 通过配置时钟配置寄存器(RCC_CFGR)的SW 位来选择系统时钟;
- 通过读取时钟配置寄存器(RCC_CFGR)的SWS 位,判断当前系统时钟的时钟源。
上电复位后的系统时钟就是HSI
3.4 配置HSE用作系统时钟
配置HSE用作系统时钟主要由两个步骤:
使能HSE;
- 配置时钟控制寄存器(RCC_CR)中的HSEON 位为 1,使能 HSE
- 等待时钟控制寄存器(RCC_CR)中的HSERDY 位被置位为1,表示 HSE 稳定,会输出有效时
钟信号,此时才可被选择使用作为系统时钟或外设时钟源。
系统时钟源选择HSI;
- 通过配置时钟配置寄存器(RCC_CFGR)的SW 位来选择系统时钟;
- 通过读取时钟配置寄存器(RCC_CFGR)的SWS 位,判断当前系统时钟的时钟源。
所以根据前面的内容,得到配置代码:
1 | static void SystemConfigUseHSE(void) |
3.5 配置PLL用作系统时钟
3.5.1 HSI用作PLL的输入时钟
将HSI用作PLL输入时钟配置高频的系统时钟,步骤如下:
配置时钟控制寄存器(RCC_CR)中的HSION 位为1,使能HSI;
等待时钟控制寄存器(RCC_CR)中的 HSIRDY 位被置位为 1,表示 HSI 稳定,可输出有效时
钟,此时才可被选择使用作为系统时钟或外设时钟源;配置PLL 配置寄存器 (RCC_PLLCFGR)中PLLMUL(倍频系数)和PLLDIV(分频系数)控
制位;配置时钟控制寄存器(RCC_CR)中的PLLON 位为1,使能PLL;
等待时钟控制寄存器(RCC_CR)中的 PLLRDY 位被置位为 1,表示 PLL 稳定,可输出有效时
钟,此时才可被选择使用作为系统时钟或外设时钟源。配置RCC_CFGR选择PLL作系统时钟源并等待稳定;
所以根据前面的内容,得到配置代码:
1 | /* 配置HSO和PLL */ |
3.5.2 HSE用作PLL的输入时钟
将HSE用作PLL输入时钟配置高频的系统时钟,步骤如下:
- 配置时钟控制寄存器(RCC_CR)中的HSEON 位为 1,使能HSE;
- 等待时钟控制寄存器(RCC_CR)中的HSERDY 位被置位为1,表示 HSE 稳定,可输出有效时钟,此时才可被选择使用作为系统时钟或外设时钟源;
- 配置 PLL 配置寄存器(RCC_PLLCFGR)中的 PLLSRC 位为 1,选择 HSE 时钟用作 PLL 输入
时钟源; - 配置PLL 配置寄存器(RCC_PLLCFGR)中的PLLXTPRE 位,选择HSE 或者HSE 2 分频时钟
为PLL 输入时钟源; - 配置PLL 配置寄存器 (RCC_PLLCFGR)中PLLMUL(倍频系数)和PLLDIV(分频系数)控
制位; - 配置时钟控制寄存器(RCC_CR)中的PLLON 位为1,使能PLL;
- 等待时钟控制寄存器(RCC_CR)中的 PLLRDY 位被置位为 1,表示 PLL 稳定,可输出有效时
钟,此时才可被选择使用作为系统时钟或外设时钟源。 - 配置RCC_CFGR选择PLL作系统时钟源并等待稳定;
所以根据前面的内容,得到配置代码:
1 | /* 配置HSE和PLL */ |
3.6 配置总线时钟
1 | /* 配置系统时钟、AHB、APB时钟 */ |
根据RCC_CFGR寄存器以及时钟树的分析来自定义配置。
3.7 综合代码
1 |
|
4. 获取系统时钟和总线时钟
获取系统时钟是根据寄存器的内容,简单的加减乘除后写成程序计算的:
1 |
|
5. 验证
1 |
|
通过调试查看寄存器的值以及变量sysfreq的值是否如预期。
- 本文作者: 摘星星的小朋友
- 本文链接: http://slhking.github.io/2022/05/10/MM32-3-SystemClock/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!