一、时钟树图表
RCC相关寄存器
//RCC 寄存器结构,RCC_TypeDeff,在文件“stm32f10x.h”中定义如下
1059行->1081行。:
typedef struct
{
vu32 CR; //HSI,HSE,CSS,PLL等的使能
vu32 CFGR; //PLL等的时钟源选择以及分频系数设定
vu32 CIR; // 清除/使能 时钟就绪中断
vu32 APB2RSTR; //APB2线上外设复位寄存器
vu32 APB1RSTR; //APB1线上外设复位寄存器
vu32 AHBENR; //DMA,SDIO等时钟使能
vu32 APB2ENR; //APB2线上外设时钟使能
vu32 APB1ENR; //APB1线上外设时钟使能
vu32 BDCR; //备份域控制寄存器
vu32 CSR;
} RCC_TypeDef;
二、时钟详解(结合时钟树)
HSE时钟(72M)
HSE:High Speed-External Clock signal,即高速的外部时钟
来源:无源晶振(4-16M),通常使用8M
控制:RCC CR时钟控制寄存器的位16:HSEON控制
HSI时钟
HSI:Low Speed Internal Clock signal,高速的内部时钟
来源:芯片内部,大小为8M,当HSE故障时,系统时钟会自动切换到HSI,直到HSE启动成功。
控制:RCC_CR时钟控制寄存器的位0:HSION控制
锁相环时钟
锁相环时钟:PLLCLK(官方72M,实际64M)
来源:(HSI2、HSE)经过倍频所得。(常用HSE)
控制:CFGR:PLLXTPRE、 PLLMUL
注意:PLL时钟源头使用HIS/2的时候, PLLMUL最大只能是16,这个时候 PLLCLK最大只能是64M,小于ST官方推荐的最大时钟72M。
系统时钟
锁相环时钟:SYSCLK,最高为72M(ST官方推荐的)
来源:HSI、HSE、 PLLCLK。
控制:CFGR:SW
注意:通常的配置是 SYSCLK= PLLCLK=72M
HCLK时钟
HCLK:AHB高速总线时钟,速度最高为72M。为AHB总线的外设提供时钟、为 Cortex系统定时器提供时钟
( SysTick)、为内核提供时钟(FCLK)
AHB:advanced high- performance bus。
来源:系统时钟分频得到,一般设置HCLK= SYSCLK=72M
控制:CFGR:HPRE
PCLK时钟
PCLK1:APB1低速总线时钟,最高为36M。为APB1总线的外设提供时钟。2倍频之后则为APB1总线的定时器2-7提供时钟,最大为72M。
来源:HCLK分频得到,一般配置PCLK1=HCLK/2=36M
控制:RCC CFGR时钟配置寄存器的PPRE1位
PCLK2时钟
PCLK2:APB2高速总线时钟,最高为72M。为APB1总线的外设提供时钟。为APB1总线的定时器1和8提供时钟,最大为72M。
来源:HCLK分频得到,一般配置PCLK1=HCLK=72M
控制:RCC CFGR时钟配置寄存器的PPRE2位
RTC时钟
RTC时钟:为芯片内部的RTC外设提供时钟。
来源:HSE RTG(HSE分频得到)、LSE(外部32.768KHz的晶体提供)、LSI(32KHZ)。
控制:RCC备份域控制寄存器 RCC BDCR:RTCSEL位控制
独立看门狗时钟:TWDGCLK,由LS提供
Mco时钟输出
Mco:microcontroller clock output,微控制器时钟输出引脚,由PA8复用所得。
来源:PLLCLK/2,HSE、HSI、 SYSCLK
控制:CRGR:MCO
(自己写时钟配置函数,检测对错,利用Mco输出引脚,通过示波器看波形)
时钟安全系统(CSS)
时钟安全系统可以通过软件被激活。一旦其被激活,时钟监测器将在HSE振荡器启动延迟后被使能,并在HSE时钟关闭后关闭。
如果HSF时鈾发生故障,HSE振荡器被自动关闭,时钟失效事件将被送到高级定时器(TIM1和TIM8)的刹车输入端,并产生时钟安全中断CSS,
允许软件完成营救操作。此CS中断连接到CortexTM-M3的NMI中断(不可屏蔽中断)
注意:一日CSS被激活,并且HSE时钟出现故障,CSS中断就产生,并NMI也自动产生。MM将被不断执行,直到CSS中断挂起位被清除。
因此,在NM的处理程序中必须通过设置时钟中断寄存器( RCC CIR)里的CSSC位来清除CSS中断。
如果HSE振荡器被直接或间接地作为系统时钟,(间接的意思是:它被作为PLL输入时钟,并且PLL时钟被作为系统时钟),时钟故障将导致系统时钟自动切换到HSI振荡器,同时外部HSE振荡器被关闭。
在时钟失效时,如果HSE振荡器时钟(被分频或未被分频)是用作系统时钟的PLL的输
(如果HES出故障,且没有使能CSS,系统时钟切换到HSI(8M低速运行))
HSE=高速外部时钟信号
HSI=高速内部时即信号
LSI=低速内部时钟信号
LSE=低速外部时钟信号
三、 时钟配置思路:
系统时钟—>AHB分频器—>各个外设分频倍频器 —> 外设时钟的设置
1、使用为外部的高速时钟信号【HSE(8M不分频)】来配置时钟
2、然后进入锁相环时钟时钟源(PLLCLK)–配9倍频—>8*9=72M
3、结果出来的锁相环时钟(PLLCLK)–为72M
4、配置系统时钟(三个选择HSE/PLLCLK/HSI)我们选择锁相环时钟(PLLCLK)为系统时钟(SYSCLK)
5、如果APB1–选择2分频=36M,或APB2–选择1分频
(以上总线配置好了)
6、剩下其它外设使用时配置
RCC初始化思路:
这里使用HSE(外部时钟),正常使用的时候也都是使用外部时钟
程序设置时钟参数流程:
1、将RCC寄存器重新设置为默认值 RCC_DeInit;
2、打开外部高速时钟晶振HSE RCC_HSEConfig(RCC_HSE_ON);
3、等待外部高速时钟晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp();
4、设置AHB时钟 RCC_HCLKConfig;
5、设置高速AHB时钟 RCC_PCLK2Config;
6、设置低速速AHB时钟 RCC_PCLK1Config;
7、设置PLL RCC_PLLConfig;
8、打开PLL RCC_PLLCmd(ENABLE);
9、等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
10、设置系统时钟 RCC_SYSCLKConfig;
11、判断是否PLL是系统时钟 while(RCC_GetSYSCLKSource() != 0x08)
12、打开要使用的外设时钟 RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()
代码实现:
对RCC的配置函数(使用外部8MHz晶振)
系统时钟72MHz,APH 72MHz,APB2 72MHz,APB1 32MHz,USB 48MHz TIMCLK=72M
void RCC_Configuration(void)
{
//----------使用外部RC晶振-----------
RCC_DeInit(); //初始化为缺省值
RCC_HSEConfig(RCC_HSE_ON); //使能外部的高速时钟
while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); //等待外部高速时钟使能就绪
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch Buffer
FLASH_SetLatency(FLASH_Latency_2); //Flash 2 wait state
RCC_HCLKConfig(RCC_SYSCLK_Div1); //HCLK = SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1); //PCLK2 = HCLK
RCC_PCLK1Config(RCC_HCLK_Div2); //PCLK1 = HCLK/2
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9); //PLLCLK = 8MHZ * 9 =72MHZ
RCC_PLLCmd(ENABLE); //Enable PLLCLK
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLLCLK is ready
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //Select PLL as system clock
while(RCC_GetSYSCLKSource()!=0x08); //Wait till PLL is used as system clock source
//---------打开相应外设时钟--------------------
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能APB2外设的GPIOA的时钟
}
四、固件库——系统时钟配置函数
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
// ① 使能 HSE,并等待 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;
}
// HSE 启动成功,则继续往下处理
if (HSEStatus == (uint32_t)0x01) {
//-----------------------------------------------------------
// 使能 FLASH 预存取缓冲区 */
FLASH->ACR |= FLASH_ACR_PRFTBE;
// SYSCLK 周期与闪存访问时间的比例设置,这里统一设置成 2
// 设置成 2 的时候,SYSCLK 低于 48M 也可以工作,如果设置成 0 或者1 的时候,
// 如果配置的 SYSCLK 超出了范围的话,则会进入硬件错误,程序就死了
// 0:0 < SYSCLK <= 24M
// 1:24< SYSCLK <= 48M
// 2:48< SYSCLK <= 72M */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
// ② 设置 AHB、APB2、APB1 预分频因子
// HCLK = SYSCLK
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
//PCLK2 = HCLK
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
//PCLK1 = HCLK/2
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
//③ 设置 PLL 时钟来源,设置 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);
// ④ 使能 PLL
RCC->CR |= RCC_CR_PLLON;
// ⑤ 等待 PLL 稳定
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
}
// ⑥ 选择 PLL 作为系统时钟来源
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
// ⑦ 读取时钟切换状态位,确保 PLLCLK 被选为系统时钟
while ((RCC->CFGR&(uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){
}
} else {// 如果 HSE 启动失败,用户可以在这里添加错误代码出来
}
}