概述
本文主要描述了STM32F103初始化过程系统时钟的初始化,主要描述了系统时钟的初始化,AHB总线时钟,APB总线时钟等的初始化。
硬件板卡3d图
时钟树
STM32F103的时钟树,如下所示:
时钟源选择
从STM32F103的时钟树框图,我们可以看到:
1、有可选的1路高速外部时钟接口,作为系统时钟的时钟源;
2、1路32.768的可选低速时钟,作为系统RTC和watchdog的时钟源;
3、1路内部的可选8M 高速时钟,作为系统时钟的时钟源;
系统时钟选择
根据时钟树所示,可选的系统的时钟选择,如下所示:
1、内部8M的HSI直接作为系统的时钟源,如果使用HSI作为系统时钟源的话,最大SYSCLK只能输出到64MHz;
2、HSI或者HSE的通过PLL的倍频后,作为系统时钟源;
3、HSE的输出,直接作为系统的时钟源;
通过系统时钟源的来源描述,系统的时钟源可以根据硬件板卡的制作情况,进行选择;作者自己设计的PCB板子上,因为没有连接外部晶振,因此将HSI作为系统的时钟源选择。后续的时钟初始化代码分析,会讲解怎么将HSI设置为系统的时钟源;
其他外设时钟
根据STM32F103的时钟树,其他外设控制器的时钟的来源如下所示:
1、USB控制器的时钟,直接来源于PLLCLK,然后经过USB预分频,最终达到48M的时钟输出,作为USB控制器的时钟;
2、I2S音频控制器的时钟,直接来源于SYSCLK, 和SYSCLK的时钟相同;
3、SDIO, FSMC, HCLK 等时钟,直接来自于AHB总线的时钟输出;
4、剩余外设的时钟自于APB1或者APB2,这里不再这里详细描述;
时钟初始化设置
由于作者自己设计的硬件板子,使用了内部的8M作为整个CPU的时钟源,因此,下面以使用内部8M的高速时钟的情况,进行源码讲解,设置源码如下所示:
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef clkinitstruct = {0};
RCC_OscInitTypeDef oscinitstruct = {0};
/* Configure PLL ------------------------------------------------------*/
/* PLL configuration: PLLCLK = (HSI / 2) * PLLMUL = (8 / 2) * 16 = 64 MHz */
/* PREDIV1 configuration: PREDIV1CLK = PLLCLK / HSEPredivValue = 64 / 1 = 64 MHz */
/* Enable HSI and activate PLL with HSi_DIV2 as source */
oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; /* HSI作为系统时钟源 */
oscinitstruct.HSEState = RCC_HSE_OFF; /* 关闭HSE时钟 */
oscinitstruct.LSEState = RCC_LSE_OFF; /* 关闭LSE时钟 */
oscinitstruct.HSIState = RCC_HSI_ON; /* 开启HSI时钟 */
oscinitstruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
oscinitstruct.PLL.PLLState = RCC_PLL_ON;
oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL16;
if (HAL_RCC_OscConfig(&oscinitstruct)!= HAL_OK)
{
/* Initialization Error */
while(1);
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers 将PLL的输出,作为系统时钟*/
clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK)
{
/* Initialization Error */
while(1);
}
}
由于作者为了减少PCB板子的尺寸,因此在设计过程中,硬件上没有接外部晶振和32.768的低速晶振。因此只能使用内部HSI作为时钟源,但是在使用HSI作为时钟源时,系统的时钟最大只能设置到64MHz;
代码主要逻辑如下:
1、将HSI的晶振作为系统的晶振输入;
2、关闭HSE时钟源;
3、关闭LSE时钟源;
4、计算出SYSCLK = HSI /2 * PLL_MUl16 = 8/2 * 16 = 64M;
5、调用HAL_RCC_OscConfig()接口,设置系统时钟源;
6、选择PLLCLK的输出,最为系统时钟(64M);
总结
本文主要描述了,在STM32F103 CPU初始化过程中,系统时钟的初始化。虽然,我们可以利用ST提供的上位机图形化工具进行时钟配置,简单的勾选就可以产生我们需要的代码。但是,作为一个嵌入式开发程序员,我觉得,还是有必要去分析源码,了解CPU的内部原理和HAL层代码,这样才能根据自己产品的实际需求情况,设计出更具有性价比的产品。