LinkedInSTM32F4 时钟体系初始化是在system_stm32f4xx.c中的 SystemInit()函数中完结的。 关于体系时钟要害寄存器设置主要是在 SystemInit 函数中调用 SetSysClock()函数来设置的。咱们能够先看看 SystemInit ()函数体:
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
SetSysClock();
#ifdef VECT_TAB_SRAM
SCB-》VTOR = SRAM_BASE | VECT_TAB_OFFSET;
#else
SCB-》VTOR = FLASH_BASE | VECT_TAB_OFFSET;
#endif
}
SystemInit函数开端先进行浮点运算单元设置,然后是复位PLLCFGR,CFGR寄存器,一起经过设置 CR 寄存器的 HSI 时钟使能位来翻开 HSI 时钟。默许状况下假如 CFGR 寄存器复位,那么是挑选HSI作为体系时钟,这点咱们能够检查RCC-》CFGR 寄存器的位描绘最低2位能够得知,当低两位装备为 00的时分(复位之后),会挑选 HSI振荡器为体系时钟。也便是说,调用 SystemInit 函数之后,首要是挑选 HSI 作为体系时钟。
在设置完相关寄存器后,接下来SystemInit函数内部会调用 SetSysClock函数。这个函数比较长,咱们就把函数一些要害代码行截取出来给咱们解说一下。这儿咱们省掉一些宏界说标识符值的判别而直接把针对STM32F407 比较重要的内容贴出来:
staTIc void SetSysClock(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC-》CR |= ((uint32_t)RCC_CR_HSEON);
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)
{
RCC-》APB1ENR |= RCC_APB1ENR_PWREN;
PWR-》CR |= PWR_CR_VOS;
RCC-》CFGR |= RCC_CFGR_HPRE_DIV1;
RCC-》CFGR |= RCC_CFGR_PPRE2_DIV2;
RCC-》CFGR |= RCC_CFGR_PPRE1_DIV4;
RCC-》CFGR |= RCC_CFGR_PPRE2_DIV1;
RCC-》CFGR |= RCC_CFGR_PPRE1_DIV2;
RCC-》PLLCFGR = PLL_M | (PLL_N 《《 6) | (((PLL_P 》》 1) -1) 《《 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q 《《 24);
RCC-》CR |= RCC_CR_PLLON;
while((RCC-》CR & RCC_CR_PLLRDY) == 0)
{
}
FLASH-》ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN
|FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
RCC-》CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC-》CFGR |= RCC_CFGR_SW_PLL;
while ((RCC-》CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
{
}
}
else
{
}
}
这段代码的大致流程是这样的:先使能外部时钟 HSE,等候 HSE 安稳之后,装备AHB,APB1,APB2 时钟相关的分频因子,也便是相关外设的时钟。等候这些都装备完结之后,翻开主PLL时钟,然后设置主PLL作为体系时钟 SYSCLK时钟源。假如HSE 不能到达安排妥当状况(比方外部晶振不能安稳或许没有外部晶振),那么仍然会是HSI作为体系时钟。
在这儿要特别提出来,在设置主PLL时钟的时分,会要设置一系列的分频系数和倍频系数参数。咱们能够从SetSysClock函数的这行代码看出:
RCC-》PLLCFGR = PLL_M | (PLL_N 《《 6) | (((PLL_P 》》 1) -1) 《《 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q 《《 24);
这些参数是经过宏界说标识符的值来设置的。默许的装备在 System_stm32f4xx.c 文件最初的当地装备。关于咱们开发板,咱们的设置参数值如下:
#define PLL_M 8
#define PLL_Q 7
#define PLL_N 336
#define PLL_P 2
所以咱们的主PLL时钟为:
PLL=8MHz * N/ (M*P)=8MHz* 336 /(8*2) = 168MHz
在开发进程中,咱们能够经过调整这些值来设置咱们的体系时钟。
这儿还有个特别需求留意的当地,便是咱们还要同步修正 stm32f4xx.h 中宏界说标识符HSE_VALUE 的值为咱们的外部时钟:
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000)
#endif
这儿默许固件库装备的是25000000,咱们外部时钟为8MHz,所以咱们依据咱们硬件状况修正为8000000即可。
讲到这儿,咱们对 SystemInit 函数的流程会有个比较明晰的了解。那么 SystemInit 函数是怎样被体系调用的呢?SystemInit是整个设置体系时钟的进口函数。这个函数关于咱们运用ST供给的 STM32F4 固件库的话,会在体系发动之后先履行main函数,然后再接着履行SystemInit函数完结体系相关时钟的设置。这个进程设置是在发动文件 startup_stm32f40_41xxx.s中心设置的,咱们接下来看看发动文件中这段发动代码:
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
这段代码的作用是在体系复位之后引导进入main函数,一起在进入main函数之前,首要
要调用 SystemInit体系初始化函数完结体系时钟等相关装备。
最终咱们总结一下SystemInit()函数中设置的体系时钟巨细:
SYSCLK(体系时钟) =168MHz
AHB总线时钟(HCLK=SYSCLK) =168MHz
APB1总线时钟(PCLK1=SYSCLK/4) =42MHz
APB2总线时钟(PCLK2=SYSCLK/2) =84MHz
PLL主时钟 =168MHz