STM32时钟系统示意图
时钟源主要有
- HSI 内部高速RC振荡时钟,约为8M
- HSE 外接晶振,例如8M石英晶振
- PLL 锁相环,可以倍频(2到16倍)
- LSE 外部低速晶振,如32.768KHz
- LSI 内部低速RC振荡时钟,约为40KHz
其他相关部分
- CSS 时钟检测系统,当外部时钟不正常工作时,自动切换为内部时钟
- MCO 内部时钟输出接口
- AHB 分频器
- APB1\APB2 分频器
RCC寄存器相关部分
主要寄存器
对应寄存器每个位置的控制信息可以看芯片手册查询。
- CR 控制寄存器
- OFCR 配置寄存器
- CIR 中断寄存器
- AHBENR 使能寄存器
- APB1ENR (低速外设)
- APB2ENR (高速外设)
- APB1RSTR 复位寄存器
- APB2RSTR
- BDCR 备份域寄存器
- CSR 控制、状态寄存器
分析SystemInit函数
void SystemInit (void)//来源标准库便于理解有删减,详细请去标准库查看
{
/* 修改CR打开HSI*/
RCC->CR |= (uint32_t)0x00000001;
/* 设置 SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
RCC->CFGR &= (uint32_t)0xF0FF0000;
/* 设置 HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* 设置 HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* 设置 PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;
/*中断关闭*/
RCC->CIR = 0x009F0000;
/* 系统时钟配置 */
SetSysClock();
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
}
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
/* 通过定义频率的相关变量来决定调用哪个函数 */
}
假设我们定义了SYSCLK_FREQ_72MHz,下面看看SetSysClockTo72()函数:
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* 使能 HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* 等待HSE稳定 */
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 */
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;
/* PLL锁相环输出配置: 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 */
/* 使能PLL */
RCC->CR |= RCC_CR_PLLON;
/* 等待 PLL 稳定 */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* 把PLLCLK设置为系统时钟 */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* 等待稳定 */
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 */
}
}