STM32时钟系统和SysTick定时器
STM32时钟系统
STM32F429的时钟树如下图所示
![时钟树]()
STM32有5个时钟源:HSI、HSE、LSI、LSE、PLL。
HSI是高速内部时钟,RC振荡器,频率为16MHz,精度不高。可以直接作为系统时钟或者用作PLL时钟输入。
HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~26MHz。
LSI是低速内部时钟,RC振荡器,频率为32kHz,提供低功耗时钟。主要供独立看 门狗和自动唤醒单元使用。
LSE是低速外部时钟,接频率为32.768kHz的石英晶体。RTC
PLL为锁相环倍频输出。
PLL为锁相环倍频输出。STM32F4有三个PLL:
主PLL(PLL)由HSE或者HSI提供时钟信号,并具有两个不同的输出时钟。
①第一个输出PLLP用于生成高速的系统时钟(最高180MHz)
②第二个输出PLLQ为48M时钟,用于USB OTG FS时钟,随机数
发生器的时钟和SDIO时钟。
第一个专用PLL(PLLI2S)生成精确时钟,在I2S和SAI1上实现高品质音频
N是用于PLLI2S vco的倍频系数,其取值范围是:192~432;
R是I2S时钟的分频系数,其取值范围是:2~7;
Q是SAI时钟分频系数,其取值范围是:2~15;P没用到。
第二个专用PLL(PLLSAI)同样用于生成精确时钟,用于SAI1输入时钟,同时还为LCD_TFT接口提供精确时钟。
N是用于PLLSAI vco的倍频系数,其取值范围是:192~432;
Q是SAI时钟分频系数,其取值范围是:2~15;
R是时钟的分频系数,其取值范围是:2-7;
主PLL时钟计算——PLLCLK= HSE * N / (M*P)
![主PLL时钟计算]()
系统时钟SYSCLK有三个时钟源:
HSI振荡器时钟。HSE振荡器时钟。PLL时钟。
Stm32_Clock_Init时钟系统初始化函数剖析
在系统启动之后,程序会先执行 HAL 库定义的 SystemInit 函数,进行系统一些初始化配置
1 2 3 4 5 6 7 8 9 10
| Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __main
LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP
|
转入SystemInit函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| void SystemInit(void) { #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); #endif RCC->CR |= (uint32_t)0x00000001;
RCC->CFGR = 0x00000000;
RCC->CR &= (uint32_t)0xFEF6FFFF;
RCC->PLLCFGR = 0x24003010;
RCC->CR &= (uint32_t)0xFFFBFFFF;
RCC->CIR = 0x00000000;
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM) SystemInit_ExtMemCtl(); #endif
#ifdef VECT_TAB_SRAM SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; #endif }
|
从上面代码可以看出,SystemInit 主要做了如下四个方面工作:
1) FPU 设置
2) 复位 RCC 时钟配置为默认复位值(默认开始了 HIS)
3) 外部存储器配置
4) 中断向量表地址配置
HAL 库的 SystemInit 函数并没有像标准库的 SystemInit 函数一样进行时钟的初始化配置。HAL库的 SystemInit 函数除了打开 HSI 之外,没有任何时钟相关配置,所以使用 HAL 库我们必须编写自己的时钟配置函数。打开工程模板SYSTEM分组下面定义的sys.c 文件中的时钟初始化函数 Stm32_Clock_Init 的内容:
时钟系统配置一般步骤:
①使能PWR时钟:调用函数__HAL_RCC_PWR_CLK_ENABLE()。
②设置调压器输出电压级别:调用函数__HAL_PWR_VOLTAGESCALING_CONFIG()。
![调压器输出级别]()
③选择是否开启Over-Driver功能:调用函数HAL_PWREx_EnableOverDrive()。
④配置时钟源相关参数:调用函数HAL_RCC_OscConfig()。
1
| HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct);
|
查看RCC_OscInitTypeDef结构体的成员变量
1 2 3 4 5 6 7 8 9 10
| typedef struct { uint32_t OscillatorType; uint32_t HSEState; uint32_t LSEState; uint32_t HSIState; uint32_t HSICalibrationValue; uint32_t LSIState; RCC_PLLInitTypeDef PLL; }RCC_OscInitTypeDef;
|
设置RCC_PLLInitTypeDef结构体类型的PLL。
1 2 3 4 5 6 7 8 9
| typedef struct { uint32_t PLLState; uint32_t PLLSource; uint32_t PLLM; uint32_t PLLN; uint32_t PLLP; uint32_t PLLQ; }RCC_PLLInitTypeDef;
|
⑤配置系统时钟源以及AHB,APB1和APB2的分频系数:调用函数HAL_RCC_ClockConfig()。
1
| HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency);
|
RCC_ClkInitTypeDef结构体类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| typedef struct { uint32_t ClockType;
uint32_t SYSCLKSource;
uint32_t AHBCLKDivider;
uint32_t APB1CLKDivider;
uint32_t APB2CLKDivider;
}RCC_ClkInitTypeDef;
|
Stm32_Clock_Init()函数实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq) { HAL_StatusTypeDef ret = HAL_OK; RCC_OscInitTypeDef RCC_OscInitStructure; RCC_ClkInitTypeDef RCC_ClkInitStructure; __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE; RCC_OscInitStructure.HSEState=RCC_HSE_ON; RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON; RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE; RCC_OscInitStructure.PLL.PLLM=pllm; RCC_OscInitStructure.PLL.PLLN=plln; RCC_OscInitStructure.PLL.PLLP=pllp; RCC_OscInitStructure.PLL.PLLQ=pllq; ret=HAL_RCC_OscConfig(&RCC_OscInitStructure); if(ret!=HAL_OK) while(1); ret=HAL_PWREx_EnableOverDrive(); if(ret!=HAL_OK) while(1); RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2); RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1; RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV4; RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV2; ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_5); if(ret!=HAL_OK) while(1); }
|