RCC(复位与时钟控制)
主要作用有两个,复位与时钟
复位
1、系统复位
系统复位将所有寄存器设置为其复位值,通过以下事件触发
- 外部复位,即NRST引脚低电平
- 窗口看门狗计数结束条件,即窗口看门狗复位
- 独立看门狗计数结束条件,即独立看门狗复位
- 软件复位,判断RCC_CSR寄存器上的复位标志位
- 低功耗管理复位,进入待机模式或停机模式
2、电源复位
电源复位将所有寄存器设置为其复位值除了备份域,通过以下事件触发
- POR/PDR 复位信号或BOR复位信号
- 退出待机模式
3、备份域复位
备份域复位将所有的RTC寄存器、RCC-BDCR寄存器、PWR_CSR寄存器BRE位设为其复位值,必须设置PWR_CR寄存器中的BDP位才能产生备份域复位。重置BKPSRAM的唯一方法是通过Flash接口请求将保护级别从1改为0。通过以下事件产生复位
- 软件复位,通过RCC_BDCR寄存器中的BDRST位触发
- V D D V_{DD} VDD或 V B A T V_{BAT} VBAT都断电
时钟
STM32系统时钟(SYSCLK)有三种时钟源
- 高速内部时钟HSI
- 高速外部时钟HSE
- 主PLL时钟
有两种辅助时钟源
- 低速内部时钟LSI(32KHz)
- 低速外部时钟LSE(32.768KHz)
多个预分频器可用于配置多种时钟频率,AHB总线最大时钟频率为168MHz,APB2总线最大时钟频率为84MHz,APB1总线最大时钟频率为42MHz。定时器外设都在APB总线,定时器时钟频率有两种情况
- 如果APB总线预分频系数为1,则定时器时钟频率与该总线时钟频率相等
- 如果APB总线预分频系数不为1,则定时器时钟频率是该总线时钟频率两倍
1、HSE
高速外部时钟,可以由有源晶振或无源晶振提供,频率从4-26MHZ不等。当使用有源晶振时,时钟从OSC_IN引脚进入, OSC_OUT引脚悬空,当选用无源晶振时,时钟从OSC_IN和OSC_OUT进入,并且要配谐振电容,尽可能靠经晶振引脚以减少输出失真和稳定启动事件。当HSE故障时,PLL也会关闭,系统时钟由HSI提供。
2、HSI
高速内部时钟,由内部16MHz的RC振荡器产生。虽然无需外围电路且启动时间比HSE短,但是时钟频率不如HSE准确,制造工艺不同时钟频率也会不同,同时环境温度对齐也会有影响。系统复位后,HSI默认为系统时钟。
3、锁相环PLL
PLL的主要作用是对时钟进行倍频,然后把时钟输出到各个功能部件。STM32F4xx有两个PLL
- 主PLL
主PLL对HSE或HSI的时钟频率进行倍频,具有两种不同的时钟输出- 高速系统时钟,PLLCLK = HCLK = SYSCLK = 168MHz
- USB OTG FS(48MHz)、随机模拟数生成器( ≤ 48 M H z \le 48MHz ≤48MHz)和SDIO( ≤ 48 M H z \le 48MHz ≤48MHz)
- 专用PLL
为I2S接口实现高质量音频性能表现提供准确时钟频率
PLL只能在启动系统之前进行配置,即对M、N、P和Q进行配置。
4、LSE
LSE时钟由32.768KHz的晶振产生,主要用于RTC。
5、LSI
内部低速时钟,由内部32KHzRC振荡器产生。
6、时钟相关计算
HSE或HSI经过PLL时钟输入分频因子M(
2
≤
P
L
L
M
≤
63
2 \le PLLM \le 63
2≤PLLM≤63)分频,进入压控振荡器(VCO),VCO输入频率范围应在
1
−
2
M
H
z
1-2MHz
1−2MHz内,VCO输入频率公式:
V
C
O
i
n
F
=
H
S
E
或
H
S
I
P
L
L
M
VCO_{inF} = \frac {HSE或HSI}{PLLM}
VCOinF=PLLMHSE或HSI,这里板载HSE为8MHz,PLLM设置为8,则计算公式为:
V
C
O
i
n
F
=
8
M
H
z
8
=
1
M
H
z
VCO_{inF} = \frac {8MHz}{8} = 1MHz
VCOinF=88MHz=1MHz。
VCO输入频率
V
C
O
i
n
F
VCO_{inF}
VCOinF经过VCO倍频因子N(
50
≤
P
L
L
N
≤
432
50 \le PLLN \le 432
50≤PLLN≤432)倍频之后,成为VCO时钟输出,输出范围在
100
M
H
z
≤
V
C
O
o
u
t
F
≤
432
M
H
z
100MHz \le VCO_{outF} \le 432MHz
100MHz≤VCOoutF≤432MHz内,VCO输出频率公式:
V
C
O
o
u
t
F
=
V
C
O
i
n
F
×
P
L
L
N
VCO_{outF} = VCO_{inF} \times PLLN
VCOoutF=VCOinF×PLLN,这里设置PLLN为336,则计算公式为:
V
C
O
o
u
t
F
=
V
C
O
i
n
F
×
P
L
L
N
=
336
M
H
z
VCO_{outF} = VCO_{inF} \times PLLN = 336MHz
VCOoutF=VCOinF×PLLN=336MHz。
VCO输出频率
V
C
O
o
u
t
F
VCO_{outF}
VCOoutF经过锁相环倍频因子P(
P
L
L
P
=
2
,
4
,
6
o
r
8
PLLP = 2, 4, 6 or 8
PLLP=2,4,6or8)倍频之后,产生不超过168MHz的锁相环输出频率
P
L
L
C
L
K
PLLCLK
PLLCLK,这里设置PLLP为2,则计算公式为:
P
L
L
C
L
K
f
=
V
C
O
o
u
t
F
P
L
L
P
=
336
M
H
z
2
=
168
M
H
z
PLLCLK_f = \frac {VCO_{outF}}{PLLP} = \frac {336MHz}{2} = 168MHz
PLLCLKf=PLLPVCOoutF=2336MHz=168MHz。
USB OTG FS/RNG/SDIO时钟分频因子Q(
2
≤
P
L
L
Q
≤
15
2 \le PLLQ \le 15
2≤PLLQ≤15),USB OTG FS要求48MHz时钟,这里设置PLLQ为7即可。
分频因子R(F446才有,F407没有)。
7、总线时钟频率
- 高速APB总线(APB2),通过RCC_CFGR寄存器中的PPRE2[15:13]位进行配置预分频系数,不超过频率84MHz,这里设置2分频,即AHB总线频率168MHz的一半,PCLK2=HCLK/2=84MHz
- 低速APB总线(APB1),通过RCC_CFGR寄存器中的PPRE1[12:10]位进行配置预分频系数,不超过频率42MHz,这里设置4分频,即AHB总线频率168MHz的四分之一,PCLK1=HCLK/4=42MHz
- AHB总线,RCC_CFGR寄存器中的HPRE[7:4]位进行配置预分频系数,最低频率为25MHz,这里设置为1分频,即HCLK=SYSCLK=168MHz
设置系统时钟
在system_stm32f4xx.c
文件中给出了系统时钟函数,SystemInit(void)
/**
* @brief Setup the microcontroller system
* Initialize the Embedded Flash Interface, the PLL and update the
* SystemFrequency variable.
* @param None
* @retval None
*/
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;//开启HSI
/* Reset CFGR register */
RCC->CFGR = 0x00000000;//RCC时钟配置寄存器复位
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;//关闭PLL,CSS,关闭HSE
/* Reset PLLCFGR register */
RCC->PLLCFGR = 0x24003010;//复位PLL
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;//复位HSE时钟旁路
/* Disable all interrupts */
RCC->CIR = 0x00000000;//失能所有中断
#if defined(DATA_IN_ExtSRAM) || defined(DATA_IN_ExtSDRAM)
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
/* 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
}
SetSysClock(void)函数用于设置系统时钟,启动文件startup_stm32f40xxx.s
会将SYSCLK将系统时钟初始化为168MHz,代码如下
/**
* @brief Configures the System clock source, PLL Multiplier and Divider factors,
* AHB/APBx prescalers and Flash settings
* @Note This function should be called only once the RCC clock configuration
* is reset to the default reset state (done in SystemInit() function).
* @param None
* @retval None
*/
static void SetSysClock(void)
{
#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F412xG) || defined(STM32F446xx)|| defined(STM32F469_479xx)
/******************************************************************************/
/* PLL (clocked by HSE) used as System clock source */
/******************************************************************************/
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* Enable 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 */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
/* HCLK = SYSCLK / 1*/
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F412xG) || defined(STM32F446xx) || defined(STM32F469_479xx)
/* PCLK2 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
/* PCLK1 = HCLK / 4*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
#endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx || STM32F412xG || STM32F446xx || STM32F469_479xx */
#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F469_479xx)
/* Configure the main PLL */
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
#endif /* STM32F40_41xxx || STM32F401xx || STM32F427_437x || STM32F429_439xx || STM32F469_479xx */
/* Enable the main PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till the main PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
#if defined(STM32F40_41xxx) || defined(STM32F412xG)
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif /* STM32F40_41xxx || STM32F412xG */
/* 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 */
}
#elif defined(STM32F410xx) || defined(STM32F411xE)
#endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F469_479xx */
}