STM32F429 Discovery开发板,集成了ST_LINK2和2.4寸的TFT LCD彩屏,可以为学习开发带来不少的方便。此外,还有64Mbits SDRAM,ST MEMS,LED,按键及USB OTG micro-B接口。本文将介绍STM32F4的系统时钟编程。
系统时钟,单片机的时钟好比人们的心脏的脉波,没有脉了人就完了。同样,单片机没有系统时钟了基本上就是废片一块。
STM32F429的时钟必须搞明白才能编程为我所用。
以下是系统时鈡的框图:
看上去很复杂。现在一点一点的剖释。SYSCLK有三种不同的时钟可以驱动
还有两个辅助的时钟源,分别是
- 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): PLLQ, USB 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->LLCFGR = 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->LLCFGR = 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); { } }
|