ST固件库 SetSysClockTo72(void) 解析

[复制链接]
4536|22
 楼主| sunmeat 发表于 2014-9-25 10:32 | 显示全部楼层 |阅读模式
一直以来,对系统的初始化比较感兴趣,系统的主时钟是如何得到的呢,现解析如下
  1. #elif defined SYSCLK_FREQ_72MHz
  2. /**
  3.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Sets System clock frequency to 72MHz and configure HCLK, PCLK2
  4.   *         and PCLK1 prescalers.
  5.   * [url=home.php?mod=space&uid=536309]@NOTE[/url]   This function should be used only after reset.
  6.   * @param  None
  7.   * @retval None
  8.   */
  9. static void SetSysClockTo72(void)
  10. {
  11.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  12.   
  13.   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/   
  14.   /* Enable HSE */   
  15.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);

  16.   /* Wait till HSE is ready and if Time out is reached exit */
  17.   do
  18.   {
  19.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
  20.     StartUpCounter++;  
  21.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  22.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  23.   {
  24.     HSEStatus = (uint32_t)0x01;
  25.   }
  26.   else
  27.   {
  28.     HSEStatus = (uint32_t)0x00;
  29.   }  

  30.   if (HSEStatus == (uint32_t)0x01)
  31.   {
  32.     /* Enable Prefetch Buffer */
  33.     FLASH->ACR |= FLASH_ACR_PRFTBE;

  34.     /* Flash 2 wait state */
  35.     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
  36.     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   


  37.     /* HCLK = SYSCLK */
  38.     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
  39.       
  40.     /* PCLK2 = HCLK */
  41.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
  42.    
  43.     /* PCLK1 = HCLK */
  44.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

  45. #ifdef STM32F10X_CL
  46.     /* Configure PLLs ------------------------------------------------------*/
  47.     /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
  48.     /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
  49.         
  50.     RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
  51.                               RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
  52.     RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
  53.                              RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  54.   
  55.     /* Enable PLL2 */
  56.     RCC->CR |= RCC_CR_PLL2ON;
  57.     /* Wait till PLL2 is ready */
  58.     while((RCC->CR & RCC_CR_PLL2RDY) == 0)
  59.     {
  60.     }
  61.    
  62.    
  63.     /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */
  64.     RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
  65.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
  66.                             RCC_CFGR_PLLMULL9);
  67. #else   
  68.     /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
  69.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
  70.                                         RCC_CFGR_PLLMULL));
  71.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
  72. #endif /* STM32F10X_CL */

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

  75.     /* Wait till PLL is ready */
  76.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
  77.     {
  78.     }
  79.    
  80.     /* Select PLL as system clock source */
  81.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
  82.     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   

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



 楼主| sunmeat 发表于 2014-9-25 11:05 | 显示全部楼层
#elif defined SYSCLK_FREQ_72MHz
这句的意思是,假如宏定义了SYSCLK_FREQ_72MHz,才会执行下面的语句,SYSCLK_FREQ_72MHz这个宏定义,在system_stm32f10x.c的第115行定义
  1. #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  2. /* #define SYSCLK_FREQ_HSE    HSE_VALUE */
  3. #define SYSCLK_FREQ_24MHz  24000000
  4. #else
  5. /* #define SYSCLK_FREQ_HSE    HSE_VALUE */
  6. /* #define SYSCLK_FREQ_24MHz  24000000 */
  7. /* #define SYSCLK_FREQ_36MHz  36000000 */
  8. /* #define SYSCLK_FREQ_48MHz  48000000 */
  9. /* #define SYSCLK_FREQ_56MHz  56000000 */
  10. #define SYSCLK_FREQ_72MHz  72000000
  11. #endif
根据屏蔽掉的注释,选择不同的系统主时钟,然后在下面执行不同的代码,这里屏蔽掉的是#define SYSCLK_FREQ_72MHz  72000000的注释
 楼主| sunmeat 发表于 2014-9-25 11:09 | 显示全部楼层
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
#define  RCC_CR_HSEON                        ((uint32_t)0x00010000)        /*!< External High Speed clock enable */
这句的意思是使能外部的HSE,就是使能外部晶振的意思。CR的第16位置1,开启HSE振荡器
图像 602.png
 楼主| sunmeat 发表于 2014-9-25 11:14 | 显示全部楼层
  1.   do
  2.   {
  3.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
  4.     StartUpCounter++;  
  5.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
#define  RCC_CR_HSERDY                       ((uint32_t)0x00020000)        /*!< External High Speed clock ready flag */
#define HSE_STARTUP_TIMEOUT   ((uint16_t)0x0500) /*!< Time out for HSE start up */
 楼主| sunmeat 发表于 2014-9-25 11:16 | 显示全部楼层
首先取得HSE稳定的标志,在CR的第17位
#define  RCC_CR_HSERDY                       ((uint32_t)0x00020000)        /*!< External High Speed clock ready flag */
图像 603.png
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;  
不停的查询HSE稳定的标志
 楼主| sunmeat 发表于 2014-9-25 11:20 | 显示全部楼层
while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
只要HSE一直不稳定并且没到达稳定时间,一直检测HSE标志的状态,假设期间HSE的标志由硬件置1或者达到溢出时间,直接退出检测循环
 楼主| sunmeat 发表于 2014-9-25 11:28 | 显示全部楼层
  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  
再次加入判断晶振是否稳定的判断,上面的语句退出,是为了避免死循环,假如晶振已经稳定,HSEStatus置1,后面根据HSEStatus的状态执行语句
 楼主| sunmeat 发表于 2014-9-25 11:51 | 显示全部楼层
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;
#define  FLASH_ACR_PRFTBE                    ((uint8_t)0x10)               /*!< Prefetch Buffer Enable */
注意,FLASH_ACR这个寄存器在中文的手册中找不到,在英文的手册中才可以找到
图像 605.png
使能FLASH的预缓冲器
 楼主| sunmeat 发表于 2014-9-25 12:02 | 显示全部楼层
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
#define  FLASH_ACR_LATENCY                   ((uint8_t)0x03)               /*!< LATENCY[2:0] bits (Latency) */
FLASH_ACR_LATENCY为0x03,~FLASH_ACR_LATENCY为1111 1100,再与原来的状态相与为最低两位置0
 楼主| sunmeat 发表于 2014-9-25 12:03 | 显示全部楼层
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;  
#define  FLASH_ACR_LATENCY_2                 ((uint8_t)0x02)               /*!< Bit 1 */
图像 607.png
FLASH设置为2等待状态
 楼主| sunmeat 发表于 2014-9-25 12:06 | 显示全部楼层
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
#define  RCC_CFGR_HPRE_DIV1                  ((uint32_t)0x00000000)        /*!< SYSCLK not divided */
图像 608.png
AHB预分频系数设置为SYSCLK不分频,即HCLK = SYSCLK
 楼主| sunmeat 发表于 2014-9-25 12:07 | 显示全部楼层
本帖最后由 sunmeat 于 2014-9-25 15:15 编辑

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
#define  RCC_CFGR_PPRE2_DIV1                 ((uint32_t)0x00000000)        /*!< HCLK not divided */
图像 610.png
APB2的预分频系数为HCLK不分频,即PCLK2 = HCLK
 楼主| sunmeat 发表于 2014-9-25 15:19 | 显示全部楼层
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
#define  RCC_CFGR_PPRE1_DIV2                 ((uint32_t)0x00000400)        /*!< HCLK divided by 2 */
图像 611.png
APB1时钟的预分频系数为HCLK二分频,即PCLK1=HCLK/2
 楼主| sunmeat 发表于 2014-9-25 15:25 | 显示全部楼层
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
这个函数不外乎是把某个位置零的函数,不用管他,关键是后面的函数。
 楼主| sunmeat 发表于 2014-9-25 15:37 | 显示全部楼层
本帖最后由 sunmeat 于 2014-9-25 15:54 编辑

    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
#define  RCC_CFGR2_PREDIV2_DIV5             ((uint32_t)0x00000040)        /*!< PREDIV2 input clock divided by 5 */
#define  RCC_CFGR2_PLL2MUL8                 ((uint32_t)0x00000600)        /*!< PLL2 input clock * 8 */
#define  RCC_CFGR2_PREDIV1SRC_PLL2          ((uint32_t)0x00010000)        /*!< PLL2 selected as PREDIV1 entry clock source */
#define  RCC_CFGR2_PREDIV1_DIV5             ((uint32_t)0x00000004)        /*!< PREDIV1 input clock divided by 5 */
 楼主| sunmeat 发表于 2014-9-25 15:46 | 显示全部楼层
本帖最后由 sunmeat 于 2014-9-25 15:53 编辑

#define  RCC_CFGR2_PREDIV2_DIV5             ((uint32_t)0x00000040)        /*!< PREDIV2 input clock divided by 5 */
图像 613.png
PREDIV2对输入时钟进行5分频
 楼主| sunmeat 发表于 2014-9-25 15:55 | 显示全部楼层
#define  RCC_CFGR2_PLL2MUL8                 ((uint32_t)0x00000600)        /*!< PLL2 input clock * 8 */
图像 614.png
PLL2 8倍频输出
 楼主| sunmeat 发表于 2014-9-25 15:57 | 显示全部楼层
#define  RCC_CFGR2_PREDIV1SRC_PLL2          ((uint32_t)0x00010000)        /*!< PLL2 selected as PREDIV1 entry clock source */
图像 615.png
选择PLL2CLK 作为PREDIV1的时钟源
 楼主| sunmeat 发表于 2014-9-25 15:58 | 显示全部楼层
#define  RCC_CFGR2_PREDIV1_DIV5             ((uint32_t)0x00000004)        /*!< PREDIV1 input clock divided by 5 */
图像 616.png
PREDIV1对输入时钟五分频
 楼主| sunmeat 发表于 2014-9-25 16:03 | 显示全部楼层

  1.     RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
  2.                              RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
这段代码是基于外部时钟是25MHZ来配置的,讲诉的这么详细是为了说明PLL时钟是怎么来的。根据时钟树中的配置,PLL的时钟是这么算的
图像 617.png
HSE/5*8/5=8MHZ
您需要登录后才可以回帖 登录 | 注册

本版积分规则

208

主题

2132

帖子

13

粉丝
快速回复 在线客服 返回列表 返回顶部