回答

收藏

STM32F4步步为营二:系统时钟

#其他 #其他 3160 人阅读 | 0 人回复 | 2014-07-18

STM32F429 Discovery开发板,集成了ST_LINK2和2.4寸的TFT  LCD彩屏,可以为学习开发带来不少的方便。此外,还有64Mbits SDRAM,ST MEMS,LED,按键及USB OTG  micro-B接口。本文将介绍STM32F4的系统时钟编程。
        系统时钟,单片机的时钟好比人们的心脏的脉波,没有脉了人就完了。同样,单片机没有系统时钟了基本上就是废片一块。
        STM32F429的时钟必须搞明白才能编程为我所用。
        以下是系统时鈡的框图:
              
        看上去很复杂。现在一点一点的剖释。SYSCLK有三种不同的时钟可以驱动
           
  • HIS内部高速时钟       
  • HSE外部高速时钟       
  • PLL
        还有两个辅助的时钟源,分别是
           
  • LSI内部RC低速时钟32KHz主要驱动内部看门狗和RTC电路       
  • LSE外部RC低速时钟32.768主要用于驱动RTC时钟
        大部分外设都在SYSCLK下工作。除了以下一些时钟:
           
  • ? USB OTG FS 时钟 (48 MHz)、random analog generator (RNG)时钟(<= 48 MHz)和SDIO时钟 (<= 48 MHz)来自PLL的输出PLL48CLK       
  • I2S clock,可以从PLL(PLLI2S)或者一个映射到I2S_CKIN管脚的外部时钟得到。       
  • SAI1 clock,可以从PLL (PLLSAI or PLLI2S)或从外部时钟映射管脚I2S_CKIN得到。PLLSAI 能被用作SAI1设备的时钟,在这种情况下PLLI2S可以被用作另外的音频(49.152 MHz or11.2896 MHz),并且两个频率同时发生。       
  • LTDC clock,LTDC时钟从PLL (PLLSAI)产生。       
  • The USB OTG HS (60 MHz) 时钟是由外部PHY提供的。       
  • The Ethernet MAC clocks (TX, RX and RMII) 时钟是由外部PHY提供的。当Ethernet被用的时候AHB时钟必须达到25MHZ
        要想平时顺利操作时钟,就必须了解几个寄存器:

        其中一个是RCC PLL配置寄存器RCC_PLLCFGR(RCC PLL configuration register),其控制着频率的生成。

           
  • ? f(VCO clock) = f(PLL clock input) × (PLLN / PLLM)       
  • ? f(PLL general clock output) = f(VCO clock) / PLLP       
  • ? f(USB OTG FS, SDIO, RNG clock output) = f(VCO clock) / PLLQ
        大家看到上边的公式,也许会发愁,这是怎么回事,其实只要细细研究下就会非常明白:

        RCC_PLLCFGR寄存器如下:

           
  • Bits(27:24): PLLQUSB OTG FS、SDIO 和隨机数字发生器的分频值,在PLL无效时才能改写。USB OTG FS需要48 MHz 时钟才能正确工作. SDIO和隨机数字发生器需要比48MHz小或者等于48MHz时才能工作。Bits(27:24)值为2到15。       
  • Bit 22:PLLSRC,主PLL(PLL) 和音频PLL (PLLI2S) 的时钟源。当PLL和PLLI2S没使能的情况下可改写,0为内部高速时钟被选择;1为外部晶振时钟被选择。       
  • Bits(17:16):PLLP,主PLL (PLL) 分频为系统时钟的分频值。当PLL没有使能时改写。注意该值不应超过180MHz,PLL 输出时钟 = VCO 频率 / PLLP (PLLP = 2, 4, 6, or 8)。       
  • Bits(14:6):PLLN,主PLL (PLL)乘积因子,VCO的乘积因子,可以软件清除和设置。这个只有两种选项192MHzt和432MHz,输入频率最小为1MHzVCO output frequency = VCO input frequency × PLLN with 192 MHz或432MHz。       
  • Bits(5:0):PLLM,主 PLL (PLL) 和音频PLL (PLLI2S) 输入时钟的分频因子,这个是保证在输入VCO的频率在1到2MHz之间,它的值为2到63。VCO input frequency = PLL input clock frequency / PLLM with (2-63)
        另一个寄存器是:RCC时钟控制 寄存器RCC_CR(RCC clock control register )
           
  • Bit29:PLLSAIRDY,PLLSAI 时钟锁定标志       
  • Bit28:PLLISAION,PLLSAI有效       
  • Bit27:PLLI2SRDY,PLLI2S准备好标志       
  • Bit26:PLLI2SON,PLLI2S 有效       
  • Bit25:PLLRDY,主PLL (PLL) clock 准备好标志       
  • Bit24:PLLON,主PLL (PLL)使能
        还有一个寄存器是:RCC时钟配置寄存器RCC_CFGR(RCC clock configuration register)

        里边有APB1,APB2,AHB 各个总线的分频因子。

        由此,我们不难读懂如下函数:

        static void SetSysClock(void)    {    /******************************************************************************    * PLL (clocked by HSE) used as System clock source *    ******************************************************************************/    __IO uint32_t StartUpCounter = 0, HSEStatus = 0;    #ifdef PLL_SOURCE_HSI //如果时钟源定义为内部低速时钟           RCC-&gtLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |(RCC_PLLCFGR_PLLSRC_HSI) | (PLL_Q << 24);    #else           RCC->CR |= ((uint32_t)RCC_CR_HSEON); //定义时钟源为内部高速时钟    #ifdef PLL_SOURCE_HSE_BYPASS //如果定义外部时钟为 BYPASS模式           RCC->CR |= ((uint32_t)RCC_CR_HSEBYP);    #endif         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)      {        //如果外部时钟稳定就开始配置主时钟        RCC-&gtLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |                      (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);      }        else      {        //否则就表示外部时钟出了问题,用户可以自己加些代码处理这个问题      }    #endif        //设置系统频率为180MHZ    RCC->APB1ENR |= RCC_APB1ENR_PWREN;        PWR->CR |= PWR_CR_VOS;    //设置HCLK频率    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;        //设置PCLK2 = HCLK / 2        RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;         //设置PCLK1 = HCLK / 4        RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;        //使能PLL        RCC->CR |= RCC_CR_PLLON;       //等待PLL准备好        while((RCC->CR & RCC_CR_PLLRDY) == 0)        {        }        //设置扩展时钟为180MHZ        PWR->CR |= PWR_CR_ODEN;        while((PWR->CSR & PWR_CSR_ODRDY) == 0)        {        }        PWR->CR |= PWR_CR_ODSWEN;        while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)        {        }         //设置FLASH,预取指令缓冲和数据缓冲和等待状态         FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;        //选取主PLL时钟为系统时钟源         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));        RCC->CFGR |= RCC_CFGR_SW_PLL;    //等待时钟稳定        while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);        {        }    }       
关注下面的标签,发现更多相似文章
分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条