stm32F429启动时钟配置
阅读原文时间:2023年07月13日阅读:1

STM32f429在启动时会在startup_stm32f429_439xx.s中调用static void SetSysClock(void)函数。默认使用的是25M晶振,把系统时钟设置为180M.

在system_stm32f4xx.c中给出了相关的默认时钟参数设置。static void SetSysClock(void)函数执行的就是这个参数设置的过程。

*=============================================================================
* Supported STM32F42xxx/43xxx devices
*-----------------------------------------------------------------------------
* System Clock source | PLL (HSE)
*-----------------------------------------------------------------------------
* SYSCLK(Hz) |
*-----------------------------------------------------------------------------
* HCLK(Hz) |
*-----------------------------------------------------------------------------
* AHB Prescaler |
*-----------------------------------------------------------------------------
* APB1 Prescaler |
*-----------------------------------------------------------------------------
* APB2 Prescaler |
*-----------------------------------------------------------------------------
* HSE Frequency(Hz) |
*-----------------------------------------------------------------------------
* PLL_M |
*-----------------------------------------------------------------------------
* PLL_N |
*-----------------------------------------------------------------------------
* PLL_P |
*-----------------------------------------------------------------------------
* PLL_Q |
*-----------------------------------------------------------------------------
* PLLI2S_N | NA
*-----------------------------------------------------------------------------
* PLLI2S_R | NA
*-----------------------------------------------------------------------------
* I2S input clock | NA
*-----------------------------------------------------------------------------
* VDD(V) | 3.3
*-----------------------------------------------------------------------------
* Main regulator output voltage | Scale1 mode
*-----------------------------------------------------------------------------
* Flash Latency(WS) |
*-----------------------------------------------------------------------------
* Prefetch Buffer | ON
*-----------------------------------------------------------------------------
* Instruction cache | ON
*-----------------------------------------------------------------------------
* Data cache | ON
*-----------------------------------------------------------------------------
* Require 48MHz for USB OTG FS, | Disabled
* SDIO and RNG clock |
*-----------------------------------------------------------------------------
*=============================================================================

假设外部晶振改成了其他的数值比如说8M ,要修改  "stm32f4xx.h " 文件中的 "HSE_VALUE" 宏定义。

如果程序在运行过程中动态修改了PLL倍频系数,或者切换了时钟源,请务必执行一次 SystemCoreClockUpdate()函数,这个函数会自动根据PLL倍频参数计算出实际的主频。

void SystemCoreClockUpdate(void)函数会检测 RCC clock configurat ion register (RCC_CFGR)寄存器的 Bits 3:2 这两位是只读的,由硬件清除和设置,不能软件写入。

Bits 3:2 SWS: System clock switch status
Set and cleared by hardware to indicate which clock source is used as the system clock.
00: HSI oscillator used as the system clock
01: HSE oscillator used as the system clock
10: PLL used as the system clock
11: not applicable

根据这两位通过置swtich语句分析设置源的选择,进一步进行设置,如果是用PLL还要读取RCC_PLLCFGR寄存器的值

获取P N M PLLSRC等参数,来更新系统时钟。系统时钟SYSCLK 有下列公式决定。

PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
SYSCLK = PLL_VCO / PLL_P

最后获得HCLK frequency :

tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
/* HCLK frequency */
SystemCoreClock >>= tmp;

void SystemCoreClockUpdate(void)
{
uint32_t tmp = , pllvco = , pllp = , pllsource = , pllm = ;
#if defined(STM32F446xx)
uint32_t pllr = ;
#endif /* STM32F446xx */
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;

switch (tmp)
{
case 0x00: /* HSI used as system clock source */
SystemCoreClock = HSI_VALUE;
break;
case 0x04: /* HSE used as system clock source */
SystemCoreClock = HSE_VALUE;
break;
case 0x08: /* PLL P used as system clock source */
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
SYSCLK = PLL_VCO / PLL_P
*/
pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> ;
pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;

#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F446xx) || defined(STM32F469_479xx)
if (pllsource != )
{
/* HSE used as PLL clock source */
pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> );
}
else
{
/* HSI used as PLL clock source */
pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> );
}
#elif defined(STM32F410xx) || defined(STM32F411xE)
#if defined(USE_HSE_BYPASS)
if (pllsource != )
{
/* HSE used as PLL clock source */
pllvco = (HSE_BYPASS_INPUT_FREQUENCY / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> );
}
#else
if (pllsource == )
{
/* HSI used as PLL clock source */
pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> );
}
#endif /* USE_HSE_BYPASS */
#endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F446xx || STM32F469_479xx */
pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>) + ) *;
SystemCoreClock = pllvco/pllp;
break;
#if defined(STM32F446xx)
case 0x0C: /* PLL R used as system clock source */
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
SYSCLK = PLL_VCO / PLL_R
*/
pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> ;
pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
if (pllsource != )
{
/* HSE used as PLL clock source */
pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> );
}
else
{
/* HSI used as PLL clock source */
pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> );
}

  pllr = (((RCC->PLLCFGR & RCC\_PLLCFGR\_PLLR) >>) +  ) \*;  
  SystemCoreClock = pllvco/pllr;  
  break;  

#endif /* STM32F446xx */
default:
SystemCoreClock = HSI_VALUE;
break;
}
/* Compute HCLK frequency --------------------------------------------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> )];
/* HCLK frequency */
SystemCoreClock >>= tmp;
}

另外也可以自己实现两个设置时钟的函数:

/*
* 使用HSE时,设置系统时钟的步骤
* 1、开启HSE ,并等待 HSE 稳定
* 2、设置 AHB、APB2、APB1的预分频因子
* 3、设置PLL的时钟来源
* 设置VCO输入时钟 分频因子 m
* 设置VCO输出时钟 倍频因子 n
* 设置PLLCLK时钟分频因子 p
* 设置OTG FS,SDIO,RNG时钟分频因子 q
* 4、开启PLL,并等待PLL稳定
* 5、把PLLCK切换为系统时钟SYSCLK
* 6、读取时钟切换状态位,确保PLLCLK被选为系统时钟
*/

/*
* m: VCO输入时钟 分频因子,取值2~63
* n: VCO输出时钟 倍频因子,取值192~432
* p: PLLCLK时钟分频因子 ,取值2,4,6,8
* q: OTG FS,SDIO,RNG时钟分频因子,取值4~15
* 函数调用举例,使用HSE设置时钟
* SYSCLK=HCLK=180M,PCLK2=HCLK/2=90M,PCLK1=HCLK/4=45M
* HSE_SetSysClock(25, 360, 2, 7);
* HSE作为时钟来源,经过PLL倍频作为系统时钟,这是通常的做法

* 系统时钟超频到216M爽一下
* HSE_SetSysClock(25, 432, 2, 9);
*/
void HSE_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q)
{
__IO uint32_t HSEStartUpStatus = ;

// 使能HSE,开启外部晶振,秉火F429使用 HSE=25M
RCC_HSEConfig(RCC_HSE_ON);

// 等待HSE启动稳定
HSEStartUpStatus = RCC_WaitForHSEStartUp();

if (HSEStartUpStatus == SUCCESS)
{
// 调压器电压输出级别配置为1,以便在器件为最大频率
// 工作时使性能和功耗实现平衡
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;

    // HCLK = SYSCLK / 1  
RCC\_HCLKConfig(RCC\_SYSCLK\_Div1);

 // PCLK2 = HCLK / 2  
RCC\_PCLK2Config(RCC\_HCLK\_Div2);

    // PCLK1 = HCLK / 4  
RCC\_PCLK1Config(RCC\_HCLK\_Div4);

// 如果要超频就得在这里下手啦  
    // 设置PLL来源时钟,设置VCO分频因子m,设置VCO倍频因子n,  
    //  设置系统时钟分频因子p,设置OTG FS,SDIO,RNG分频因子q  
RCC\_PLLConfig(RCC\_PLLSource\_HSE, m, n, p, q);

    // 使能PLL  
RCC\_PLLCmd(ENABLE);

  // 等待 PLL稳定  
while (RCC\_GetFlagStatus(RCC\_FLAG\_PLLRDY) == RESET)  
{  
}   

/*-----------------------------------------------------*/
//开启 OVER-RIDE模式,以能达到更高频率
PWR->CR |= PWR_CR_ODEN;
while((PWR->CSR & PWR_CSR_ODRDY) == )
{
}
PWR->CR |= PWR_CR_ODSWEN;
while((PWR->CSR & PWR_CSR_ODSWRDY) == )
{
}
// 配置FLASH预取指,指令缓存,数据缓存和等待状态
FLASH->ACR = FLASH_ACR_PRFTEN
| FLASH_ACR_ICEN
| FLASH_ACR_DCEN
| FLASH_ACR_LATENCY_5WS;
/*-----------------------------------------------------*/

    // 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK  
RCC\_SYSCLKConfig(RCC\_SYSCLKSource\_PLLCLK);

// 读取时钟切换状态位,确保PLLCLK被选为系统时钟  
while (RCC\_GetSYSCLKSource() != 0x08)  
{  
}  

}
else
{ // HSE启动出错处理

while ()  
{  
}  

}
}

/*
* 使用HSI时,设置系统时钟的步骤
* 1、开启HSI ,并等待 HSI 稳定
* 2、设置 AHB、APB2、APB1的预分频因子
* 3、设置PLL的时钟来源
* 设置VCO输入时钟 分频因子 m
* 设置VCO输出时钟 倍频因子 n
* 设置SYSCLK时钟分频因子 p
* 设置OTG FS,SDIO,RNG时钟分频因子 q
* 4、开启PLL,并等待PLL稳定
* 5、把PLLCK切换为系统时钟SYSCLK
* 6、读取时钟切换状态位,确保PLLCLK被选为系统时钟
*/

/*
* m: VCO输入时钟 分频因子,取值2~63
* n: VCO输出时钟 倍频因子,取值192~432
* p: PLLCLK时钟分频因子 ,取值2,4,6,8
* q: OTG FS,SDIO,RNG时钟分频因子,取值4~15
* 函数调用举例,使用HSI设置时钟
* SYSCLK=HCLK=180M,PCLK2=HCLK/2=90M,PCLK1=HCLK/4=45M
* HSI_SetSysClock(16, 360, 2, 7);
* HSE作为时钟来源,经过PLL倍频作为系统时钟,这是通常的做法

* 系统时钟超频到216M爽一下
* HSI_SetSysClock(16, 432, 2, 9);
*/

void HSI_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q)
{
__IO uint32_t HSIStartUpStatus = ;

// 把RCC外设初始化成复位状态  

RCC_DeInit();

//使能HSI, HSI=16M
RCC_HSICmd(ENABLE);

// 等待 HSI 就绪
HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY;

// 只有 HSI就绪之后则继续往下执行  

if (HSIStartUpStatus == RCC_CR_HSIRDY)
{
// 调压器电压输出级别配置为1,以便在器件为最大频率
// 工作时使性能和功耗实现平衡
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;

    // HCLK = SYSCLK / 1  
    RCC\_HCLKConfig(RCC\_SYSCLK\_Div1);

    // PCLK2 = HCLK / 2  
    RCC\_PCLK2Config(RCC\_HCLK\_Div2);

    // PCLK1 = HCLK / 4  
    RCC\_PCLK1Config(RCC\_HCLK\_Div4);

// 如果要超频就得在这里下手啦  
    // 设置PLL来源时钟,设置VCO分频因子m,设置VCO倍频因子n,  
    //  设置系统时钟分频因子p,设置OTG FS,SDIO,RNG分频因子q  
    RCC\_PLLConfig(RCC\_PLLSource\_HSI, m, n, p, q);

    // 使能PLL  
    RCC\_PLLCmd(ENABLE);

  // 等待 PLL稳定  
while (RCC\_GetFlagStatus(RCC\_FLAG\_PLLRDY) == RESET)  
{  
}   

/*-----------------------------------------------------*/
//开启 OVER-RIDE模式,以能达到更高频率
PWR->CR |= PWR_CR_ODEN;
while((PWR->CSR & PWR_CSR_ODRDY) == )
{
}
PWR->CR |= PWR_CR_ODSWEN;
while((PWR->CSR & PWR_CSR_ODSWRDY) == )
{
}
// 配置FLASH预取指,指令缓存,数据缓存和等待状态
FLASH->ACR = FLASH_ACR_PRFTEN
| FLASH_ACR_ICEN
|FLASH_ACR_DCEN
|FLASH_ACR_LATENCY_5WS;
/*-----------------------------------------------------*/

    // 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK  
RCC\_SYSCLKConfig(RCC\_SYSCLKSource\_PLLCLK);

// 读取时钟切换状态位,确保PLLCLK被选为系统时钟  
while (RCC\_GetSYSCLKSource() != 0x08)  
{  
}  

}
else
{ // HSI启动出错处理
while ()
{
}
}
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章