三、STM32F10x 时钟控制
1、控制概述
STM32F10x 芯片的时钟控制主要包括以下几个方面知识;系统时钟源的选择、系统时钟频率的配置、总线时钟的配置、总线设备时钟的使能/除能;
(1)系统时钟源的选择:系统时钟源为 SYSCLK,由 SW(系统时钟切换)选择时钟源来作为系统时钟 SYSCLK,可供选择的输入时钟有 HSE、HSI、PLLCLK(PLL 输出);
(2)系统时钟频率的配置:选择 SW(系统时钟切换)的 3 个输入时钟源的其中一个的时钟频率作为系统频率;HSI 则是 HSI RC 的频率,通常为 8MHz;PLLCLK 作为系统时钟频率时,需要根据 PLLXTPRE 和 PLLSRC 两个选择器的输出经 PLL 倍频后作为系统时钟频率,通常为 8MHz;HSE 直接作为系统时钟频率使用相对较少;
和 SW 三个选择器和 PLL 倍频器来控制,输入时钟源经 PLL 倍频后输出作为 SW(系统时钟切换)的其中一项输入,再经过 SW 选择后作为 SYSCLK(系统时钟);
(3)总线时钟的配置:AHB 总线,输入时钟源 SYSCLK 经 AHB 预分频器分频后输出,输出为 HCLK,高性能总线供给时钟;APB1 低速外设总线,输入时钟源 HCLK 经 APB1 分频器预分频后输出,输出为 PCLK1,低速外设总线时钟;APB2 高速外设总线,输入时钟源 HCLK 经 APB2 分频器预分频后输出,输出为 PCLK2,高速外设总线时钟;
(4)总线设备时钟的使能/除能:主要是外设总线 APB1 和 APB2 的使能/不使能,时钟初始化默认是不使能,如果要使用外设,则需要打开外设对应的时钟;
即在使用STM32F10x之前需要先进行时钟系统的相关配置,也就是时钟初始化,在工程文件中会在启动时进行一个默认的初始化SystemInit(),使用者在初始化完成后在进行所需的个性配置;默认配置是在启动时系统操作寄存器来进行配置,寄存器配置想对麻烦,所以在使用者进行个性化设置时,是使用库函数直接配置。
2、时钟初始化
初始化时钟系统时,在工程文件 system_stm32f10x.c 中通过 SystemInit()和 SetSysClock()两个函数进行初始化,使用的是寄存器操作的方法来初始化时钟系统;因为是直接操作寄存器,所以初始化过程非常复杂,以下是这两个函数的解析,仅供学习、参考用(以 STM32F103C8T6 为例);可跳过,直接看如何通过库函数配置即可。
SystemInit(),启动芯片,将系统频率设置为8MHz,关闭所有外设;具体操作为:启动内部时钟源 HSI RC(8MHz)作为系统时钟、配置总线时钟预分频器和外设总线时钟预分频器、配置 ADC 预分频器和定时器预分频器/倍频器、微控制器时钟不输出、关闭 HSE Osc、关闭 CSS 时钟监视系统、PLL 不使能、配置 PLLXTPRE、PLLSRC、PLL 输出、USB 预分频、关闭时钟中断使能(LSI、LSE、HSE、HSI、PL 就绪中断使能)、清除中断标志位(LSI、LSE、HSE、HSI、PLL就绪)、清除安全系统时钟中断;
void SystemInit (void)
{
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
/*Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
// 将时钟控制寄存器RCC_CR[0]位置1
// 内部8MHz振荡器启动
//
//
// RCC-CR[0]
// HSION内部高速时钟使能 (Internal high-speed clock enable)
// 0:内部8MHz振荡器关闭; 1:内部8MHz振荡器开启。
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */
// 判断所使用stm32f10x类型:(点击魔术棒选择C/C++选项,观察Define即可查看产品类型)
// cl:互联型产品,stm32f105/107系列
// vl:超值型产品,stm32f100系列
// xl:超高密度产品,stm32f101/103系列
// ld:低密度产品,FLASH小于64K
// md:中等密度产品,FLASH=64 or 128
// hd:高密度产品,FLASH大于128
// 这里使用的是md中等密度产品,所以执行if not define 中的代码
// 将RCC-CFGR寄存器中的[0:1]、[4:7]位和[24:26]位置0
// 将HSI作为系统时钟,AHB预分频系数配置为SYSCLK不分频,低速APB预分频系数配置为HCLK不分频,高速APB预分频系数配置为HCLK不分频,ADC预分频系数配置为PCLK2 2分频后作为ADC系统时钟,微控制器时钟输出配置为没有时钟输出,因为RCC-CFGR[3:2]为系统时钟切换状态,是只读位,由硬件置1或置0;
//
//
// RCC-CFGR[1,0]:SW,系统时钟切换 (System clock switch)
// 00:HSI作为系统时钟; 01:HSE作为系统时钟;
// 10:PLL输出作为系统时钟; 11:不可用。
//
// RCC-CFGR[7,4]
// HPRE,AHB预分频 (AHB Presscaler)
// 0xxx:SYSCLK 不分频 1000:SYSCLK 2分频 1001:SYSCLK 4分频 1010:SYSCLK 8分频
// 1011:SYSCLK 16分频 1100:SYSCLK 64分频 1101:SYSCLK 128分频 1111:SYSCLK 512分频 1110:SYSCLK 256分频
//
//
// RCC-CFGR[10,8]
// PPRE1,低速APB预分频 (APB1)(APB low-speed prescaler (APB1))
// 0xx:HCLK不分频 100:HCLK 2分频 101:HCLK 4分频 110:HCLK 8分频 111:HCLK 16分频
//
// RCC-CFGR[13,11]
// PPRE2,高速APB预分频 (APB2) (APB high-speed prescaler (APB2))
// 0xx:HCLK不分频 100:HCLK 2分频 101:HCLK 4分频 110:HCLK 8分频 111:HCLK 16分频
//
// RCC-CFGR[15,14]
// ADCPRE,ADC预分频 (ADC prescaler)
// 00:PCLK2 2分频后作为ADC时钟 01:PCLK2 4分频后作为ADC时钟 10:PCLK2 6分频后作为ADC时钟 11:PCLK2 8分频后作为ADC时钟
//
// RCC-CFGR[26,24]
// MCO,微控制器时钟输出,置0为不输出时钟输出;PA8引脚具有复用功能——时钟输出(MCO)
// 0xx:没有时钟输出; 100:系统时钟(SYSCLK)输出; 101:内部RC振荡器时钟(HSI)输出; 110:外部振荡器时钟(HSE)输出; 111:PLL时钟2分频后输出
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
// 将时钟控制寄存器RCC-CR[16]、[19]、[24]置0
// 外部高速时钟使能配置为HSE振荡器关闭,时钟安全系统使能配置为时钟检测器关闭,PLL使能配置为PLL关闭
//
//
// RCC-CR[16]:
// HSEON,外部高速时钟使能 (External high-speed clock enable)
// 0:HSE振荡器关闭; 1:HSE振荡器开启
//
// RCC-CR[19]:
// CSSON,时钟安全系统使能 (Clock security system enable)
// 0:时钟监测器关闭; 1:如果外部4-16MHz振荡器就绪,时钟监测器开启
//
// RCC-CR[24]:
// PLLON,PLL使能 (PLL enable)
// 0:PLL关闭; 1:PLL使能
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
// 将时钟控制寄存器RCC-CR[18]置0
// 将外部高速时钟旁路配置为外部4-16MHz振荡器不被旁路
// RCC->CR[18]:
// HSEBYP,外部高速时钟旁路 (External high-speed clock bypass)
// 0:外部4-16MHz振荡器没有旁路; 1:外部4-16MHz外部晶体振荡器被旁路
//????????
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;
// 将时钟配置寄存器RCC-CFGR[22,16]置0
// 将PLL输入时钟源配置为HSI振荡器时钟经2分频后作为PLL输入时钟,PLL倍频系数配置为PLL 2倍频输出,USB预分频配置为PLL时钟1.5倍分频作为USB时钟;
// RCC->CFGR[16]:
// PLLSRC,PLL输入时钟源 (PLL entry clock source)
// 0:HSI振荡器时钟经2分频后作为PLL输入时钟 1:HSE时钟作为PLL输入时钟。
// RCC->CFGR[17]:
// PLLXTPRE,HSE分频器作为PLL输入 (HSE divider for PLL entry),0:HSE不分频;
// 0:HSE不分频 1:HSE 2分频
// RCC->CFGR[21,18]:
// PLLMUL,PLL倍频系数 (PLL multiplication factor),0000:PLL 2倍频输出;
// 0000:PLL 2倍频输出 1000:PLL 10倍频输出 0001:PLL 3倍频输出 1001:PLL 11倍频输出
// 0010:PLL 4倍频输出 1010:PLL 12倍频输出 0011:PLL 5倍频输出 1011:PLL 13倍频输出
// 0100:PLL 6倍频输出 1100:PLL 14倍频输出 0101:PLL 7倍频输出 1101:PLL 15倍频输出
// 0110:PLL 8倍频输出 1110:PLL 16倍频输出 0111:PLL 9倍频输出 1111:PLL 16倍频输出
// RCC->CFGR[22]:
// USBPRE,USB预分频 (USB prescaler),0:PLL时钟1.5倍分频作为USB时钟
// 0:PLL时钟1.5倍分频作为USB时钟 1:PLL时钟直接作为USB时钟
//ifdef同上,只执行else中的一句
#ifdef STM32F10X_CL
/* Reset PLL2ON and PLL3ON bits */
RCC->CR &= (uint32_t)0xEBFFFFFF;
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x00FF0000;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000;
#else
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
// 时钟中断寄存器RCC-CIR[23]和[20,16]位置1,[12:8]位置0
// 配置LSI就绪中断使能、LSE就绪中断使能、HSE就绪中断使能、HSI就绪中断使能、PLL就绪中断使能为中断关闭
// 清除LSI就绪中断标志位、LSE就绪中断标志位、HSE就绪中断标志位、HSI就绪中断标志位、PLL就绪中断标志位,清除时钟安全系统中断;
// 总结来说就是关闭所有时钟中断,清除所有时钟中断标志位
//
// RCC-CIR[8]:
// LSIRDYIE,LSI就绪中断使能(LSI ready interrupt enable)
// 0:LSI就绪中断关闭; 1:LSI就绪中断使能
//
// RCC-CIR[9]:
// LSERDYIE,LSE就绪中断使能 (LSE ready interrupt enable)
// 0:LSE就绪中断关闭; 1:LSE就绪中断使能
//
// RCC-CIR[10]:
// HSIRDYIE,HSI就绪中断使能 (HSI ready interrupt enable)
// 0:HSI就绪中断关闭; 1:HSI就绪中断使能
//
// RCC-CIR[11]:
// HSERDYIE,HSE就绪中断使能 (HSE ready interrupt enable)
// 0:HSE就绪中断关闭; 1:HSE就绪中断使能
//
// RCC-CIR[12]:
// PLLRDYIE,PLL就绪中断使能 (PLL ready interrupt enable)
// 0:PLL就绪中断关闭; 1:PLL就绪中断使能
//
// RCC-CIR[16]:
// LSIRDYC,清除LSI就绪中断 (LSI ready interrupt clear)
// 0:无作用; 1:清除LSI就绪中断标志位LSIRDYF
//
// RCC-CIR[17]:
// LSERDYC,清除LSE就绪中断 (LSE ready interrupt clear)
// 0:无作用; 1:清除LSE就绪中断标志位LSERDY F
//
// RCC-CIR[18]:
// HSIRDYC,清除HSI就绪中断 (HSI ready interrupt clear)
// 0:无作用; 1:清除HSI就绪中断标志位HSIRDYF
//
// RCC-CIR[19]:
// HSERDYC,清除HSE就绪中断 (HSE ready interrupt clear)
// 0:无作用; 1:清除HSE就绪中断标志位HSERDYF
//
// RCC-CIR[20]:
// PLLRDYC,清除PLL就绪中断 (PLL ready interrupt clear)
// 0:无作用; 1:清除PLL就绪中断标志位PLLRDYF
//
// RCC-CIR[23]:
// CSSC,清除时钟安全系统中断 (Clock security system interrupt clear)
// 0:无作用; 1:清除CSSF安全系统中断标志位
// 同上,不执行
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
#endif
/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
/* Configure the Flash Latency cycles and enable prefetch buffer */
SetSysClock();
#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
}
|