在系统启动之后,程序会先执行HAL库定义的SystemInit函数,进行系统一些初始化配置。SystemInit程序如下:
void SystemInit(void)
{
// FPU 设置
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));
#endif
// 复位RCC时钟配置为默认配置
RCC->CR |= (uint32_t)0x00000001; // 打开HSION位
RCC->CFGR = 0x00000000; // 复位CFGR
RCC->CR &= (uint32_t)0xFEF6FFFF; // 复位HSEON, CSSON 和 PLLON位
RCC->PLLCFGR = 0x24003010; // 复位寄存器PLLCFGR
RCC->CR &= (uint32_t)0xFFFBFFFF; // 复位HSEBYP位
RCC->CIR = 0x00000000; // 关闭所有中断
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
// 配置中断向量表地址 = 基地址 + 偏移地址
#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
}
从上面代码可以看出,SystemInit主要做了如下四个方面工作:
- FPU设置
- 复位RCC时钟配置为默认复位值(默认开始了HSI内部时钟)
- 外部存储器配置
- 中断向量表地址配置
HAL库的SystemInit函数并没有像标准库的SystemInit函数一样进行时钟的初始化配置。HAL库的SystemInit函数除了打开HSI之外,没有任何时钟相关配置,所以使用HAL库我们必须编写自己的时钟配置函数。
系统时钟配置函数如下(配置为168M):
// Systick时钟配置 168M
void CLOCLK_Init(void)
{
RCC_OscInitTypeDef RCC_OscInitStructure; // 定义初始化锁相环配置的结构体变量
RCC_ClkInitTypeDef RCC_ClkInitStructure; // 定义初始化系统时钟源的结构体变量
RCC_OscInitStructure.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 晶振类型,外部高速时钟源
RCC_OscInitStructure.HSEState = RCC_HSE_ON; // 打开HSE
RCC_OscInitStructure.PLL.PLLState = RCC_PLL_ON; // 打开PLL
RCC_OscInitStructure.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL时钟源选择HSE
RCC_OscInitStructure.PLL.PLLM = 8; // 主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
RCC_OscInitStructure.PLL.PLLN = 336; // 主PLL倍频系数(PLL倍频),取值范围:64~432.
RCC_OscInitStructure.PLL.PLLP = 2; // 系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
RCC_OscInitStructure.PLL.PLLQ = 7; // USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
if(HAL_RCC_OscConfig(&RCC_OscInitStructure) != HAL_OK) while(1); //初始化
// 选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
RCC_ClkInitStructure.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStructure.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 设置系统时钟时钟源为PLL
RCC_ClkInitStructure.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB分频系数为1
RCC_ClkInitStructure.APB1CLKDivider = RCC_HCLK_DIV4; // APB1分频系数为4
RCC_ClkInitStructure.APB2CLKDivider = RCC_HCLK_DIV2; // APB2分频系数为2
if(HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_5)) while(1); // 同时设置FLASH延时周期为5WS,也就是6个CPU周期。
}