阻容复位
- 系统复位、上电复位和备份区域复位
时钟源
任一个时钟源都可被独立地启动或关闭,优化系统功耗。
-
主时钟源
三种不同的时钟源可被用来驱动系统时钟(SYSCLK)
HSI 振荡器时钟。
HSE振荡器时钟
PLL 时钟[主PLL和专用PLL) -
二级时钟源
LSI时钟:32KHz低速内部RC
LSE时钟:32.768khz低速外部晶体 -
时钟树
-
[1] LSI是低速内部时钟,RC振荡器,供独立看门狗和自动唤醒单元使用
-
[2] LSE是低速外部时钟,主要是RTC的时钟源
-
[3] HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~26MHz。HSE也可以直接做为系统时钟或者PLL输入
-
[4] HSI是高速内部时钟,RC振荡器,频率为16MHz。可以直接作为系统时钟或者用作PLL输入
-
[5] PLL为锁相环倍频输出。STM32F4有两个PLL:
1、主PLL(PLL)由HSE或者HSI提供时钟信号,并具有两个不同的输出时钟。第一个输出PLLP用于生成高速的系统时钟(最高168MHz)第二个输出PLLQ用于生成USB OTG FS的时钟(48MHz),随机数发生器的时钟和SDIO时钟。
2、专用PLL(PLLI2S)用于生成精确时钟,从而在I2S接口实现高品质音频性能 -
[A] 这里是看门狗时钟输入。看门狗时钟源只能是低速的LSI时钟。
-
[B] 这里是RTC时钟源,从图上可以看出,RTC的时钟源可以选择LSI,LSE,以及HSE分频后的时钟,HSE分频系数为2~31。
-
[C] 这里是STM32F4输出时钟MCO1和MCO2。MCO1是向芯片的PA8引脚输出时钟。它有四个时钟来源分别为:HSI,LSE,HSE和PLL时钟。MCO2是向芯片的PC9输出时钟,它同样有四个时钟来源分别为:HSE,PLL,SYSCLK以及PLLI2S时钟。MCO输出时钟频率最大不超过100MHz。
-
[D] 这里是系统时钟。SYSCLK系统时钟来源有三个方面:HSI,HSE和PLL。
HCLK = SYSCLK / 1 (AHB1Periph) = 168MHz
PCLK2 = HCLK / 2 (APB2Periph) = 84MHz
PCLK1 = HCLK / 4 (APB1Periph) = 42MHz
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM6, TIM12, TIM13,TIM14
APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11 -
[E] 这里我们指的是以太网PTP时钟,AHB时钟,APB2高速时钟,APB1低速时钟。这些时钟都是来源于SYSCLK系统时钟。其中以太网PTP时钟是使用系统时钟。AHB,APB2和APB1时钟是经过SYSCLK时钟分频得来。这里大家记住,AHB最大时钟为168MHz, APB2高速时钟最大频率为84MHz,而APB1低速时钟最大频率为42MHz。
-
[F] 这里是指I2S时钟源。I2S的时钟源来源于PLLI2S或者映射到I2S_CKIN引脚的外部时钟。I2S出于音质的考虑,对时钟精度要求很高。STM32F4开发板使用的是内部PLLI2SCLK。
-
[G] 这是STM32F4内部以太网MAC时钟的来源。对于MII接口来说,必须向外部PHY芯片提供25Mhz的时钟,这个时钟,可以由PHY芯片外接晶振,或者使用STM32F4 的MCO输出来提供。然后,PHY 芯片再给STM32F4提供ETH_MII_TX_CLK和ETH_MII_RX_CLK时钟。对于RMII接口来说,外部必须提供50Mhz的时钟驱动PHY和STM32F4的ETH_RMII_REF_CLK,这个50Mhz时钟可以来自PHY、有源晶振或者STM32F4的MCO。我们的开发板使用的是RMII 接口,使用PHY 芯片提供50Mhz时钟驱动STM32F4 的ETH_RMII_REF_CLK。
-
[H] 这里是指外部PHY提供的USB OTG HS(60MHZ)时钟。
时钟初始化配置
- 系统启动以后默认使用的是内部 16MHz 的 RC 振荡器,启动过程中 NRST 引脚产生复位信号,从而进入 STM32F4 的复位中断服务程序,在里面调用相关的函数,将时钟切换到 HSE,进入到 main 函数执行。
- SystemInit()功能:建立系统时钟(系统时钟源,PLL分频和倍频因子,AHB/APBx 分频,FLASH 设置)
void SystemInit(void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
#endif
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset CFGR register */
RCC->CFGR = 0x00000000;
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset PLLCFGR register */
RCC->PLLCFGR = 0x24003010;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Disable all interrupts */
RCC->CIR = 0x00000000;
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
/* Configure the System clock source, PLL Multiplier and Divider factors,
AHB/APBx prescalers and Flash settings ----------------------------------*/
SetSysClock();
/* Configure the Vector Table location add offset address ------------------*/
#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函数开始先进行浮点运算单元设置,然后是复位PLLCFGR,CFGR寄存器,同时通过设置CR寄存器的HSI时钟使能位来打开HSI时钟。此代码就是RCC->CR |=(uint32_t)0x00000001,打开HSI振荡器,在设置完相关寄存器后,接下来SystemInit函数内部会调用SetSysClock函数。
static void SetSysClock(void)
{
/******************************************************************************/
/* PLL (clocked by HSE) used as System clock source */
/******************************************************************************/
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* Enable HSE 在第16bit置1将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)
{
/* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
/* HCLK = SYSCLK / 1*不分频/
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK / 2*2分频/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
/* PCLK1 = HCLK / 4*4分频/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
/* Configure the main PLL */
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
/* Enable the main PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till the main PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
/* Select the main PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
/* Wait till the main PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
{
}
}
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 */
}
/******************************************************************************/
/* I2S clock configuration */
/******************************************************************************/
/* PLLI2S clock used as I2S clock source */
RCC->CFGR &= ~RCC_CFGR_I2SSRC;
/* Configure PLLI2S */
RCC->PLLI2SCFGR = (PLLI2S_N << 6) | (PLLI2S_R << 28);
/* Enable PLLI2S */
RCC->CR |= ((uint32_t)RCC_CR_PLLI2SON);
/* Wait till PLLI2S is ready */
while((RCC->CR & RCC_CR_PLLI2SRDY) == 0)
{
}
}
- HSE 就绪就绪后配置流程如下:
HCLK = SYSCLK / 1。
PCLK2 = HCLK / 2。
PCLK1 = HCLK / 4。
配置主 PLL,并等待其就绪。
配置 Flash prefetch, Instruction cache, Data cache 和 wait state。
选择 mian PLL 作为系统时钟源
到这里基本完成了HSE 作为系统时钟的初始化工作,剩下就可以进入 main 函数进行操作了。到这里时钟系统就告一段落。