你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F4时钟系统

[复制链接]
STMCU小助手 发布时间:2022-3-31 11:00
01. STM32F4时钟系统概述
) [+ e+ s' c& F0 f& h4 W时钟系统是 CPU 的脉搏,就像人的心跳一样。所以时钟系统的重要性就不言而喻了。 STM32F4 的时钟系统比较复杂,不像简单的 51 单片机一个系统时钟就可以解决一切。于是有人要问,采用一个系统时钟不是很简单吗?为什么 STM32 要有多个时钟源呢? 因为首先 STM32 本身非常复杂,外设非常的多,但是并不是所有外设都需要系统时钟这么高的频率,比如看门狗以及 RTC 只需要几十 k 的时钟即可。同一个电路,时钟越快功耗越大,同时抗电磁干扰能力也会越弱,所以对于较为复杂的 MCU 一般都是采取多时钟源的方法来解决这些问题。8 Y1 P9 w& @1 B& h- Z8 \

& i2 T) J% R, v/ `1 G. v" f4 ^  @0 [7 l02. STM32F4时钟系统图
' Q; A, U3 H4 W. j/ E9 a/ ?: B) ^5 Z" i3 c2 P1 u* I" j1 t' b
20200829145259439.png
  X1 o8 i+ W: I# }; K5 K! ]. r6 K8 C: S7 p# t( G
在 STM32F4 中,有 5 个最重要的时钟源,为 HSI、HSE、LSI、LSE、PLL。其中 PLL 实际是分为两个时钟源,分别为主 PLL 和专用 PLL。从时钟频率来分可以分为高速时钟源和低速时钟源,在这 5 个中 HSI,HSE 以及 PLL 是高速时钟,LSI 和 LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE 和LSE 是外部时钟源,其他的是内部时钟源。下面我们看看 STM32F4 的这 5 个时钟源,我们讲解顺序是按图中红圈标示的顺序:
! h8 I' i0 s% f5 I; h4 ~. |) m9 r8 D& @$ i- L
①、LSI 是低速内部时钟,RC 振荡器,频率为 32kHz 左右。供独立看门狗和自动唤醒单元使用。
8 ]( l: Y' W9 o$ h6 H②、LSE 是低速外部时钟,接频率为 32.768kHz 的石英晶体。这个主要是 RTC 的时钟源。
! h  y/ }3 w! h+ e" L2 P3 z③、HSE 是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为 4MHz~26MHz。我们的开发板接的是 8M 的晶振。HSE 也可以直接做为系统时钟或者 PLL 输入。3 g( `  F/ y3 L4 o
④、HSI 是高速内部时钟,RC 振荡器,频率为 16MHz。可以直接作为系统时钟或者用作 PLL输入。
$ @. B6 }9 c, _# Z3 e' N7 u( H: }9 v$ O# ^' y- U1 ?: r2 K( }8 ^
⑤、PLL 为锁相环倍频输出。STM32F4 有两个 PLL:9 s0 v+ A  J% }, p( T7 [& H: C
1) 主 PLL(PLL)由 HSE 或者 HSI 提供时钟信号,并具有两个不同的输出时钟。
. ~* C7 N4 b1 [5 M! ^第一个输出 PLLP 用于生成高速的系统时钟(最高 168MHz)+ |2 u! c* C+ Y
第二个输出 PLLQ 用于生成 USB OTG FS 的时钟(48MHz),随机数发生器的时钟和 SDIO时钟。
0 }3 j# F" T, c9 u0 }" c$ d5 O2)专用 PLL(PLLI2S)用于生成精确时钟,从而在 I2S 接口实现高品质音频性能。; c/ f+ A/ S* P! C) S& S3 F
" C; }% Y  ]* _; }' U: M
A. 这里是看门狗时钟输入。从图中可以看出,看门狗时钟源只能是低速的 LSI 时钟。
( z; E3 g) P9 X( p3 G5 y+ a* m. R4 J# P" B  D. z, x/ C; U
B. 这里是 RTC 时钟源,从图上可以看出,RTC 的时钟源可以选择 LSI,LSE,以及HSE 分频后的时钟,HSE 分频系数为 2~31。
+ h* x- M' G( l3 C! \$ p6 ^- {+ _. ?: Z& y6 W5 t% z
C. 这里是 STM32F4 输出时钟 MCO1 和 MCO2。MCO1 是向芯片的 PA8 引脚输出时钟。它有四个时钟来源分别为:HSI,LSE,HSE 和 PLL 时钟。MCO2 是向芯片的PC9 输出时钟,它同样有四个时钟来源分别为:HSE,PLL,SYSCLK 以及 PLLI2S时钟。MCO 输出时钟频率最大不超过 100MHz。5 R% S" H0 b9 K: {0 y& }+ ^7 c
& n5 y. {6 r. @" ~0 w6 q
D. 这里是系统时钟。从图 4.3.1 可以看出,SYSCLK 系统时钟来源有三个方面:HSI,HSE 和 PLL。在我们实际应用中,因为对时钟速度要求都比较高我们才会选用 STM32F4 这种级别的处理器,所以一般情况下,都是采用 PLL 作为 SYSCLK时钟源。根据前面的计算公式,大家就可以算出你的系统的 SYSCLK 是多少。
4 f) Z1 @  _% t2 V; s" S, c8 k6 H0 q- H+ L
E. 这里我们指的是以太网 PTP 时钟,AHB 时钟,APB2 高速时钟,APB1 低速时钟。这些时钟都是来源于 SYSCLK 系统时钟。其中以太网 PTP 时钟是使用系统时钟。AHB,APB2 和 APB1 时钟是经过 SYSCLK 时钟分频得来。这里大家记住,AHB最大时钟为168MHz, APB2高速时钟最大频率为84MHz,而APB1低速时钟最大频率为 42MHz。) d) j" J& |2 n. m5 H
% e# r! R& Q! s2 N3 y9 W1 j+ y
F. 这里是指 I2S 时钟源。从图 4.3.1 可以看出,I2S 的时钟源来源于 PLLI2S 或者映射到 I2S_CKIN 引脚的外部时钟。I2S 出于音质的考虑,对时钟精度要求很高。探索者 STM32F4 开发板使用的是内部 PLLI2SCLK。
1 \1 y. |7 B. Y9 t* U  N3 X( k( ~; `6 E
G. 这是 STM32F4 内部以太网 MAC 时钟的来源。对于 MII 接口来说,必须向外部PHY 芯片提供 25Mhz 的时钟,这个时钟,可以由 PHY 芯片外接晶振,或者使用STM32F4 的 MCO 输出来提供。然后,PHY 芯片再给 STM32F4 提供ETH_MII_TX_CLK 和 ETH_MII_RX_CLK 时钟。对于 RMII 接口来说,外部必须提供 50Mhz 的时钟驱动 PHY 和 STM32F4 的 ETH_RMII_REF_CLK,这个 50Mhz时钟可以来自 PHY、有源晶振或者 STM32F4 的 MCO。我们的开发板使用的是RMII 接 口 , 使 用 PHY 芯 片 提 供 50Mhz 时 钟 驱 动 STM32F4 的ETH_RMII_REF_CLK。
" S2 I: U  Y6 m7 ~7 \, k- L2 h! \" j: X- s. ~0 [
H. 这里是指外部 PHY 提供的 USB OTG HS(60MHZ)时钟。
2 ]9 m+ ?0 }) L. ^0 n, j- w2 U0 a# v& ?- L0 O0 U
03. STM32F4时钟初始化配置, l: b$ C, a8 c! }8 Q+ m
STM32F4 时钟系统初始化是在 system_stm32f4xx.c 中的 SystemInit()函数中完成的。对于系统时钟关键寄存器设置主要是在 SystemInit 函数中调用 SetSysClock()函数来设置的。我们可以先看看 SystemInit ()函数体。) H* P) M* a$ E6 t) o5 x: R
3 i, {8 W5 H* c$ i
  1. /**# ]' P8 Y, |" z5 s& j
  2.   * @brief  Setup the microcontroller system
    8 y, J1 J( N# l: K5 h3 L/ S
  3.   *         Initialize the Embedded Flash Interface, the PLL and update the
    1 \# A1 `" a; k0 l0 ?% i/ q) Y
  4.   *         SystemFrequency variable.  j# O# V; {% W; t4 O6 [+ A0 @
  5.   * @param  None
    ( y1 `/ X$ i* Z0 |0 j
  6.   * @retval None% y9 U7 Q3 Q0 J
  7.   */% Y& n& [0 j: K! N6 P: q0 C
  8. void SystemInit(void)- r2 s( `% G( L: o
  9. {
    4 d4 B9 X# a4 e# b0 n3 N
  10.   /* FPU settings ------------------------------------------------------------*/0 @* @9 B9 i% x1 q
  11.   #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)5 g; s: v/ X1 |1 _0 K
  12.     SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
      F+ x6 @7 x& H  c0 e
  13.   #endif
    9 o- y  q6 D* z# F
  14.   /* Reset the RCC clock configuration to the default reset state ------------*/
    ) h& G7 D5 W/ @1 z; e3 |
  15.   /* Set HSION bit */
    8 r8 z5 R7 u: c, p1 l  R1 V
  16.   RCC->CR |= (uint32_t)0x00000001;
    ! d4 X% c0 C1 m- W$ u

  17. $ ^& H. K+ _  W0 i
  18.   /* Reset CFGR register */
    * b& f% x7 |' a& m2 x& J
  19.   RCC->CFGR = 0x00000000;
    ( X3 f- J* _. |8 E

  20. ! R4 [5 l3 @% l) t% y# Q
  21.   /* Reset HSEON, CSSON and PLLON bits */8 m8 p" b# V6 M- p: a  L" K! Q
  22.   RCC->CR &= (uint32_t)0xFEF6FFFF;
    4 O( ^0 b  w% H

  23. 9 g3 v' |! t1 \2 S  |
  24.   /* Reset PLLCFGR register */
    " X# {: \& A- ]2 x1 F0 ]5 A8 g% p
  25.   RCC->PLLCFGR = 0x24003010;
    2 D2 Y# u! R3 G; F: q; F) w

  26. 4 F( U  E- s+ _+ g6 P
  27.   /* Reset HSEBYP bit */$ v& u4 n3 Q# z
  28.   RCC->CR &= (uint32_t)0xFFFBFFFF;
    * _7 d% D! Q6 c9 S
  29. & i  {1 C" g5 J- P" g5 y
  30.   /* Disable all interrupts */) a: l; l; [% b2 |, E0 x* g
  31.   RCC->CIR = 0x00000000;
    ' S3 @9 d4 \; b( I, X0 q

  32. 1 K* d" o1 y# t( J( {
  33. #if defined(DATA_IN_ExtSRAM) || defined(DATA_IN_ExtSDRAM)$ p1 I+ k7 b& _9 M  [
  34.   SystemInit_ExtMemCtl(); & [) u2 s' K' k& a
  35. #endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */: Y5 `$ C0 P" O, X/ ?( c

  36. : j  H% S. g* `0 @- ]
  37.   /* Configure the System clock source, PLL Multiplier and Divider factors, . u1 V: f1 O% [7 j7 O# K
  38.      AHB/APBx prescalers and Flash settings ----------------------------------*/
    4 M% Q& B, J: b: |
  39.   SetSysClock();9 J: H6 T# P- l* c
  40. ( {: T0 Q, B+ }6 z2 v
  41.   /* Configure the Vector Table location add offset address ------------------*/
    ; G; a+ E7 W4 N. e# v. n" }, Z
  42. #ifdef VECT_TAB_SRAM
    1 q" y, T0 c1 b, s+ Y
  43.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
    8 d0 S  J8 d" A& v& \
  44. #else% _: P2 ]4 B; m& O5 ~' I5 J; J
  45.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */" z' r% K6 j# s9 C; D, `) m4 {1 |. R# N
  46. #endif
    % O4 {2 l  U: p: m) r
  47. }
    ; D! s0 }" \' P- Q/ y$ [2 m
复制代码
, a- n0 o; d/ w4 }! D
在设置完相关寄存器后,接下来 SystemInit 函数内部会调用 SetSysClock 函数。( N% C3 O: G- T# F/ R! ^: Z
" N, D% l1 ?2 \, q
  1. /**8 O# l& @# A: O
  2.   * @brief  Configures the System clock source, PLL Multiplier and Divider factors, 1 }, w" U  e: v4 f1 A% H7 q& m" w
  3.   *         AHB/APBx prescalers and Flash settings# U2 S' D' t# c$ j. K
  4.   * @Note   This function should be called only once the RCC clock configuration  
    , U! Q# _( @$ I
  5.   *         is reset to the default reset state (done in SystemInit() function).   
    ; v1 Q2 K" T* x: Q. m) U+ M
  6.   * @param  None+ g( r) k3 T  u, J
  7.   * @retval None
    8 e& [% `/ u1 y# t
  8.   */
    ) ?, W9 o$ T! Q  u7 X& t- ]4 v0 ~) a
  9. static void SetSysClock(void)
    : r7 w: c# l2 _6 N
  10. {, r9 ]! [- W& t0 N8 x, _; Q
  11. #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)|| defined(STM32F469_479xx)
    & j3 Y" F0 r2 a* G
  12. /******************************************************************************/
    6 Q1 K' ^/ z; L; @4 x
  13. /*            PLL (clocked by HSE) used as System clock source                */
    7 g+ m; C. b: \. B
  14. /******************************************************************************/
    4 z( \7 c' ^) `( z% _
  15.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;, I0 j/ b8 N" U1 W3 Z
  16. 8 x2 l8 R% w( m0 C0 k1 \, n' c+ Z
  17.   /* Enable HSE */ //HSE时钟使能3 W7 O9 v1 ^7 H4 L. d
  18.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);& n. P& H8 O* m; d- i( S) e! D/ J
  19.   //等待HSE时钟稳定
    , W0 J7 A' j! w
  20.   /* Wait till HSE is ready and if Time out is reached exit */8 Q* r+ a' N' {' F4 G
  21.   do
    3 ^+ q9 S: ]* Z: m7 t
  22.   {5 `0 U, Q0 M! Q8 y. Y9 j2 a) q" i
  23.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
    ) H. Q. f& o/ }2 n  c7 @
  24.     StartUpCounter++;
    1 i( i4 g( B1 r
  25.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));5 W. O. J/ J# Y

  26. 4 D: V  v6 e# I% M: @
  27.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
    5 m- C4 v7 y, \6 B
  28.   {
    : `8 C3 G! W- ?5 ^, z8 [
  29.     HSEStatus = (uint32_t)0x01;5 S5 S/ K# S( R- C7 E  d. U9 [
  30.   }- H8 D5 B. g  X3 h7 V4 `+ {/ R
  31.   else
    & ~* K, _, q; q! N, H
  32.   {% P7 M7 c* h! \. X4 i) m; j/ R7 q
  33.     HSEStatus = (uint32_t)0x00;# I/ o% B, [7 C9 t3 D- h1 \
  34.   }
    9 `. m) H. p1 f- O7 g: a/ j

  35. . _" |+ X9 y% }2 q6 t1 _  d: b
  36.   if (HSEStatus == (uint32_t)0x01)
    + I& t2 D( \0 b7 B( z. G" W
  37.   {
    1 C! _7 n4 s& u$ L( u" _6 N
  38.     /* Select regulator voltage output Scale 1 mode */
    / W' N7 a5 \+ D9 T
  39.     RCC->APB1ENR |= RCC_APB1ENR_PWREN;* l2 t* Q( E. f- y: F$ Z
  40.     PWR->CR |= PWR_CR_VOS;
    0 d1 o8 }4 Y0 C  @/ K
  41.         //AHB不分频5 d1 Y, x. i4 s7 @0 I6 `7 J2 r  ?
  42.     /* HCLK = SYSCLK / 1*/! `5 X: t4 _- X6 S0 I0 a$ h4 d
  43.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    ; i7 Z5 W; s; @2 z! K" Q; |5 H$ [; t" W

  44. 5 ^2 a) i/ A' W  o) K* I
  45. #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) ||  defined(STM32F412xG) || defined(STM32F446xx) || defined(STM32F469_479xx)   
    3 y3 K; A; w2 B* T( `
  46.     /* PCLK2 = HCLK / 2*/ //高速APB二分频+ M: [- D' U; e
  47.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
    ; \: w; ?$ ~9 w; P* Q
  48. 1 W0 N4 ~1 A1 {7 o
  49.     /* PCLK1 = HCLK / 4*/ //低速APB4分频% E) ]  l; E* k7 G) A. M% ~8 L) f
  50.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;, J* L6 d& K8 c) s0 `! ?9 G; X2 s
  51. #endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx  || STM32F412xG || STM32F446xx || STM32F469_479xx */
    6 n4 x9 i- e+ j( A# C$ T

  52.   m9 n" A4 D% f7 L: h" b3 y
  53. #if defined(STM32F401xx) || defined(STM32F413_423xx)
    9 ^# j2 R; m" V$ l1 `$ w( m
  54.     /* PCLK2 = HCLK / 1*/  {" X1 c2 W( c3 \* t
  55.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;$ ~3 B5 K9 j; c7 Y% ^7 }* m

  56. 6 k/ \0 I  x) e; R
  57.     /* PCLK1 = HCLK / 2*/
    4 m+ {2 m# t( ~9 Q, `
  58.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    : `" u" g  A2 [
  59. #endif /* STM32F401xx || STM32F413_423xx */9 Y8 l: t* k, E" @
  60. % w5 q. j" d% k  \* i& Y" Z
  61. #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F469_479xx)   
    . }- N# f" b% K# p' n" w
  62.     /* Configure the main PLL */  `8 J0 T  v! H- ?( G/ u% N
  63.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    & L: ]9 _% s) U2 I/ w0 J. m: t
  64.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);& r+ q# D& }+ a( x! f
  65. #endif /* STM32F40_41xxx || STM32F401xx || STM32F427_437x || STM32F429_439xx || STM32F469_479xx */
    & [; O0 L1 y8 A1 O, |; M
  66. . |: Y# X! \5 T; C' n& ?
  67. #if  defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)8 g+ r6 k! Z  b' k3 j. j
  68.     /* Configure the main PLL */; u8 U3 b$ U. r) o  B6 |* C
  69.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |: H) e! b) e! B! ?
  70.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24) | (PLL_R << 28);* q; L6 L, N, ~
  71. #endif /* STM32F412xG || STM32F413_423xx || STM32F446xx */   
    0 z% {" P3 }' S& e
  72.   Y& K0 u6 S! m# l
  73.     /* Enable the main PLL */
    % H" i/ q+ J4 x
  74.     RCC->CR |= RCC_CR_PLLON;+ a$ @; l- R' X) d. K# [

  75. 0 S: V1 k1 n# Y/ X
  76.     /* Wait till the main PLL is ready */2 m3 o" `! l4 x0 y: x
  77.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    / K" G2 Z5 L7 f8 d; {  k7 {# A) T
  78.     {9 m3 ]( ?( h0 W
  79.     }& W: ~! v% A3 D# u& _+ _2 H# X

  80. % H7 k5 d/ O0 F4 k5 p
  81. #if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx) || defined(STM32F469_479xx)
    4 T8 H' P2 e9 O# o' ?1 u
  82.     /* Enable the Over-drive to extend the clock frequency to 180 Mhz */& e( R9 Q  {' L% Z
  83.     PWR->CR |= PWR_CR_ODEN;& Y( _* D! D& ?- h8 x0 o& E5 _$ b
  84.     while((PWR->CSR & PWR_CSR_ODRDY) == 0); P8 Z  O) `) k8 n0 d5 a
  85.     {
    + F2 h. F+ x' z; v. J4 l/ I
  86.     }
    5 {6 [( p' E# U  g! w/ x5 T
  87.     PWR->CR |= PWR_CR_ODSWEN;
    1 l9 }" @, U) F9 V# z
  88.     while((PWR->CSR & PWR_CSR_ODSWRDY) == 0): D& W) t) [0 k( i2 z
  89.     {5 e, c3 {1 b7 V6 U) |% `4 u
  90.     }      - R% d9 r. V/ f
  91.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    " P, t+ T( r2 @
  92.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
    5 v6 v* s( l2 Z- W
  93. #endif /* STM32F427_437x || STM32F429_439xx || STM32F446xx || STM32F469_479xx */
    , _+ b# D: [5 p
  94. , K7 H+ j2 Q4 }. @4 o  B0 _$ ?
  95. #if defined(STM32F40_41xxx)  || defined(STM32F412xG)  2 [" B5 [! r6 J: }1 g6 E/ j
  96.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */* [& u8 J9 o6 S3 [6 d: A
  97.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
    2 _$ A% K  G4 ~+ V
  98. #endif /* STM32F40_41xxx  || STM32F412xG */
    * U  ^/ \4 K+ J5 a5 G: K4 G
  99. - S8 c( Z$ f* u5 x/ K6 m
  100. #if defined(STM32F413_423xx)  7 U+ ^, Z3 ^! w1 i
  101.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    % i5 w0 K0 s# O; h
  102.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS;$ X5 n& Q$ V' Z( C" \( E
  103. #endif /* STM32F413_423xx */
    6 y& x( ^9 c  H$ d

  104. 6 n9 r9 L# r' N) Y3 N
  105. #if defined(STM32F401xx)
    % e6 Y+ C' {# f6 z6 k
  106.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */+ {! T% q0 x) K! }
  107.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;, c) j7 t  \+ }& w# _' a  I
  108. #endif /* STM32F401xx */- |6 `, P2 A0 t  b0 a/ _; }. k( }

  109. ' a, H6 d$ Z- j" B8 ~; A
  110.     /* Select the main PLL as system clock source */3 c! y' Q: ~3 Y* V7 N
  111.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));+ N! }# L$ O2 X; N4 z! _
  112.     RCC->CFGR |= RCC_CFGR_SW_PLL;; }# N8 x6 k) a5 s2 A- M3 ?

  113. ' C  V9 t. ^6 L) P4 S" _
  114.     /* Wait till the main PLL is used as system clock source */
    3 U+ ^  ?- U8 c6 C' s
  115.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    7 P' F0 _0 s9 [" J+ G/ K$ M
  116.     {
    + r% @0 h8 z# z% B# N5 {$ @
  117.     }
      \- Z2 c. y2 e1 Z+ n5 d
  118.   }
    9 O# _% f+ q+ I) @8 f6 L; G
  119.   else
    7 @' _9 W" S# v4 }
  120.   { /* If HSE fails to start-up, the application will have wrong clock6 f8 d2 {9 k" A
  121.          configuration. User can add here some code to deal with this error */
    + V- N5 J3 ^: ^% c! l
  122.   }
    - ^& ]: W" {: \
  123. #elif defined(STM32F410xx) || defined(STM32F411xE)5 W' ~; a' s8 ?5 o( ?% {/ H& j
  124. #if defined(USE_HSE_BYPASS)
    ; Y! l5 E. a2 y  v+ C6 O# n4 v
  125. /******************************************************************************/
    ( t. c( j" {) z0 c+ \" N2 I
  126. /*            PLL (clocked by HSE) used as System clock source                */1 t7 ~% o# ]" d: j; ^$ A
  127. /******************************************************************************/7 C1 F6 X, h# ^! D# w) S
  128.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    8 a# u/ z1 D  X: W* l# u
  129. 1 _, \8 B" q3 ?7 F; H
  130.   /* Enable HSE and HSE BYPASS */. b! Y* e- x9 [
  131.   RCC->CR |= ((uint32_t)RCC_CR_HSEON | RCC_CR_HSEBYP);8 h! \: d8 K5 L# P: A( A& k
  132. 5 F! {4 y  I& w8 q
  133.   /* Wait till HSE is ready and if Time out is reached exit */: z5 v4 f* W8 M; G( F3 X6 _) g3 `4 l
  134.   do
    7 Q' S  V5 z; C1 k, g/ |7 Y
  135.   {
    2 i: F, I% B6 I4 Y8 h
  136.     HSEStatus = RCC->CR & RCC_CR_HSERDY;6 n2 s) `6 L# a! h6 _% e* L
  137.     StartUpCounter++;
    1 R+ f/ c( |4 E/ t$ D4 T: I% A5 m
  138.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));: S" b" o; b8 [- K2 T9 j
  139. 3 Y& t: M" D- }/ s. R" f- Y
  140.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)' x  G" A' t  _5 x- L! w/ N) |
  141.   {
    2 Z% Q$ n5 E0 _% C* Y
  142.     HSEStatus = (uint32_t)0x01;% ]! F5 ~% m* V+ [. w
  143.   }3 |- U( p! k  L
  144.   else8 Y9 L! |3 k' A# D7 U' l
  145.   {& [, i- O! p5 f  p9 F$ X/ q, S+ G
  146.     HSEStatus = (uint32_t)0x00;
    ! e! t  ^6 @( a& I: p* z3 C
  147.   }
    - E( G( Y) I; L% N: K: x: a
  148. $ f( J* h) f, A* {4 W: C
  149.   if (HSEStatus == (uint32_t)0x01)
    $ X; o! k- z" n( }( I# q/ `* p
  150.   {& v6 q1 [% M* [/ U' m* R9 T6 v7 Z
  151.     /* Select regulator voltage output Scale 1 mode */6 B/ G# H* e+ T0 R& H
  152.     RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    ! `3 c- A/ [1 `7 g3 {2 {3 B
  153.     PWR->CR |= PWR_CR_VOS;
    ' @8 J4 B$ V0 r* b  E4 A$ j, K
  154. * \* v& P7 s+ r  M# x8 k8 V2 n+ M
  155.     /* HCLK = SYSCLK / 1*/7 T. ]: A0 ~+ a9 ^6 A! l
  156.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;" t# d! h7 K% k+ ^
  157. * \: s! q, ^/ s7 u
  158.     /* PCLK2 = HCLK / 2*/
    7 V  }1 j$ F$ ?$ D  q
  159.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;% x% {9 e9 B, y' Z
  160. & ^7 x$ L- D8 b$ F# T/ z+ N
  161.     /* PCLK1 = HCLK / 4*/
    4 c: y# m6 n+ K6 f% ~
  162.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;8 p) u2 Y0 e; }; S, s3 Z

  163. , v, Q2 \, E9 M$ \6 I' m
  164.     /* Configure the main PLL */: q. O: D  N& s2 ~! n
  165.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    ( M+ @) K( w8 ]6 a
  166.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
    - h6 W7 R" `/ ?5 h! ^

  167. 5 A' z  P5 y' T6 ?9 F$ Z
  168.     /* Enable the main PLL */# N" s1 t5 g# l+ t! D
  169.     RCC->CR |= RCC_CR_PLLON;
    ) ^) e' b# Y2 a' T/ V6 p1 ?/ A. T

  170. * V3 D; T. J4 `% h2 T) y
  171.     /* Wait till the main PLL is ready */* w3 l. W/ I) b( O$ {6 s  Y5 R
  172.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    / b6 p/ q7 H% C- h1 ~7 }; \# _
  173.     {
    * u/ l# N, w3 c3 G: ^
  174.     }9 u/ T  Q% t/ s( q$ C+ m

  175. / d6 |. V$ K* V: I" f
  176.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */$ w# O3 @) C5 h% k# k% l6 k
  177.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
    2 x3 f9 k6 X+ y, X; Z" ~! r) y

  178. 6 w( @5 q) e/ Z& l/ l6 [
  179.     /* Select the main PLL as system clock source */" K. D( L6 A4 y: R( t# G' A
  180.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    0 O; j1 s# w2 ]) U6 R' Z! Z
  181.     RCC->CFGR |= RCC_CFGR_SW_PLL;
    $ b) B; i2 J* ?% Y
  182. % j: G( `; C  \- `
  183.     /* Wait till the main PLL is used as system clock source */
    9 s( ]  y( j6 V5 ]; H3 y* [* Z
  184.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    - V$ x# t7 k4 d) E- I4 @6 [. |; {
  185.     {
    ; Z( s3 U5 s& e, m4 G6 j0 x
  186.     }
    0 F1 J  H, P; ~% @; o4 R- {! X8 P5 e
  187.   }) I/ e1 Z( F: N# d! S0 a% V9 e* H
  188.   else
    ; I! n. _/ H. T8 W  P2 S2 Z$ K" K, y# x
  189.   { /* If HSE fails to start-up, the application will have wrong clock
    - V5 p' U& f& U. l% q
  190.          configuration. User can add here some code to deal with this error */
    , M6 z4 r" x3 C( b0 w7 Z* P% X
  191.   }
    0 Z. t% n1 ?4 y$ S4 t: m; [
  192. #else /* HSI will be used as PLL clock source */# E" u5 o  ]( v
  193.   /* Select regulator voltage output Scale 1 mode */$ n# z, {: |: `
  194.   RCC->APB1ENR |= RCC_APB1ENR_PWREN;9 T. A- o) K' h7 l1 m' U
  195.   PWR->CR |= PWR_CR_VOS;
    / x3 `* I, l* Y7 m
  196. + e9 C2 Z4 |* V6 V1 X
  197.   /* HCLK = SYSCLK / 1*/! b2 g; t0 o6 U/ g. Y% N
  198.   RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    * X1 y  x# u2 A3 o: @

  199. ' G; F! w2 a, g5 b. d
  200.   /* PCLK2 = HCLK / 2*/
    9 N+ K# w  P7 \3 R
  201.   RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;) }* S: h+ p% O5 q
  202. 5 S/ [2 ]9 g0 L! r
  203.   /* PCLK1 = HCLK / 4*/& m" u0 s# W1 ^* H+ w4 e! z
  204.   RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;/ g8 I- H1 z, |+ X& D
  205. ( ~" Z) E* O8 ]+ w* P7 f
  206.   /* Configure the main PLL */! L$ `5 |: \/ d/ r
  207.   RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (PLL_Q << 24);
    $ f6 [' ^0 i. J7 `; |, p

  208. 9 r+ ]  \9 ]) F- S
  209.   /* Enable the main PLL */
    " X& n" w. U2 P/ C. o& m8 L
  210.   RCC->CR |= RCC_CR_PLLON;; P- A* ?# o1 Q
  211. ' U$ Y' N" L4 Y" G& |. a1 q
  212.   /* Wait till the main PLL is ready */) r& g* V: \& `4 H
  213.   while((RCC->CR & RCC_CR_PLLRDY) == 0)# H  V+ N- S9 D6 d
  214.   {
      W' T5 B/ B2 d" A4 m7 S
  215.   }+ L9 ~/ f7 h1 `
  216. 9 T7 ]0 l0 H  N: q; n" h
  217.   /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    , J/ x/ T0 M9 e2 ?2 `3 c; L
  218.   FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
    2 ]  [/ d1 g' {6 p  Z, c

  219. $ P  [. X! b& E
  220.   /* Select the main PLL as system clock source */
    0 S7 e: ^& F4 I+ `
  221.   RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    ) S: r* [: C; g' m
  222.   RCC->CFGR |= RCC_CFGR_SW_PLL;; ~1 f1 ?! i9 m+ \& k! q. V! w) D
  223. # c  Y! i) m4 M. e9 X* S9 x
  224.   /* Wait till the main PLL is used as system clock source */1 B( R, D+ m# ^1 F
  225.   while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);' I4 Z  B) I! b
  226.   {
    $ _; b& B4 B" R: x& b' c
  227.   }
    , g0 J6 w2 A& b
  228. #endif /* USE_HSE_BYPASS */  
    % X1 S6 {# E, I! ~/ W: T! x
  229. #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F469_479xx */  
    / k* N! L$ \' U, V" H1 a% R
  230. }
复制代码
. m$ p0 g& {9 \% h! i8 W' t  l
先使能外部时钟 HSE,等待 HSE 稳定之后,配置AHB,APB1,APB2 时钟相关的分频因子,也就是相关外设的时钟。等待这些都配置完成之后,打开主 PLL 时钟,然后设置主 PLL 作为系统时钟 SYSCLK 时钟源。如果 HSE 不能达到就绪状态(比如外部晶振不能稳定或者没有外部晶振),那么依然会是 HSI 作为系统时钟。9 z' K$ T5 b$ d3 Q; y5 s. S

+ ~/ F) i4 a0 ^8 A) @在这里要特别提出来,在设置主 PLL 时钟的时候,会要设置一系列的分频系数和倍频系数参数。大家可以从 SetSysClock 函数的这行代码看出:
3 u! \( r: l2 p2 F! I% y
+ X5 c( z% @4 E" A: u
  1.     /* Configure the main PLL */$ Q. ^2 e. _9 C' U5 _: t8 N8 R7 z
  2.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    % l; y" D# U2 k2 V$ ^3 v
  3.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
复制代码
) X- O% Q4 [3 a$ d8 N
这些参数是通过宏定义标识符的值来设置的。默认的配置在 System_stm32f4xx.c 文件开头的地方配置。对于我们开发板,我们的设置参数值如下:
- a, t% b+ E9 D7 X/ K0 J
; [# r+ N2 g5 ~3 o* [
  1. #define PLL_M 8
    ) A6 V; h% `8 \1 w5 b
  2. #define PLL_Q 7+ }: ?5 \9 A0 B: u
  3. #define PLL_N 336
    / M* H3 N! c3 c  n0 _2 f5 Z9 k' E3 _9 _
  4. #define PLL_P 2
    9 p4 ~8 {% Z: |. Q" X. y" \: q; @
复制代码

! \8 t- I" L3 u; O这里还有个特别需要注意的地方,就是我们还要同步修改 stm32f4xx.h 中宏定义标识符HSE_VALUE 的值为我们的外部时钟:7 C2 P; q; W6 |% W2 f- o
5 N7 ^" \/ y8 D" C3 E; ?) K4 @
  1. #if !defined (HSE_VALUE): D: E3 p1 f) S- }4 T/ e
  2. #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */% n# o, O1 c# G4 _" V
  3. #endif /* HSE_VALUE */
复制代码

$ k+ u5 d5 e+ T. }% A这里默认固件库配置的是 25000000,我们外部时钟为 8MHz,所以我们根据我们硬件情况修改为 8000000 即可。$ a/ A1 S# |9 x% s8 k: `& n

5 c7 H' Y% f0 l04. 时钟配置总结
8 B% P5 L5 p* j: N9 K$ e  e$ h
最后我们总结一下 SystemInit()函数中设置的系统时钟大小:
  M" Q& D( S- I( r1 e# C/ e8 \0 b
SYSCLK(系统时钟) =168MHz) n4 r& W8 y# }+ x" R/ f$ j
9 P5 B+ m. Q  V/ c8 z8 `, F* C
AHB 总线时钟(HCLK=SYSCLK) =168MHz' ~5 U& z% I7 u" X" h# X* p3 I
6 ~  J, \0 \7 C8 c
APB1 总线时钟(PCLK1=SYSCLK/4) =42MHz6 T( o% ?8 M: ]; [( b; Q6 s

" G8 l2 H  K9 m0 vAPB2 总线时钟(PCLK2=SYSCLK/2) =84MHz& u  J0 i# _8 S% h) e2 X
1 ^- m# L# y* a) i; o: P
PLL 主时钟 =168MHz
3 G, w$ U/ D3 \( f+ x9 g( s  b3 M" M+ X0 N9 a

' D, e; p3 x* g
: k' D9 F% J- ?, y; R' x5 k
赞 收藏 评论0 发布时间:2022-3-31 11:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版