MM32F0140学习笔记-时钟系统RCC
RCC 是 Reset and Clock Control 模块的缩写,可用于复位片上外设模块寄存器以及设置时钟树的时钟频率。本篇笔记将探讨 MM32F0140 微控制器上复位寄存器和设置时钟的操作流程,并以 pokt-f0140 开发板作为实际演示平台进行实验,实现 48MHz 开发板系统时钟。
RCC 功能描述
软件复位片上外设模块寄存器
通过设置 RCC_AHBRSTR 寄存器、RCC_APB1RSTR 寄存器以及 RCC_APB2RSTR 寄存器中对应外设模块位,可以实现软件复位片上外设模块寄存器。
设置时钟树频率
图 1. RCC 时钟树框图
如图 1 所示,RCC 时钟树主要分成以下四部分:
- 系统时钟
- MCO时钟输出
- 总线时钟
- 外设时钟
下文将探讨 RCC 时钟树上系统时钟的配置流程、系统时钟与总线时钟的关系以及部分外设时钟与总线时钟的关系。
配置系统时钟
MM32F0140 支持四个独立时钟源:
- 高速内部时钟(HSI)
- 高速外部时钟 (HSE)
- 锁相环(PLL)
- 低速内部时钟(LSI)
通过配置 RCC_CFGR[SW] ,可以选择不同的时钟源作为系统时钟源。通过读取RCC_CFGR[SWS] 的值,可以确定系统时钟源选择。值得注意的是,当使能上述四个时钟源后,需要等待 RCC 寄存器中对应的时钟准备就绪标志被拉高,才能确认时钟源被使能完成。( eg. 配置 RCC_CR[HSION] = 1 也即使能高速内部时钟后, 需要等待 RCC_CR[HSIRDY] 被拉高后,才能确认 HSI 准备就绪。)
在上述四个独立时钟源中,PLL 配置相对复杂。PLL 频率取决于 PLL 输入时钟频率 FREFIN、 PLL 时钟倍频因子N 以及PLL 时钟分频因子M和P。PLL 频率 FCLKO 的计算公式为
FCLKO = FREFIN N / ( M P )
其中,输入时钟频率 FREFIN, 可以通过配置 RCC_PLLCFGR[PLLXTPRE] 和 RCC_PLLCFGR[PLLSRC] 进行选择 ,可选项有 HSI 输出时钟频率 、HSE 输出时钟频率以及 HSE 输出时钟的 2 分频频率。配置此项前,需要使能对应的时钟输入源。分频因子 M = RCC_PLLCFGR[PLL_DM] + 1, P = RCC_PLLCFGR[PLL_PM] + 1; 倍频因子 N = RCC_PLLCFGR[PLL_DN] + 1。这三个系数可以通过配置 PLLCFGR 寄存器的相应位实现。M 值 和 P 值的区别在于,M 值是 PLL 对于输入时钟频率的分频, P 值是 PLL 作为系统时钟输出时的分频。
系统时钟与总线时钟
片上总线时钟由系统时钟一次或多次分频后得到。通过设置 RCC_CFGR[PPRE2] / RCC_CFGR[PPRE1] / RCC_CFGR[HPRE] 可以分别配置APB2,APB1 和 AHB1 总线时钟分频系数。总线时钟频率最高可达 72 MHz。
总线时钟与外设时钟
通过配置 RCC_AHBENR 寄存器、RCC_APB1ENR 寄存器以及 RCC_APB2ENR 寄存器的特定外设位,使能总线上外设时钟,从而可以允许总线对外设寄存器的读写操作。
对于大部分外设而言,外设时钟频率与外设所在总线频率相同。但有以下几个特例。
对于非 TIM1 的定时器而言,如果所在总线时钟分频系数不为 1,则定时器时钟频率为 2 倍频的总线时钟频率。TIM1 的时钟频率取决于 AHB 总线时钟和 APB2 总线时钟。如果 AHB 总线时钟和 APB2 总线时钟都不分频,则 TIM1 时钟频率和 APB2 时钟频率相同;如果 AHB 总线时钟和 APB2 总线时钟仅有一方分频,则 TIM1 时钟频率为 2 倍频的总线分频时钟频率。如果 AHB 总线时钟和 APB2 总线时钟都分频,则 TIM1 时钟频率为 4 倍频的 APB 总线时钟频率。
CPU 系统定时器频率 SysTick ,为 8 分频的 AHB 总线时钟频率。
样例1 pokt-f0140 开发板初始化 48MHz 系统时钟
在 SDK 中已有支持的 pokt-f0140 开发板上,在任一样例工程中的 clock_init.c 中,通过 CLOCK_BootToHSE48MHz() 实现 48MHz 系统时钟和总线时钟。其中,HSE的输出时钟频率为12MHz。
主要代码如下:
void CLOCK_BootToHSE48MHz(void)
{
/* enable HSE.使能HSE时钟。 */
RCC->CR |= RCC_CR_HSEON_MASK;
/* check HSE ready mask.时钟准备就绪。 */
while ( RCC_CR_HSERDY_MASK != (RCC->CR & RCC_CR_HSERDY_MASK) )
{
}
/* F_clko = F_refin * N/(M*P), F_refin = 12M. HSE输出频率为12MHz,倍频系数为8,分频系数为 1*2 = 2,PLL时钟频率为 12*8/2 = 48MHz。 */
RCC->PLLCFGR = RCC_PLLCFGR_PLLSRC(1) /* (pllsrc == 1) ? HSE : HSI. */
| RCC_PLLCFGR_PLLDN(7) /* N = DN+1. */
| RCC_PLLCFGR_PLLDM(1) /* M = DM+1. */
| RCC_PLLCFGR_PLLDP(0) /* P = DP+1. */
| RCC_PLLCFGR_PLLLDS(1)
| RCC_PLLCFGR_PLLICTRL(3) /* 10uA. */
;
/* Enable PLL. 使能PLL时钟并等待时钟准备就绪。*/
RCC->CR |= RCC_CR_PLLON_MASK;
while((RCC->CR & RCC_CR_PLLRDY_MASK) == 0)
{
}
/* Enable the FLASH prefetch. */
RCC->AHB1ENR |= RCC_AHB1ENR_FLITFEN_MASK; /* enable the access to FLASH. */
FLASH->ACR = FLASH_ACR_LATENCY(1u) /* setup divider: 1 for 48Mhz, 2 for 72MHz.. */
| FLASH_ACR_PRFTBE_MASK /* enable flash prefetch. */
;
/* Setup the dividers for each bus. 为各总线设置分频系数。 */
RCC->CFGR = RCC_CFGR_HPRE(0) /* div=1 for AHB freq. */
| RCC_CFGR_PPRE1(0x0) /* div=1 for APB1 freq. */
| RCC_CFGR_PPRE2(0x0) /* div=1 for APB2 freq. */
| RCC_CFGR_MCO(7) /* use PLL/2 as output. */
;
/* Switch the system clock source to PLL. 选择系统时钟源为PLL。*/
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW_MASK) | RCC_CFGR_SW(2); /* use PLL as SYSCLK */
/* Wait till PLL is used as system clock source.检查SWS标志,确认系统时钟源设置。 */
while ( (RCC->CFGR & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS(2) )
{
}
}
样例2 pokt-f0140 开发板使能 GPIOA 模块时钟
在 SDK 中已有支持的 pokt-f0140 开发板上,可以通过以下代码使能 GPIOA 模块时钟。
RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOA, true);
样例3 pokt-f0140 开发板复位 GPIOA 模块寄存器
在 SDK 中已有支持的 pokt-f0140 开发板上,可以通过以下代码复位 GPIOA 模块寄存器。
RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOA);