您现在的位置: 主页 > 技术分享 > 硬件知识 > MCU & ARM

STM32时钟初始化函数SystemInit()详解

 
关于SystemInit()函数实现了哪些功能,下面进行介绍:使用的是3.5的库,用的是STM32F107VC,开发环境RVMDK4.23
已经定义了STM32F10X_CL,SYSCLK_FREQ_72MHz
函数调用顺序:
startup_stm32f10x_cl.s(启动文件) → SystemInit() →  SetSysClock () → SetSysClockTo72()
初始化时钟用到的RCC寄存器复位值:
RCC_CR = 0x0000 xx83; RCC_CFGR = 0x0000 0000;RCC_CIR = 0x0000 0000; RCC_CFGR2 = 0x0000 0000;
SystemInit()
在调用 SetSysClock()之前RCC寄存器的值如下(都是一些与运算,或运算,在此就不赘述了):
RCC->CR = 0x0000 0083;内、外部高速时钟的选择使能、就绪标志
RCC->CIR = 0x00FF0000; LSI、LSE、HIS、HSE、PLL就绪中断标志
RCC->CFGR2 = 0x00000000;系统时钟源切换及状态
***于这些寄存器都代表着什么意思,详见芯片资料RCC寄存器,该文重点不在此处;
SetSysClock()函数如下
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz
//我的定义的是SYSCLK_FREQ_72MHz,所以调用SetSysClockTo72()
  SetSysClockTo72();
#endif
}
SetSysClockTo72()函数如下:
static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);1、使能外部晶振
  /* Wait till HSE is ready and if Time out is reached exit */
  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)
  {
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;
 
    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    
一、先设AHB APB1 AHB2分频寄存器RCC->CFGR  
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;2、系统时钟不分频作为AHB频率所以AHB等于SYSCLK频率0xxx: system clock not divided   Bits 7:4 HPRE: AHB prescaler:Set and cleared by software to control AHB clock division factor.
      
    /* PCLK2 = HCLK/2 */
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;3、AHB时钟2分频作为高速APB2时钟故APB2=(AHB=SYSCLK)/2
PPRE2: APB high-speed prescaler (APB2)
Set and cleared by software to control APB high-speed clock division factor.
0xx: AHB clock not divided
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;4、AHB时钟4分频作为低速APB1时钟故APB1=(APB2=AHB=SYSCLK)/4,所以定时器2~7时钟为2倍APB1,为60M--参加文章:
STM32中定时器的时钟源
 
PPRE1: APB Low speed prescaler (APB1)
Set and cleared by software to control APB low-speed clock division factor.
100: AHB clock divided by 2
#ifdef STM32F10X_CL
二、配置PLL2时钟频率
    /* Configure PLLs ------------------------------------------------------*/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
    /* Configure the main PLL */
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);5、所以PLL时钟=8M/8*240/2=120M SYSCLK=AHB=120M,PLL时钟=8M/8*240/2=120M,APB2=60M,APB1=30M(upt项目时钟)
RCC_PLLCFGR_PLLSRC_HSE:
Bit 22 PLLSRC: Main PLL(PLL) and audio PLL (PLLI2S) entry clock source
1: HSE oscillator clock selected as PLL and PLLI2S clock entry
 
Bits 17:16 PLLP: Main PLL (PLL) division factor for main system clock
PLL output clock frequency = VCO frequency / PLLP with PLLP = 2, 4, 6, or 8
00: PLLP = 2
f(PLL general clock output) = f(VCO clock) / PLLP,
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define PLL_M      8   
#define PLL_N      240  
#define PLL_P      2   
 
/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
#define PLL_Q      5
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /* Enable the main PLL */
    RCC->CR |= RCC_CR_PLLON; 6、使能PLL时钟
Bit 24 PLLON: Main PLL (PLL) enable
Set and cleared by software to enable PLL.
    /* Wait till the main PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
   
    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;
 
    /* Select the main PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= RCC_CFGR_SW_PLL;7、将PLL作为系统时钟
Bits 1:0 SW: System clock switch
Set and cleared by software to select the system clock source.
Set by hardware to force the HSI selection when leaving the Stop or Standby mode or in
case of failure of the HSE oscillator used directly or indirectly as the system clock.
00: HSI oscillator selected as system clock
01: HSE oscillator selected as system clock
10: PLL selected as system clock
11: not allowed
    /* Wait till the main PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    {
    }
 
 
1:AHB, APB1,APB2时钟确定
//HCLK = SYSCLK ,从下面的分析可以得出SYSCLK是使用PLLCLK时钟的,也就是72MHZ(***于72MHZ如何得来,请看下面分析)
   //那么就是HCLK(AHB总线时钟)=PLLCLK = 72MHZ    
    //AHB总线时钟等于系统时钟SYSCLK,也就是 AHB时钟 = HCLK = SYSCLK = 72MHZ
   /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
 
   //PLCK2等于HCLK一分频, 所以PCLK2 = HCLK,HCLK = 72MHZ, 那么PLCK2(APB2总线时钟) = 72MHZ   
   //APB2总线时钟等于HCLK的一分频,也就是不分频;APB2 时钟 = HCLK = SYSCLK = 72MHZ 
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
 
    //PCLK1 = HCLK / 2;PCLK1 等于HCLK时钟的二分频,那么PCLK1(APB1) = 72MHZ / 2 = 36MHZ    
    //APB1总线时钟等于HCLK的二分频,也就是 APB1时钟= HCLK / 2 = 36MHZ
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
 
2:如何得出SYSCLK(系统时钟)为72MHZ(外部晶振25MHZ)
//记得参考英文芯片资料的时钟树P115页和RCC时钟寄存器进行理解
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
 
RCC_CFGR2_PREDIV2_DIV5:  PREDIV2 = 5; 5分频
          也就是PREDIV2对输入的外部时钟 5分频,那么PLL2和PLL3没有倍频前是25 /5 = 5MHZ
RCC_CFGR2_PLL2MUL8  : PLL2MUL = 8; 8倍频  
          8倍频后,PLL2时钟 = 5 * 8 = 40MHZ; 因此 PLL2CLK = 40MHZ
RCC_CFGR2_PREDIV1SRC_PLL2 : RCC_CFGR2的第16位为1, 选择PLL2CLK 作为PREDIV1的时钟源
RCC_CFGR2_PREDIV1_DIV5:PREDIV1 = 5;PREDIV1对输入时钟5分频 PREDIV1CLK = PLL2CLK / 5 = 8MHZ
 
以上是对RCC_CFGR2进行的配置
--------------------------------------------------------------------------------------
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
 RCC_CFGR_PLLMULL9); 
 
RCC_CFGR_PLLXTPRE_PREDIV1 :操作的是RCC_CFGR的第17位PLLXTPRE,操作这一位和操作RCC_CFGR2寄存器的
位[3:0]中的**位是相同的效果  
RCC_CFGR_PLLSRC_PREDIV1 :选择PREDIV1输出作为PLL输入时钟;PREDIV1CLK = 8MHZ,所以输入给PLL倍频的
时钟源是8MHZ
RCC_CFGR_PLLMULL9 :PLLMUL = 9;PLL倍频系数为9,也就是对 PLLCLK = PREDIV1CLK * 8 = 72MHZ
 
以上是对RCC_CFGR进行的配置
---------------------------------------------------------------------------------------------------
 
 RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   //选择PLLCLK作为系统时钟源 
 
--------------------------------------------------------------------------------------------------
***此基本配置已经完成,配置的时钟如下所述:
SYSCLK(系统时钟) = 72MHZ
AHB总线时钟   = 72MHZ
APB1总线时钟  = 36MHZ
APB2总线时钟  = 72MHZ
PLL时钟   = 72MHZ
PLL2时钟  = 40MHZ

版权*转载申明:
本站内容为本站编辑或整理,所以转载务必通知本站并以超链接形式注明内容来自本站,以免带来不必要麻烦。文章出处:http://www.360doc.com/content/17/0905/13/6973384_684731817.shtml