打印

ST固件库 SetSysClockTo72(void) 解析

[复制链接]
3772|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
sunmeat|  楼主 | 2014-9-25 10:32 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
一直以来,对系统的初始化比较感兴趣,系统的主时钟是如何得到的呢,现解析如下
#elif defined SYSCLK_FREQ_72MHz
/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  Sets System clock frequency to 72MHz and configure HCLK, PCLK2
  *         and PCLK1 prescalers.
  * [url=home.php?mod=space&uid=536309]@NOTE[/url]   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 */
    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 */
  }
}
#endif



沙发
sunmeat|  楼主 | 2014-9-25 11:05 | 只看该作者
#elif defined SYSCLK_FREQ_72MHz
这句的意思是,假如宏定义了SYSCLK_FREQ_72MHz,才会执行下面的语句,SYSCLK_FREQ_72MHz这个宏定义,在system_stm32f10x.c的第115行定义
#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
根据屏蔽掉的注释,选择不同的系统主时钟,然后在下面执行不同的代码,这里屏蔽掉的是#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振荡器

使用特权

评论回复
地板
sunmeat|  楼主 | 2014-9-25 11:14 | 只看该作者
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } 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 */

使用特权

评论回复
5
sunmeat|  楼主 | 2014-9-25 11:16 | 只看该作者
首先取得HSE稳定的标志,在CR的第17位
#define  RCC_CR_HSERDY                       ((uint32_t)0x00020000)        /*!< External High Speed clock ready flag */

HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;  
不停的查询HSE稳定的标志

使用特权

评论回复
6
sunmeat|  楼主 | 2014-9-25 11:20 | 只看该作者
while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
只要HSE一直不稳定并且没到达稳定时间,一直检测HSE标志的状态,假设期间HSE的标志由硬件置1或者达到溢出时间,直接退出检测循环

使用特权

评论回复
7
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的状态执行语句

使用特权

评论回复
8
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这个寄存器在中文的手册中找不到,在英文的手册中才可以找到

使能FLASH的预缓冲器

使用特权

评论回复
9
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

使用特权

评论回复
10
sunmeat|  楼主 | 2014-9-25 12:03 | 只看该作者
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;  
#define  FLASH_ACR_LATENCY_2                 ((uint8_t)0x02)               /*!< Bit 1 */

FLASH设置为2等待状态

使用特权

评论回复
11
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 */

AHB预分频系数设置为SYSCLK不分频,即HCLK = SYSCLK

使用特权

评论回复
12
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 */

APB2的预分频系数为HCLK不分频,即PCLK2 = HCLK

使用特权

评论回复
13
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 */

APB1时钟的预分频系数为HCLK二分频,即PCLK1=HCLK/2

使用特权

评论回复
14
sunmeat|  楼主 | 2014-9-25 15:25 | 只看该作者
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
这个函数不外乎是把某个位置零的函数,不用管他,关键是后面的函数。

使用特权

评论回复
15
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 */

使用特权

评论回复
16
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 */

PREDIV2对输入时钟进行5分频

使用特权

评论回复
17
sunmeat|  楼主 | 2014-9-25 15:55 | 只看该作者
#define  RCC_CFGR2_PLL2MUL8                 ((uint32_t)0x00000600)        /*!< PLL2 input clock * 8 */

PLL2 8倍频输出

使用特权

评论回复
18
sunmeat|  楼主 | 2014-9-25 15:57 | 只看该作者
#define  RCC_CFGR2_PREDIV1SRC_PLL2          ((uint32_t)0x00010000)        /*!< PLL2 selected as PREDIV1 entry clock source */

选择PLL2CLK 作为PREDIV1的时钟源

使用特权

评论回复
19
sunmeat|  楼主 | 2014-9-25 15:58 | 只看该作者
#define  RCC_CFGR2_PREDIV1_DIV5             ((uint32_t)0x00000004)        /*!< PREDIV1 input clock divided by 5 */

PREDIV1对输入时钟五分频

使用特权

评论回复
20
sunmeat|  楼主 | 2014-9-25 16:03 | 只看该作者

    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
这段代码是基于外部时钟是25MHZ来配置的,讲诉的这么详细是为了说明PLL时钟是怎么来的。根据时钟树中的配置,PLL的时钟是这么算的

HSE/5*8/5=8MHZ

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

208

主题

2132

帖子

13

粉丝