3、SystemInit时钟配置分析

1、新建工程之后,第一个最重要的文件就是启动文件” startup_stm32f10x_xd.s”,它是汇编文件,主要做了:

        1)初始化堆栈内存空间

        2)设置PC寄存器的地址指向Reset_Handler,即上电便运行复位程序

        3)设置向量表,中断服务函数入口地址

        4)配置系统时钟SystemInit

        5) 运行外部的函数,LDR R0, =__main;即:开始运行c库,并最终调用用户编写的C程序main函数

3、其他的都不管,只分析配置系统时钟SystemInit的过程

4、找到下面指令:LDR     R0, =SystemInit

3、SystemInit时钟配置分析

 5、跳转到该函数(编译后,按F12)

6、void SystemInit (void)函数如下:

/**
  * @brief  Setup the microcontroller system
  *         Initialize the Embedded Flash Interface, the PLL and update the 
  *         SystemCoreClock variable.
  * @note   This function should be used only after reset.
  * @param  None
  * @retval None
  */
void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   
  
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL
  /* Reset PLL2ON and PLL3ON bits */
  RCC->CR &= (uint32_t)0xEBFFFFFF;

  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x00FF0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;      
#else
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
    
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 

  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  /* Configure the Flash Latency cycles and enable prefetch buffer */
  SetSysClock();

#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 
}

分析这段代码需要打开《STM32中文参考手册_V10.pdf》第6.3小节:

1、RCC->CR |= (uint32_t)0x00000001;//把RCC_CR寄存器的第0位置1:打开HSI

2、#ifndef STM32F10X_CL//定义模板时用的是STM32F10X_MD,所以,会执行else

3、RCC->CFGR &= (uint32_t)0xF0FF0000;//复位一些位(保持寄存器的初始状态)

4、RCC->CR &= (uint32_t)0xFEF6FFFF;//同上

5、  RCC->CR &= (uint32_t)0xFFFBFFFF;//

6、 RCC->CFGR &= (uint32_t)0xFF80FFFF;//

7、RCC->CIR = 0x009F0000;//关闭所有中断,清除所有中断标志位

8、  SetSysClock();//设置系统时钟函数

7、SetSysClock();//设置系统时钟函数,F12跳转

/**
  * @brief  Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
  * @param  None
  * @retval None
  */
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
  SetSysClockTo72();
#endif
 
 /* If none of the define above is enabled, the HSI is used as System clock
    source (default after reset) */ 
}

通过判断一些标识符有没有定义,去执行不同的函数

通过F12跳转发现只有:#elif defined SYSCLK_FREQ_72MHz能被编译器找到

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
#define SYSCLK_FREQ_72MHz  72000000
#endif

也就是说,官方默认配置的系统时钟是72MHz

[如果要设置其他频率,只需屏蔽72M,打开需要的相应频率即可]

接下来会执行:

#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();

8、继续跳转  SetSysClockTo72();【重点!!!】

#elif defined SYSCLK_FREQ_72MHz
/**
  * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2 
  *         and PCLK1 prescalers. 
  * @note   This function should be used only after reset.
  * @param  None
  * @retval None
  */
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);
 
  /* 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;    

 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK/2 */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
    /* Configure PLLs ------------------------------------------------------*/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  
    /* Enable PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* Wait till PLL2 is ready */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }
    
   
    /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL9); 
#else    
    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  else
  { /* If HSE fails to start-up, the application will have wrong clock 
         configuration. User can add here some code to deal with this error */
  }
}

1、  RCC->CR |= ((uint32_t)RCC_CR_HSEON);//打开HSE

3、SystemInit时钟配置分析

 需要解释的是:自己配置寄存器时,不能直接配置寄存器的某一位为0或者为1,因为大多寄存器的访问只允许:字, 半字 和字节访问。(但是寄存器的每一位,官方都已经定义好名字),所以可以采用上面的方式去定义

2、//等待外部时钟稳定。如果RCC_CR_HSERDY位为1,说明外部时钟已经就绪

  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

如果外部时钟已经就绪或者超时未就绪

#define HSE_STARTUP_TIMEOUT   ((uint16_t)0x0500) //超时时间

3、都会退出do...while...进入下面判断

如果外部时钟就绪: 

if ((RCC->CR & RCC_CR_HSERDY) != RESET)//RCC_CR_HSERDY位≠0

HSEStatus = (uint32_t)0x01;//标志位置1

否则

HSEStatus = (uint32_t)0x00;//标志位清0

[  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;//为函数中自己定义的两个标志位]

--------------------------------------------------------------------------------------------------------------------

4A、if (HSEStatus == (uint32_t)0x01)// 如果外部时钟就绪,标志位置1

/-----------------配置flash----------------------------------/

    FLASH->ACR |= FLASH_ACR_PRFTBE;
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;

参考《STM32F10xxx闪存编程参考手册.pdf》

3、SystemInit时钟配置分析

/------------------配置HCLK/PCLK2/PCLK1-----------------/

    /* HCLK = SYSCLK ,HCLK=系统时钟,意味着AHB预分频系数要设置为1*/
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    /* PCLK2 = HCLK ,PCLK2=HCLK,意味着APB2预分频系数要设置为1*/
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    /* PCLK1 = HCLK /2,PCLK1=HCLK的一半(官方注释错误),意味着APB2预分频要➗2*/
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

3、SystemInit时钟配置分析

/-------配置锁相环(分频器)-PLLSRC=HSE,PLLMULL=9-------/

  /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
  RCC_CFGR_PLLMULL));
  RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

3、SystemInit时钟配置分析

     /*---------------Enable PLL-------------------------------- */

    RCC->CR |= RCC_CR_PLLON;//前面的位配置完之后,再打开锁相环

3、SystemInit时钟配置分析

/---------------------等待PLL准备就绪-----------------------------/

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0);

/----------------------选择锁相环作为系统时钟输入CFGR的SW位=0x10------------/

    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; 

/-------------------------------等待系统时钟就绪---------------------------------------/

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08);

#如果走到这里:此时,使用外部晶振HSE(8MHz),HSE作为PLL锁相环的输入,锁相环9倍频输出,SYSCLK=72MHz,AHB=1分频,则HCLK=SYSLCK=72MHZ,APB1低速外设总线预分频器2分频则PCLK1=36MHz,APB2高速外设总线预分频器1分频则PCLK2=72MHZ。

/---------------------------------正常流程结束-----------------------------------------------------------/

 4B、else//外部晶振无效,硬件默认配置使用HSI

  { /* If HSE fails to start-up, the application will have wrong clock 
         configuration. User can add here some code to deal with this error */
  }

/---------------------------------异常流程结束,使用内部RC-HSI-------------------------------------/

也就是说,无论如何,创建完工程之后,写个空的main函数,单片机就已经可以工作了。

上一篇:层次分析法的代码


下一篇:某大学作业