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

【经验分享】STM32F4时钟系统

[复制链接]
STMCU小助手 发布时间:2022-6-10 20:08
01. STM32F4时钟系统概述
( s" X4 @6 ]. I  g! f0 j; q: U4 j时钟系统是 CPU 的脉搏,就像人的心跳一样。所以时钟系统的重要性就不言而喻了。 STM32F4 的时钟系统比较复杂,不像简单的 51 单片机一个系统时钟就可以解决一切。于是有人要问,采用一个系统时钟不是很简单吗?为什么 STM32 要有多个时钟源呢? 因为首先 STM32 本身非常复杂,外设非常的多,但是并不是所有外设都需要系统时钟这么高的频率,比如看门狗以及 RTC 只需要几十 k 的时钟即可。同一个电路,时钟越快功耗越大,同时抗电磁干扰能力也会越弱,所以对于较为复杂的 MCU 一般都是采取多时钟源的方法来解决这些问题。7 D, F2 \. }1 M. [/ y) e9 v- d
) i9 k$ n# u; o3 K0 I* W6 Z
02. STM32F4时钟系统图
, ~9 p" y/ ^4 x2 D: u7 y, ]0 f" E) _! Y) Q# W( d
54RK2N3M}XS88ZREGCB7RB6.png
% i% S3 x/ |2 q/ O  [3 @* F! E# {4 e9 M4 z
在 STM32F4 中,有 5 个最重要的时钟源,为 HSI、HSE、LSI、LSE、PLL。其中 PLL 实际是分为两个时钟源,分别为主 PLL 和专用 PLL。从时钟频率来分可以分为高速时钟源和低速时钟源,在这 5 个中 HSI,HSE 以及 PLL 是高速时钟,LSI 和 LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE 和LSE 是外部时钟源,其他的是内部时钟源。下面我们看看 STM32F4 的这 5 个时钟源,我们讲解顺序是按图中红圈标示的顺序:* m5 F/ v% ]: Q. g+ f% r- D4 z
9 P5 A3 X" O* j. E/ F
①、LSI 是低速内部时钟,RC 振荡器,频率为 32kHz 左右。供独立看门狗和自动唤醒单元使用。2 C+ W, S- C  E6 j
②、LSE 是低速外部时钟,接频率为 32.768kHz 的石英晶体。这个主要是 RTC 的时钟源。; D0 \: g0 i2 f, c
③、HSE 是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为 4MHz~26MHz。我们的开发板接的是 8M 的晶振。HSE 也可以直接做为系统时钟或者 PLL 输入。, l: U0 j8 Z% z
④、HSI 是高速内部时钟,RC 振荡器,频率为 16MHz。可以直接作为系统时钟或者用作 PLL输入。
& p( m9 h+ k. b6 M( s- O, Z- k+ R' }1 g6 V% }
⑤、PLL 为锁相环倍频输出。STM32F4 有两个 PLL:) R9 O$ \, j# m3 \& c# \6 y
1) 主 PLL(PLL)由 HSE 或者 HSI 提供时钟信号,并具有两个不同的输出时钟。, z8 r* O0 o9 |  v! C% n
第一个输出 PLLP 用于生成高速的系统时钟(最高 168MHz)* e7 Q" O' d3 d+ R
第二个输出 PLLQ 用于生成 USB OTG FS 的时钟(48MHz),随机数发生器的时钟和 SDIO时钟。! B) F4 P; t' P/ B  l7 `
2)专用 PLL(PLLI2S)用于生成精确时钟,从而在 I2S 接口实现高品质音频性能。
7 Q4 Q: r; [) u3 C; B! N: E) ^0 ]) c& W
A. 这里是看门狗时钟输入。从图中可以看出,看门狗时钟源只能是低速的 LSI 时钟。
( Q8 f1 Y9 P( u; e
+ ~  {' X8 u: Z; t! E# H, BB. 这里是 RTC 时钟源,从图上可以看出,RTC 的时钟源可以选择 LSI,LSE,以及HSE 分频后的时钟,HSE 分频系数为 2~31。
+ _5 k- h% u! N; d8 ?. T/ A; @+ @8 q
C. 这里是 STM32F4 输出时钟 MCO1 和 MCO2。MCO1 是向芯片的 PA8 引脚输出时钟。它有四个时钟来源分别为:HSI,LSE,HSE 和 PLL 时钟。MCO2 是向芯片的PC9 输出时钟,它同样有四个时钟来源分别为:HSE,PLL,SYSCLK 以及 PLLI2S时钟。MCO 输出时钟频率最大不超过 100MHz。
( g6 }* @2 |0 w4 n% i4 x, Y5 t' ?* S/ K5 |% C; E$ j( r% v. b. S
D. 这里是系统时钟。从图 4.3.1 可以看出,SYSCLK 系统时钟来源有三个方面:HSI,HSE 和 PLL。在我们实际应用中,因为对时钟速度要求都比较高我们才会选用 STM32F4 这种级别的处理器,所以一般情况下,都是采用 PLL 作为 SYSCLK时钟源。根据前面的计算公式,大家就可以算出你的系统的 SYSCLK 是多少。9 m' E" H' z8 Z
( P' l' U  H1 Z8 @, e
E. 这里我们指的是以太网 PTP 时钟,AHB 时钟,APB2 高速时钟,APB1 低速时钟。这些时钟都是来源于 SYSCLK 系统时钟。其中以太网 PTP 时钟是使用系统时钟。AHB,APB2 和 APB1 时钟是经过 SYSCLK 时钟分频得来。这里大家记住,AHB最大时钟为168MHz, APB2高速时钟最大频率为84MHz,而APB1低速时钟最大频率为 42MHz。
; E2 |+ z0 e7 D& H# n, y+ g& e7 y$ A) }$ }! ~6 j1 X+ C/ b0 h
F. 这里是指 I2S 时钟源。从图 4.3.1 可以看出,I2S 的时钟源来源于 PLLI2S 或者映射到 I2S_CKIN 引脚的外部时钟。I2S 出于音质的考虑,对时钟精度要求很高。探索者 STM32F4 开发板使用的是内部 PLLI2SCLK。/ c4 y- W7 [" N* y5 L6 |

' F* w& C. q; x' y  FG. 这是 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。" M" `/ W+ ?& q6 ^4 F1 X
9 o/ X' q0 b5 l+ o0 z0 i1 N$ j
H. 这里是指外部 PHY 提供的 USB OTG HS(60MHZ)时钟。
, I, Q( J2 L/ h" |8 C( A: t7 o
/ R+ m, c" b$ J9 h03. STM32F4时钟初始化配置0 S0 Q. R  e1 y2 _& B) D. ^8 I! M7 ^
STM32F4 时钟系统初始化是在 system_stm32f4xx.c 中的 SystemInit()函数中完成的。对于系统时钟关键寄存器设置主要是在 SystemInit 函数中调用 SetSysClock()函数来设置的。我们可以先看看 SystemInit ()函数体。
( f5 L3 F2 y# C. r. g; `2 k+ E
: x5 u4 `( ?2 }
  1. /**
    ) \! D5 \3 z' e
  2.   * @brief  Setup the microcontroller system
      S* X" U& E' l
  3.   *         Initialize the Embedded Flash Interface, the PLL and update the + ~. m& S1 \8 `
  4.   *         SystemFrequency variable.
    . \( X+ ]% C1 f
  5.   * @param  None
    : h# J+ g$ Q0 W2 ~% m; w- |, Y6 v
  6.   * @retval None. E6 b$ e2 H" J% ?% m% D
  7.   */8 p( d) D  N; d* p1 t, |& m1 y+ B
  8. void SystemInit(void)3 G$ c% x! y  Z: b: M: w7 A
  9. {
      C$ e4 [( F1 O/ m* J% t3 P6 S
  10.   /* FPU settings ------------------------------------------------------------*/
    % n  {& k( I8 ^9 O+ C
  11.   #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    3 C! c) S% J7 h* z& n3 I3 T4 l
  12.     SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */0 E' K1 ~9 M& l
  13.   #endif
    5 v" g- `# y' A) G2 V2 I1 k
  14.   /* Reset the RCC clock configuration to the default reset state ------------*/
    8 U' h* ]$ a) a
  15.   /* Set HSION bit *// S% j- f. ]* e
  16.   RCC->CR |= (uint32_t)0x00000001;
    + A+ r: g6 q" X5 }7 z' l; a
  17. ; ?9 I+ S6 T# ]0 x7 T! _
  18.   /* Reset CFGR register */* q* @# j; J# l& m7 ~1 y/ g
  19.   RCC->CFGR = 0x00000000;
    . ]1 Z: M, P/ H  r6 ~* c

  20. ! D9 Q% z% F# d* f; C/ Q
  21.   /* Reset HSEON, CSSON and PLLON bits */$ E/ P9 [% l1 I1 H# d
  22.   RCC->CR &= (uint32_t)0xFEF6FFFF;
    5 O7 Y7 ~3 ^2 t3 D% I) T
  23. . U0 @# d0 {  x7 p# d4 Q3 ^3 e
  24.   /* Reset PLLCFGR register */& ?  Z% Q& u! b- ^8 n
  25.   RCC->PLLCFGR = 0x24003010;
    ' l# ?1 a% G1 w& Y& @7 }

  26. 0 d8 C3 g* u9 S! C- V' T+ Q
  27.   /* Reset HSEBYP bit */, ^, f5 t& b1 c& T/ V( O1 C
  28.   RCC->CR &= (uint32_t)0xFFFBFFFF;8 z1 H8 Z$ L3 O' M9 q7 u
  29. 4 f2 W0 R; y& I1 K
  30.   /* Disable all interrupts */
    4 @, B0 H: Y, \# ~) V  y9 e
  31.   RCC->CIR = 0x00000000;4 B) t, [5 B; |3 R% q' [6 u
  32. 9 I7 W# v9 v6 G5 F5 t; I
  33. #if defined(DATA_IN_ExtSRAM) || defined(DATA_IN_ExtSDRAM)
    ; \7 W$ w. z% Y- @% `4 |
  34.   SystemInit_ExtMemCtl();
    # r: y7 _3 C4 ?% ?1 W8 y  W
  35. #endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
    6 u1 j2 w4 J  z9 B
  36. 5 |1 O1 ~$ A, ]& B9 R  @8 U7 u
  37.   /* Configure the System clock source, PLL Multiplier and Divider factors, 4 _6 K0 Q5 v4 k$ Z8 F
  38.      AHB/APBx prescalers and Flash settings ----------------------------------*/6 T, h, B- n3 Y" \9 V: w  u
  39.   SetSysClock();
    3 ?2 W) Q$ ?" l& v- A" i! k
  40. ! H% B$ n3 @2 P+ _3 {1 u0 q5 o: l8 c
  41.   /* Configure the Vector Table location add offset address ------------------*/# H+ K4 K% }& t& _4 N2 k( `
  42. #ifdef VECT_TAB_SRAM
    $ I/ N1 E$ D; f; [& Q
  43.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
    - e# K. U7 S" T8 w. y/ H
  44. #else
    1 t- h& Q; \1 `2 J8 w
  45.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
    ) D/ \' i& k  r. [% F' X5 X6 h
  46. #endif0 J0 w6 g7 j/ r1 T6 l6 s1 r
  47. }
复制代码

# X3 t% v8 D: n' c5 U. j1 h! t3 [在设置完相关寄存器后,接下来 SystemInit 函数内部会调用 SetSysClock 函数。
, h/ W9 j0 R, z7 B  `; z' N+ |/ b* Y9 m1 v5 D# w, P. w
  1. /**
    : o( S7 h' l% C* [
  2.   * @brief  Configures the System clock source, PLL Multiplier and Divider factors,
    3 T3 g% l' m2 Y+ S( L5 `
  3.   *         AHB/APBx prescalers and Flash settings
    . S3 v: n2 a* B& r) k) ]
  4.   * @Note   This function should be called only once the RCC clock configuration  " x4 ^5 I3 w  m( ]8 Z, S
  5.   *         is reset to the default reset state (done in SystemInit() function).   6 S0 n- u) [3 {& D2 ~
  6.   * @param  None6 d, p! W% g3 f" f& H% e8 b, d& h
  7.   * @retval None
    % A9 h- O% c, v% x/ r2 v
  8.   */
    + F  I' Q  Q2 n8 `
  9. static void SetSysClock(void)
    : _0 X) Z) f& ]2 n5 D& q1 P
  10. {
    ) J. j8 l' e$ K7 o  g' G
  11. #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)|| defined(STM32F469_479xx)
    4 D2 z2 O; Y( N! U1 |) P
  12. /******************************************************************************/
    9 k$ {% j5 Z; n: w
  13. /*            PLL (clocked by HSE) used as System clock source                */9 V; b  Z0 I3 E, t2 [+ D0 J
  14. /******************************************************************************/
    4 y. G5 b6 a- a
  15.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
      D4 N, W/ \$ A2 r9 H/ R8 M

  16. " h. ^7 j# p$ ^! |$ |6 B
  17.   /* Enable HSE */ //HSE时钟使能# Q( {' W( s4 o+ ^: d$ U
  18.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
    7 @% h  E3 V8 g5 k6 B$ C, N
  19.   //等待HSE时钟稳定
    - t5 l1 ]# W* ^; E
  20.   /* Wait till HSE is ready and if Time out is reached exit */: U! d( o5 J/ p. u+ h1 e
  21.   do
    , E; g8 L  S% S. U# X0 j
  22.   {1 U- N& Q7 w! h' u
  23.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
    6 J# A$ A. J6 y- f( L8 M# f! c
  24.     StartUpCounter++;
    3 w/ d3 `) X+ P# u6 B3 L7 T. X6 X
  25.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));6 I8 ^+ P( a) O$ b
  26. $ q& s4 S1 \, @7 Z. }
  27.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
    1 A6 v2 ^$ a0 w9 r1 Q# \' G# w' c3 l. |8 M
  28.   {& x7 l9 K# i$ ]
  29.     HSEStatus = (uint32_t)0x01;: }$ x6 R  O7 k4 S
  30.   }0 e& Z1 r' t- q8 w$ W( P9 i
  31.   else
    ) ?, u% L; x6 s- j; o) l. }
  32.   {
    8 U  h7 J: M9 B( s3 |5 G( o& n
  33.     HSEStatus = (uint32_t)0x00;" D# \. Q; v: ~$ t- q: ~
  34.   }
    . P6 m9 ?/ A0 l

  35. , Z2 k2 e  C/ i6 s4 t1 W
  36.   if (HSEStatus == (uint32_t)0x01)
    ( k" f% x/ \# f' X6 K, {8 S
  37.   {; S+ v4 j4 _1 x0 F) w2 `# s
  38.     /* Select regulator voltage output Scale 1 mode */
    1 @( V) E% C1 t* C- W0 x9 G
  39.     RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    ! W* I& T5 p, ]. `
  40.     PWR->CR |= PWR_CR_VOS;/ n& G/ N$ w* B! v4 P: Y5 \
  41.         //AHB不分频
    1 Z1 y' a  }9 n- L- |" k
  42.     /* HCLK = SYSCLK / 1*/  m& b" k* l; n! B5 ]% G7 V& z/ y  c
  43.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;6 _8 `8 B) t9 S: z9 F( ?, O3 o

  44. ( m6 ?) \4 l0 A
  45. #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) ||  defined(STM32F412xG) || defined(STM32F446xx) || defined(STM32F469_479xx)   
    , N% g3 i7 s( r- w* S7 e7 N
  46.     /* PCLK2 = HCLK / 2*/ //高速APB二分频
    2 N' l3 {/ Y/ `3 w6 O/ g
  47.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;* i) G  {% S1 i  B
  48. ' O4 r6 B1 m9 [& h' E1 G2 x
  49.     /* PCLK1 = HCLK / 4*/ //低速APB4分频
    * c1 A% f% W2 o+ X- J7 Z( g
  50.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
    - n% y( ]  y  H' f. F
  51. #endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx  || STM32F412xG || STM32F446xx || STM32F469_479xx */
    . I2 h( v$ f& U7 }/ L$ W
  52. 6 ~; e) K: j* r$ B; r, D4 @
  53. #if defined(STM32F401xx) || defined(STM32F413_423xx)
    " X1 F- C# Q% x' Y" y+ B% t
  54.     /* PCLK2 = HCLK / 1*/; d5 b# u5 y; K! u! j7 g+ |" S! G$ i. h
  55.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;& D' o: `- |/ p7 U9 R& {

  56. ; O; O' S2 C- H
  57.     /* PCLK1 = HCLK / 2*/3 ]) S+ |$ u. G7 K
  58.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    9 t; T5 }) i4 @, p' S
  59. #endif /* STM32F401xx || STM32F413_423xx */3 F5 F' S3 y+ ^
  60. ) V5 D( |8 D0 v; P& ?2 Y
  61. #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F469_479xx)   
    . V9 K- P5 g5 g' {
  62.     /* Configure the main PLL */% ]; u- ~: o- [( ^: Z% z
  63.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |6 f) F8 Q: ~3 y) p1 y4 R
  64.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);4 D8 s& X' }) y9 o" E+ w* h$ A
  65. #endif /* STM32F40_41xxx || STM32F401xx || STM32F427_437x || STM32F429_439xx || STM32F469_479xx */
    # B% ?2 w) z- v0 J
  66. " N( U8 x! V% N) X
  67. #if  defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)& f0 r+ D1 b* J& o4 X9 K# g
  68.     /* Configure the main PLL */1 k5 @8 m! L& F  }
  69.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |! l4 i2 F* q  |
  70.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24) | (PLL_R << 28);' v. s0 i, r* D' w& U. }
  71. #endif /* STM32F412xG || STM32F413_423xx || STM32F446xx */    5 ?# G' C0 v" I7 K

  72. 1 S( n3 J3 L( @+ Z& a) w
  73.     /* Enable the main PLL */& [  D" I* w9 F( R; m
  74.     RCC->CR |= RCC_CR_PLLON;
    9 ~$ o3 v8 ]8 Y. H7 @. z+ h* @

  75. 9 e) T1 K3 i7 T! U/ b; w5 `
  76.     /* Wait till the main PLL is ready */  K+ ^5 Y) Q, o8 {% t; {0 H
  77.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    " M/ }' G: r# g% c" H2 Y; N, N, w
  78.     {2 f: o! L3 O5 U; |' C- E: o1 Y! Q& H! m( V
  79.     }
    # r( m8 @# I6 f. I$ g$ V

  80. 1 D7 k1 h7 g3 r
  81. #if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx) || defined(STM32F469_479xx)/ V' w# W0 w5 B* r9 \. m: \
  82.     /* Enable the Over-drive to extend the clock frequency to 180 Mhz */6 D5 f! o+ ~0 w" H# F/ @
  83.     PWR->CR |= PWR_CR_ODEN;
    - r' ?- ?9 W4 f7 p( C9 N" E' V
  84.     while((PWR->CSR & PWR_CSR_ODRDY) == 0)
    " ^4 q) x$ Z( q6 P1 D' \0 n6 }
  85.     {
    4 s! O3 W# J! G% [7 ]" F3 e6 ^
  86.     }
    + k' C' C/ ~6 [
  87.     PWR->CR |= PWR_CR_ODSWEN;: ]. I. Y4 v3 c# B1 M( ~& s
  88.     while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)  ^( \# U/ y9 c, ^) D
  89.     {
    1 T: ]0 ]; P4 K! S- _# Q0 ^0 e
  90.     }      
    ! \, u2 b7 ~2 @6 X8 @
  91.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    $ l3 D$ \3 {2 Z3 A* E- V% I
  92.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;; q# ^6 G, i# m0 e; E
  93. #endif /* STM32F427_437x || STM32F429_439xx || STM32F446xx || STM32F469_479xx */+ V9 e( ?; S" H. o

  94. ( A) x* S4 h6 a/ J
  95. #if defined(STM32F40_41xxx)  || defined(STM32F412xG)  4 K, Q4 C8 ]) `9 w( E6 J1 J5 }# V0 f
  96.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    % e' y3 x4 k6 T# E' ?7 c* q) @0 S
  97.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
    7 ^" n2 f% o& y
  98. #endif /* STM32F40_41xxx  || STM32F412xG */
    & K0 v# @  x: h/ T/ B# S
  99. / h7 |! d5 J  k( g& a- `
  100. #if defined(STM32F413_423xx)  ( t: ?5 g4 i5 U* g3 G
  101.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */+ G' ^- d5 l9 J
  102.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS;6 @5 B+ W( N' h6 O) l
  103. #endif /* STM32F413_423xx */
    % q& t* V1 P7 K- r4 |# o% ~' _

  104. ' e$ {, ]7 Y0 J0 P/ i
  105. #if defined(STM32F401xx)
    . s7 b3 C% O9 L1 t, _
  106.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    5 w, g5 V7 P" z
  107.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;5 q2 R+ A9 t) u/ ~) U
  108. #endif /* STM32F401xx */3 E4 U# A1 x2 s, h
  109. : j6 ?4 r  a6 X0 K" O0 `
  110.     /* Select the main PLL as system clock source */1 |9 f5 ?# ?  i6 a$ ]
  111.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));8 C% C6 C7 f& o8 I: q
  112.     RCC->CFGR |= RCC_CFGR_SW_PLL;
    - f7 v3 Z% l  \3 t* `5 O, a

  113. 5 X4 l. p% d( |2 D1 E3 c: \
  114.     /* Wait till the main PLL is used as system clock source */% d' `7 h2 b/ m
  115.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);8 C- Q" T, k' F) s5 m5 D
  116.     {* ]) o( I- C' x9 ]
  117.     }
    2 A3 \2 Z5 y) P5 N* K# u8 t
  118.   }
    6 w3 I$ ?& ^* I( k4 U
  119.   else
    + u( q6 ]' j3 ?2 I* u+ s# L1 O
  120.   { /* If HSE fails to start-up, the application will have wrong clock: `6 l1 E( e; A. O% T5 Y7 B' o
  121.          configuration. User can add here some code to deal with this error */: |# L$ \/ n: }2 f, U/ g
  122.   }, S( {& [# D( r4 d+ U0 M
  123. #elif defined(STM32F410xx) || defined(STM32F411xE)
    ! F+ Y- n2 x$ x! K9 ?
  124. #if defined(USE_HSE_BYPASS)
    9 r( I  ]: F3 b0 v- O
  125. /******************************************************************************/
    + }, E- v; q' P5 t4 k. l
  126. /*            PLL (clocked by HSE) used as System clock source                */) q) b, v+ w& A& g4 v
  127. /******************************************************************************/
    / M6 j$ V2 k7 s8 i. y" z6 C
  128.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;2 R- F" e$ n. q7 t: R' V

  129. / M% x/ [# ^+ G) R; `  b8 K
  130.   /* Enable HSE and HSE BYPASS */) F5 R# ~( Y( s0 Y
  131.   RCC->CR |= ((uint32_t)RCC_CR_HSEON | RCC_CR_HSEBYP);
    5 ]" a3 Y( ^) C. p7 o

  132. # E3 i6 r4 R6 g8 u
  133.   /* Wait till HSE is ready and if Time out is reached exit */
    , O! n! q3 h  M6 s7 k
  134.   do3 N% @, e( z8 a$ K
  135.   {
    % p1 V" A) W8 b4 J5 b( Z
  136.     HSEStatus = RCC->CR & RCC_CR_HSERDY;- R/ x+ }9 f# q. _1 p5 |9 K& U7 A
  137.     StartUpCounter++;
    + g* W" i. h9 U( h" U1 O4 Z
  138.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));# z# A3 x2 O0 \' ^. Z: s5 B

  139. 6 V& j* a6 f4 y6 Y/ t) A, j: z  Q
  140.   if ((RCC->CR & RCC_CR_HSERDY) != RESET), O/ a& ?# d& S8 N4 p
  141.   {" {1 X; i! ~& G- E
  142.     HSEStatus = (uint32_t)0x01;
    4 H$ C0 |8 ?. P( a. h; O
  143.   }
    ) L/ c% X/ B/ }
  144.   else
    3 v' q! _) t% K
  145.   {) T; u- t2 E# ?: n* ^7 X) N
  146.     HSEStatus = (uint32_t)0x00;
    0 n7 G7 }5 S+ x$ a$ D
  147.   }* l) Z' y4 T/ G) f1 a( o

  148. ' `$ b0 d- R: a" ^' a) p5 c9 A
  149.   if (HSEStatus == (uint32_t)0x01)
    4 [4 y3 R; x; F0 E+ q3 {
  150.   {
    & a1 x. w. A  m# T
  151.     /* Select regulator voltage output Scale 1 mode */
    " n! ^& v% D2 t4 L6 i
  152.     RCC->APB1ENR |= RCC_APB1ENR_PWREN;: l) q0 K: O; E5 P
  153.     PWR->CR |= PWR_CR_VOS;
    4 `9 M1 }1 G+ m5 U, q& M

  154. 1 B3 e% D) m: {3 z1 D
  155.     /* HCLK = SYSCLK / 1*/
    - [, U) Q2 V$ _+ a- u# o: W
  156.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;  U3 h+ ?) U' z9 h5 F" G

  157. 0 e3 x8 ~# n$ O5 u+ j% m
  158.     /* PCLK2 = HCLK / 2*/" V+ D9 t7 Z$ |9 e1 W( `# u5 T
  159.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
    0 Y& t3 j' [! C+ F
  160. / A* h& J* p, i0 n: N
  161.     /* PCLK1 = HCLK / 4*// k6 `* n6 h! o) [& @8 {
  162.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    " I5 Z% k) _7 c, ~( X0 ?
  163. : Y0 X$ h  J  i# q- q; N
  164.     /* Configure the main PLL */
    " E6 F0 e( h2 L6 N  z) l$ ?& C. m# D
  165.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    * O3 J/ @' k0 H* H6 o8 Y' L! l. s
  166.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
    ! [7 m' ?6 k1 b4 y. E4 i
  167. # |& u8 B" _1 n  Q$ ?0 r* T1 l
  168.     /* Enable the main PLL */9 |9 V, l5 C7 b" V: a' E
  169.     RCC->CR |= RCC_CR_PLLON;& y3 h1 p( O6 z! u7 _
  170. 8 c( l+ f7 t' G: }4 {
  171.     /* Wait till the main PLL is ready */+ J: z, X. O% J( e' X( D0 N
  172.     while((RCC->CR & RCC_CR_PLLRDY) == 0)+ o" J0 A. Y( B# I+ n- o
  173.     {
    . h( L$ \: F! N# R
  174.     }
    # S7 s% o4 v# j# M4 S% ]

  175.   }+ |, [4 D3 M1 H
  176.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */; I7 g/ F  t/ v4 y% N# [
  177.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
    . t/ b  I/ X& n( H. ^) m) f2 K* ]

  178. # b4 ^0 S6 s1 |( C/ j1 [
  179.     /* Select the main PLL as system clock source */
    1 Y$ _7 S0 ]1 {2 I1 G9 i, ?' Y' b
  180.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    ! f. Y9 U6 R0 ~! u
  181.     RCC->CFGR |= RCC_CFGR_SW_PLL;
    ; S9 P% y5 y5 L
  182. ! C4 u& F4 ~+ M2 K7 |: G. z
  183.     /* Wait till the main PLL is used as system clock source */
    # W/ V0 \( D/ }6 s
  184.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    8 Y; c  d3 [' ?" T0 ]
  185.     {
    . X/ |( s! l0 m: a
  186.     }" }8 }2 {* S! C- a6 I! d9 J
  187.   }3 L; g( z- U. O  c; v& E$ _
  188.   else
    / t/ l; X& d2 L: o9 v  B, n8 ~
  189.   { /* If HSE fails to start-up, the application will have wrong clock, p$ ]7 c4 L/ [) \3 A, j2 ?
  190.          configuration. User can add here some code to deal with this error */
    7 G/ M/ v: u3 r6 d# z
  191.   }1 O# e! e' [% V
  192. #else /* HSI will be used as PLL clock source */
    / h+ h' U& F; f" l* C( [/ c
  193.   /* Select regulator voltage output Scale 1 mode */
    6 p! j+ u( r3 U, G9 O. C1 S) R
  194.   RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    ! z0 N, q2 L/ y  c9 M
  195.   PWR->CR |= PWR_CR_VOS;% @. D) a) q, t+ q: N

  196. 7 |# p1 n  H: E: k( @1 Q( I" p
  197.   /* HCLK = SYSCLK / 1*/
    $ o& R8 Z* h: P! A
  198.   RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
      m' s# B0 [. m( a* |% f6 E
  199. : s) C: ^. u0 K
  200.   /* PCLK2 = HCLK / 2*/
    1 l! L8 ^: @& f! \. `
  201.   RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;6 u  z' f3 j+ x
  202. 6 o" e0 M7 A! `: ~/ X
  203.   /* PCLK1 = HCLK / 4*/4 R( Y) f8 T* J3 c1 `
  204.   RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    + |4 V$ Z( F0 v- n& f  {* E

  205. 3 l! @: u7 C' f2 _3 r! {
  206.   /* Configure the main PLL */  m% o. |0 c" y# m
  207.   RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (PLL_Q << 24);
    - J& S" o8 b8 J6 s$ `" P1 u

  208. ; l9 M! _5 Z: @; W5 |+ }
  209.   /* Enable the main PLL */$ K8 M- I: V: f: F5 Q. r2 x5 d
  210.   RCC->CR |= RCC_CR_PLLON;& V. B$ E& J1 |" P+ l* D* f: d5 @

  211. 8 ?/ a) A- @5 @& R) O( T1 H
  212.   /* Wait till the main PLL is ready */; V8 {8 b3 b, k: p! u, R" d
  213.   while((RCC->CR & RCC_CR_PLLRDY) == 0)6 b/ t4 x; o, l7 T; C6 f
  214.   {
    1 ]6 W% E, K! y6 f2 |. n$ X
  215.   }
    2 x1 C3 [* D- m

  216. ( c* S, P5 O2 x0 \
  217.   /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
      F# o; o8 g/ [' z7 r4 ^. V& `
  218.   FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
    & N) s# B* X7 c8 S; ~& x2 f

  219. 5 m( z$ L7 m6 U0 }- d# h
  220.   /* Select the main PLL as system clock source */
    1 S6 u9 i8 P4 G0 J3 C7 G  t
  221.   RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    . g1 W. G& L2 D9 O9 d! S7 m% m
  222.   RCC->CFGR |= RCC_CFGR_SW_PLL;
    3 r+ B& b$ K+ }3 Q& K% R. a  w

  223. / b7 A# M! Y  [4 [% }" [
  224.   /* Wait till the main PLL is used as system clock source */& f% O, _; t/ I* z4 G
  225.   while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    ) K4 Q5 N9 R; X" X- O3 ~2 F# a4 F
  226.   {6 V- q0 g. j" m, i0 W
  227.   }
    ) `& O; B# B! `- O" @) `
  228. #endif /* USE_HSE_BYPASS */  
    : y4 _. u3 u" h$ `+ U
  229. #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F469_479xx */  ; |7 _1 ?# g. ?
  230. }
复制代码

! X; m  J: N/ }' k/ [先使能外部时钟 HSE,等待 HSE 稳定之后,配置AHB,APB1,APB2 时钟相关的分频因子,也就是相关外设的时钟。等待这些都配置完成之后,打开主 PLL 时钟,然后设置主 PLL 作为系统时钟 SYSCLK 时钟源。如果 HSE 不能达到就绪状态(比如外部晶振不能稳定或者没有外部晶振),那么依然会是 HSI 作为系统时钟。
/ [0 B' P& O% C
8 W2 ^# W4 x( e5 ]; a5 f, @/ s在这里要特别提出来,在设置主 PLL 时钟的时候,会要设置一系列的分频系数和倍频系数参数。大家可以从 SetSysClock 函数的这行代码看出:9 n% q" C- o: L2 B, |
4 |- }3 r" @1 Z1 A& V8 w
  1.     /* Configure the main PLL */
    / L& H- Z9 O' T- s- ~
  2.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    % Y  T% h! p. h5 W5 ^: M2 p9 P6 L
  3.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
复制代码

- |( f* z6 y7 b4 x1 X/ T# X4 x这些参数是通过宏定义标识符的值来设置的。默认的配置在 System_stm32f4xx.c 文件开头的地方配置。对于我们开发板,我们的设置参数值如下:
& w. e4 j0 z: \7 B% ?& W
* x! q7 r" w5 N' e
  1. #define PLL_M 8
    1 N0 B7 k2 G3 _# n$ H
  2. #define PLL_Q 7- p$ e7 [2 z* N' v% @
  3. #define PLL_N 336
    4 W8 z& P) [$ X: |! G9 _$ e5 K
  4. #define PLL_P 2
复制代码

: U7 S" `! ]9 Y+ g- i, ?& C! ]& Z2 S这里还有个特别需要注意的地方,就是我们还要同步修改 stm32f4xx.h 中宏定义标识符HSE_VALUE 的值为我们的外部时钟:$ ]  V) Y+ X) s- Y' S& V
' \9 A" z% D; t' _
  1. #if !defined (HSE_VALUE)- l. P% G" g- {* x: K$ Y2 J% x
  2. #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
    ; F3 p! C8 B- `1 k# O
  3. #endif /* HSE_VALUE */
复制代码

+ J7 J" C$ A0 j. j% V这里默认固件库配置的是 25000000,我们外部时钟为 8MHz,所以我们根据我们硬件情况修改为 8000000 即可。- h" u6 h, L5 i2 o$ F- v
+ Q+ R6 |! m) ], V/ V( N2 _' A: s
04. 时钟配置总结7 h: y* c! {' Q# u! V, E8 n9 g
最后我们总结一下 SystemInit()函数中设置的系统时钟大小:- @: x1 r# ]  E) ?, [
SYSCLK(系统时钟) =168MHz
1 {% o7 a% E" @2 f) y+ vAHB 总线时钟(HCLK=SYSCLK) =168MHz
2 T( }) Q9 W1 `2 R( U6 y: P' QAPB1 总线时钟(PCLK1=SYSCLK/4) =42MHz4 q6 X4 F1 B5 I, @3 y+ I5 B
APB2 总线时钟(PCLK2=SYSCLK/2) =84MHz
6 d9 O4 f" a* Z. \8 EPLL 主时钟 =168MHz. S5 C4 |) t& Y' R5 M
7 k6 y# N2 q) t0 J! j. x

' L3 T! o, o1 C" V! q' p
赞 收藏 评论0 发布时间:2022-6-10 20:08

举报

0个回答

所属标签

相似技术帖

官网相关资源

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