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

【经验分享】STM32F4时钟系统

[复制链接]
STMCU小助手 发布时间:2022-6-10 20:08
01. STM32F4时钟系统概述# V. ^# d, J; F
时钟系统是 CPU 的脉搏,就像人的心跳一样。所以时钟系统的重要性就不言而喻了。 STM32F4 的时钟系统比较复杂,不像简单的 51 单片机一个系统时钟就可以解决一切。于是有人要问,采用一个系统时钟不是很简单吗?为什么 STM32 要有多个时钟源呢? 因为首先 STM32 本身非常复杂,外设非常的多,但是并不是所有外设都需要系统时钟这么高的频率,比如看门狗以及 RTC 只需要几十 k 的时钟即可。同一个电路,时钟越快功耗越大,同时抗电磁干扰能力也会越弱,所以对于较为复杂的 MCU 一般都是采取多时钟源的方法来解决这些问题。
$ a/ O+ ~; ^; J8 P1 ^' W- S: s; g4 f5 A" ]& T- N0 B; P7 [
02. STM32F4时钟系统图
! o& f) E, u) O% l
4 ?$ I- F: S( P
54RK2N3M}XS88ZREGCB7RB6.png $ F* S0 w5 A) Z( l0 _& R
3 d1 Y2 n& K/ I- K
在 STM32F4 中,有 5 个最重要的时钟源,为 HSI、HSE、LSI、LSE、PLL。其中 PLL 实际是分为两个时钟源,分别为主 PLL 和专用 PLL。从时钟频率来分可以分为高速时钟源和低速时钟源,在这 5 个中 HSI,HSE 以及 PLL 是高速时钟,LSI 和 LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE 和LSE 是外部时钟源,其他的是内部时钟源。下面我们看看 STM32F4 的这 5 个时钟源,我们讲解顺序是按图中红圈标示的顺序:
( S, o& P) |+ {2 F' y# m6 M
! H$ ^% w! O. H+ M) A( p8 A, ~! p①、LSI 是低速内部时钟,RC 振荡器,频率为 32kHz 左右。供独立看门狗和自动唤醒单元使用。
' P: }$ |# @- `$ i; H②、LSE 是低速外部时钟,接频率为 32.768kHz 的石英晶体。这个主要是 RTC 的时钟源。
/ |, u) F8 E. ?( S! N③、HSE 是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为 4MHz~26MHz。我们的开发板接的是 8M 的晶振。HSE 也可以直接做为系统时钟或者 PLL 输入。" M8 P/ @- W" {" q& R7 K- j
④、HSI 是高速内部时钟,RC 振荡器,频率为 16MHz。可以直接作为系统时钟或者用作 PLL输入。
8 W; r, o' Z+ v% g! ?) ?5 H) _# H7 j! j$ P+ z/ Y8 y
⑤、PLL 为锁相环倍频输出。STM32F4 有两个 PLL:
5 F1 p* q( _3 L& Z5 r+ @3 o1) 主 PLL(PLL)由 HSE 或者 HSI 提供时钟信号,并具有两个不同的输出时钟。; K" {* t! M4 n6 \3 Q$ k# m5 J
第一个输出 PLLP 用于生成高速的系统时钟(最高 168MHz)
" x3 j( L/ ~/ s* a2 }: d第二个输出 PLLQ 用于生成 USB OTG FS 的时钟(48MHz),随机数发生器的时钟和 SDIO时钟。
. k. |$ F$ O, A' B2)专用 PLL(PLLI2S)用于生成精确时钟,从而在 I2S 接口实现高品质音频性能。# F- w7 I- c9 M; P4 r' E0 P
2 L* g: W  e' o4 h/ c+ v& ]2 ]6 N, u
A. 这里是看门狗时钟输入。从图中可以看出,看门狗时钟源只能是低速的 LSI 时钟。
9 C1 ]9 X2 d: ]5 n/ [) a3 ^  V( f
) _/ P3 u. g" j! i4 pB. 这里是 RTC 时钟源,从图上可以看出,RTC 的时钟源可以选择 LSI,LSE,以及HSE 分频后的时钟,HSE 分频系数为 2~31。
7 `( b/ m7 F4 }- F  }! J( ?( ^2 W: t4 h3 G6 {7 X1 c: U
C. 这里是 STM32F4 输出时钟 MCO1 和 MCO2。MCO1 是向芯片的 PA8 引脚输出时钟。它有四个时钟来源分别为:HSI,LSE,HSE 和 PLL 时钟。MCO2 是向芯片的PC9 输出时钟,它同样有四个时钟来源分别为:HSE,PLL,SYSCLK 以及 PLLI2S时钟。MCO 输出时钟频率最大不超过 100MHz。
$ l  ?& B, N# E8 f: q8 r% a7 M  T3 R, x/ s  ^
D. 这里是系统时钟。从图 4.3.1 可以看出,SYSCLK 系统时钟来源有三个方面:HSI,HSE 和 PLL。在我们实际应用中,因为对时钟速度要求都比较高我们才会选用 STM32F4 这种级别的处理器,所以一般情况下,都是采用 PLL 作为 SYSCLK时钟源。根据前面的计算公式,大家就可以算出你的系统的 SYSCLK 是多少。
  n8 r& S+ e9 [( j' H- K/ b# a# [" p5 j* d
E. 这里我们指的是以太网 PTP 时钟,AHB 时钟,APB2 高速时钟,APB1 低速时钟。这些时钟都是来源于 SYSCLK 系统时钟。其中以太网 PTP 时钟是使用系统时钟。AHB,APB2 和 APB1 时钟是经过 SYSCLK 时钟分频得来。这里大家记住,AHB最大时钟为168MHz, APB2高速时钟最大频率为84MHz,而APB1低速时钟最大频率为 42MHz。
% V0 Y: c% V& K  p# g5 H2 z5 z0 ]# U
' {( C- |: f# o0 tF. 这里是指 I2S 时钟源。从图 4.3.1 可以看出,I2S 的时钟源来源于 PLLI2S 或者映射到 I2S_CKIN 引脚的外部时钟。I2S 出于音质的考虑,对时钟精度要求很高。探索者 STM32F4 开发板使用的是内部 PLLI2SCLK。
1 }5 I- T0 d" P, [# Z7 D) n% {' H
! |  }0 N+ ~8 {9 E% A; `$ {  ZG. 这是 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。; g9 f5 G& O4 }6 X% ~/ i9 ~
! w' q( [) W# C8 l( ]- [( c
H. 这里是指外部 PHY 提供的 USB OTG HS(60MHZ)时钟。) ]5 A( m& J6 y. _- z
# I* l2 ]$ ^' g# o4 R3 N6 A
03. STM32F4时钟初始化配置- |: D! s! z, @4 ]
STM32F4 时钟系统初始化是在 system_stm32f4xx.c 中的 SystemInit()函数中完成的。对于系统时钟关键寄存器设置主要是在 SystemInit 函数中调用 SetSysClock()函数来设置的。我们可以先看看 SystemInit ()函数体。* ?3 S5 W$ F) ^# }

* r, }3 @( R  ~
  1. /**: V. z4 }+ j* f( m3 I# Z* K
  2.   * @brief  Setup the microcontroller system; z' f2 Q+ S( i7 ^: N0 R3 k
  3.   *         Initialize the Embedded Flash Interface, the PLL and update the   t; |$ x$ n. h4 U! Y. y3 Y
  4.   *         SystemFrequency variable.* H* P& ^8 u' ?
  5.   * @param  None
    2 ^5 V' t7 b5 S7 E
  6.   * @retval None
    " G: S; t5 w: f& l  z2 D3 l
  7.   */
    ( k% a% j9 b# {. P
  8. void SystemInit(void)
    3 [& E+ D9 M# S% }
  9. {% w4 E# n( p- a7 M; j9 G
  10.   /* FPU settings ------------------------------------------------------------*/3 Z+ M5 F# M3 K
  11.   #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)/ ?  \: r0 v) L) X, m6 r
  12.     SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
    0 p& ^! H) Z2 e( G  Q
  13.   #endif
    + @" Y  G# |, B: r  A* _/ l
  14.   /* Reset the RCC clock configuration to the default reset state ------------*/
    9 [4 A% m8 h3 ~: H
  15.   /* Set HSION bit */
    & A# \6 J& w9 ~( Q" F6 ~) I& G2 K) n
  16.   RCC->CR |= (uint32_t)0x00000001;5 M1 T" J6 E. \1 Y* T' H
  17. * H: W2 y$ P) \% e/ x9 j- o/ Z* r
  18.   /* Reset CFGR register */
    / c$ q; w0 t0 D6 c* }% n/ ^
  19.   RCC->CFGR = 0x00000000;: K$ t( s  @" Y6 t. N

  20. . b! Y/ c3 [) b/ J: I. {
  21.   /* Reset HSEON, CSSON and PLLON bits */
    ) L0 v' B6 w4 f. e0 {5 A
  22.   RCC->CR &= (uint32_t)0xFEF6FFFF;% H$ T- m4 I  P3 p6 n- t
  23. 9 F0 b5 f1 l' e1 w2 T
  24.   /* Reset PLLCFGR register */
      B9 q0 u$ [0 j9 |% ]7 X
  25.   RCC->PLLCFGR = 0x24003010;- ?0 {& o8 E, G# p4 M

  26. 8 e% [. _8 x; Z; e, n3 U9 o7 N
  27.   /* Reset HSEBYP bit */) E" r0 ]+ F6 _/ M! M
  28.   RCC->CR &= (uint32_t)0xFFFBFFFF;
    " A- ?( f8 X. t* t8 k, f/ r

  29. 9 D& N8 s$ t* Y7 _' B' S
  30.   /* Disable all interrupts */
    6 w- c' h. [6 r1 |4 o% K4 t
  31.   RCC->CIR = 0x00000000;+ e( V) L" e4 h5 j

  32. 8 \) N' I1 V9 {1 W0 G
  33. #if defined(DATA_IN_ExtSRAM) || defined(DATA_IN_ExtSDRAM)* E- ?( A+ Q+ \
  34.   SystemInit_ExtMemCtl(); % B4 O5 F8 x( V( C) n1 s
  35. #endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
    4 U( r. t& O' O, q
  36. $ }3 v3 d7 S! ^1 S
  37.   /* Configure the System clock source, PLL Multiplier and Divider factors,
    8 b# S. B% P- K& x* B$ \+ v
  38.      AHB/APBx prescalers and Flash settings ----------------------------------*/
    ; t5 ?0 V4 w, m9 I, V: D
  39.   SetSysClock();
    + @9 {0 X- I, g. G8 O# x$ R* h
  40. " R5 v) X  l! {+ k* A
  41.   /* Configure the Vector Table location add offset address ------------------*/' X- ^, a+ P3 ~
  42. #ifdef VECT_TAB_SRAM
    6 ~0 ~* x2 g- s, `3 q8 i: A
  43.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
    1 z+ R5 d# g. c- l' p
  44. #else
    6 t( x6 |' t8 O. v0 f% E
  45.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */1 {) i) i3 S; Y8 q
  46. #endif+ R/ V0 z" o4 f: z
  47. }
复制代码

+ }  V1 i( `2 M* b在设置完相关寄存器后,接下来 SystemInit 函数内部会调用 SetSysClock 函数。
) D8 ~0 Y) V2 p- c/ H. g5 V, m- R+ I& o1 c0 l3 `" ]
  1. /**
    + J5 @6 Y% p+ ]+ K4 F9 n
  2.   * @brief  Configures the System clock source, PLL Multiplier and Divider factors,
    6 |* D: J' w; Z+ S- k. Z) v. z
  3.   *         AHB/APBx prescalers and Flash settings
    - o- w/ i) _# m% E. J
  4.   * @Note   This function should be called only once the RCC clock configuration  
    ' w0 K0 K1 P4 C3 C, f5 G6 s3 `
  5.   *         is reset to the default reset state (done in SystemInit() function).   
    - q; [; h, j3 R3 C  z: u4 O4 l
  6.   * @param  None& z9 K! q: ?) Y  M. P, N8 a
  7.   * @retval None- m1 N* p  V8 T9 Y8 |  c* k) l1 P
  8.   */
    6 r  w* H2 f% G. ]' w: l
  9. static void SetSysClock(void)
    3 T5 h( @+ Q% b2 q
  10. {
    . O; N7 R0 ]$ }, y7 Y
  11. #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)|| defined(STM32F469_479xx)0 o0 H# U0 E) N; [
  12. /******************************************************************************/
      P) y; K7 {( n, y- X' A% t
  13. /*            PLL (clocked by HSE) used as System clock source                */  c* h: Z1 y  H# I  f
  14. /******************************************************************************/; G' @8 v1 a. v8 ~) g
  15.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;$ k8 {1 g) g, K

  16. 6 U+ M* ~. P7 q4 ^* ~1 a1 u
  17.   /* Enable HSE */ //HSE时钟使能
    & s, q. g  S1 f# a) ~2 Y! |$ r) w
  18.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
    ) I# N* o/ ~5 D% E  @
  19.   //等待HSE时钟稳定
    8 Q+ z2 ?) j: ~5 A# q( l+ R
  20.   /* Wait till HSE is ready and if Time out is reached exit */* e$ M2 j- _0 r
  21.   do
    $ b7 [& b) w1 X5 r- g7 I8 u
  22.   {
      ~9 y' Y" {( |
  23.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
    ) ]! X/ p, C4 n) `
  24.     StartUpCounter++;* l8 }7 W6 W" V7 X/ @; n
  25.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    " ~& h* P2 E  Z! ^0 ]

  26. - T! h9 A7 [/ p! k3 |
  27.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
    ( P8 w9 I. X' G  B- k) K
  28.   {9 W, ?. h5 X; z; m
  29.     HSEStatus = (uint32_t)0x01;- g" n  d9 L: u* N, D4 P
  30.   }
    " X( I( l: ~0 W. x
  31.   else, N* `, T; g4 T; s
  32.   {( V2 v8 [- O8 X  X, A$ Z( }
  33.     HSEStatus = (uint32_t)0x00;
    9 h% S0 Z8 l# i9 C  T# j( f
  34.   }' C7 r: O8 n5 O
  35. ; _) S! ^& F+ X* z
  36.   if (HSEStatus == (uint32_t)0x01)
    . r) ]9 ?/ v$ l, `
  37.   {. D# }/ c  W- z7 N) o( }( S+ y0 c
  38.     /* Select regulator voltage output Scale 1 mode */* U9 ^& w  J5 A/ U. r, Y
  39.     RCC->APB1ENR |= RCC_APB1ENR_PWREN;& g" k9 h- e/ T" q: f+ p
  40.     PWR->CR |= PWR_CR_VOS;  ^; G! r2 u0 A% q
  41.         //AHB不分频: k' {/ \. _/ U1 w
  42.     /* HCLK = SYSCLK / 1*/6 S- Y8 M7 Q, V# G6 M
  43.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    & v. a" T2 K5 M* [' f0 ~
  44. 1 X* c2 Q5 i9 t' Y, C' ~
  45. #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) ||  defined(STM32F412xG) || defined(STM32F446xx) || defined(STM32F469_479xx)    ; Z1 Y+ ?3 b9 y/ K' w( r
  46.     /* PCLK2 = HCLK / 2*/ //高速APB二分频
    - Z* F# ~- n" G( ^( j' |, T& {6 H, [6 a
  47.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;1 f- r* B* [& Q! ]$ N! d3 g& U9 g
  48. - H7 b3 \0 ~( S# V- D2 a: l
  49.     /* PCLK1 = HCLK / 4*/ //低速APB4分频
    $ t- P5 D1 i  f' {0 n- Z* ]
  50.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;! X8 [/ R* w. {/ s( W, \0 S
  51. #endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx  || STM32F412xG || STM32F446xx || STM32F469_479xx *// |3 k- Q  e! c
  52. / F1 ~9 W+ s5 n
  53. #if defined(STM32F401xx) || defined(STM32F413_423xx), {: u1 r6 P! d& |
  54.     /* PCLK2 = HCLK / 1*/+ X! g+ K7 [; z7 r( v
  55.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;$ H9 C5 ~3 S. g9 B/ [' D. l

  56. 6 I. p9 R2 z! u! r! c
  57.     /* PCLK1 = HCLK / 2*/5 h3 b' F) D/ H4 ^# p9 f, O
  58.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    ' C" ]4 b) c* e! g5 N( U+ n
  59. #endif /* STM32F401xx || STM32F413_423xx */* X# `! ?8 \( n! q8 m' |

  60. ( S2 s) J' ~' p+ T: w" R7 M9 s, N
  61. #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F469_479xx)    " U: M7 m% O! t. T0 a
  62.     /* Configure the main PLL */
      P: t" \0 v# `4 C
  63.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |/ o8 e& _$ n1 e2 S
  64.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);$ }7 U& S" u- g. V
  65. #endif /* STM32F40_41xxx || STM32F401xx || STM32F427_437x || STM32F429_439xx || STM32F469_479xx */
    $ d2 |; I  V4 L, T7 @2 B" p
  66. + `9 Z3 e- `* e3 ^+ ~+ I3 t" a* X; H
  67. #if  defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)
    0 W0 S: [) s! Q. l% ^% T
  68.     /* Configure the main PLL */
    $ @3 q& C$ ?. H" |0 B! P
  69.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    / ]2 k: [/ u. l: k# q) [2 }& a1 I
  70.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24) | (PLL_R << 28);* {) z+ e' e7 C1 J- o9 z
  71. #endif /* STM32F412xG || STM32F413_423xx || STM32F446xx */   
    ; I: ?8 z5 N% H% y; B& R2 i
  72. ! a# o8 O1 A7 j7 g+ V
  73.     /* Enable the main PLL */
    " ]! n/ E3 ?5 K6 h+ q3 H
  74.     RCC->CR |= RCC_CR_PLLON;
    : Q0 E" N5 q; N0 E" m. w. m
  75. 9 w. _7 W, w3 d7 b
  76.     /* Wait till the main PLL is ready */
    - M( ~, D/ i% _% m& K1 D& o: P
  77.     while((RCC->CR & RCC_CR_PLLRDY) == 0)0 b2 u/ o6 _8 |/ J7 e4 o$ J
  78.     {
    4 q3 p. ~$ B+ F( g% l  @
  79.     }- e5 C6 u( \& w$ y5 A

  80. 3 t, l- b" ]$ v) w; w
  81. #if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx) || defined(STM32F469_479xx)
    ( [# ?9 ^$ X$ H4 c5 J1 M8 }
  82.     /* Enable the Over-drive to extend the clock frequency to 180 Mhz */
    8 Q8 [2 m4 S2 H# ?' _3 y  H+ y' z' k
  83.     PWR->CR |= PWR_CR_ODEN;7 G+ P& M3 B# E! O( W5 V
  84.     while((PWR->CSR & PWR_CSR_ODRDY) == 0)8 d9 l4 {& h8 Y$ c
  85.     {
    ) K6 g6 O5 S  k
  86.     }
    8 `( W( S$ l. _6 M5 y
  87.     PWR->CR |= PWR_CR_ODSWEN;' K. o( o' H. g4 [7 E: z; ?
  88.     while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)2 B1 X' H3 N2 {$ Q# W
  89.     {
    ! L! S+ f' y+ s, D- s
  90.     }      + Z: p8 {7 G& D0 o6 Y
  91.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */4 X  ~4 i5 T% |
  92.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;. O: O0 R2 m) m: |% u9 K# N
  93. #endif /* STM32F427_437x || STM32F429_439xx || STM32F446xx || STM32F469_479xx */) ~0 v+ ^* f! W/ I
  94. 0 S' ]1 X0 G' k% T2 P0 x) R, l
  95. #if defined(STM32F40_41xxx)  || defined(STM32F412xG)  
    : s4 E! w% [2 s4 A0 Z# Y
  96.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    ) [/ |$ ~& S# h
  97.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
    7 X# z( U; U3 X
  98. #endif /* STM32F40_41xxx  || STM32F412xG */7 _/ C9 l  ~: N6 q% L: S
  99. ) b# N% w4 J" e. \% y, `
  100. #if defined(STM32F413_423xx)  
    2 C5 Q$ @# s' ~! d( J$ j( |
  101.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    ( Z* q# ~2 @2 i/ ^8 M( q
  102.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS;  L8 K) X! Z% [, _7 x
  103. #endif /* STM32F413_423xx */
    % F7 b- @# \  E0 b# I

  104. 7 @+ K. k+ H; i. H$ E* x
  105. #if defined(STM32F401xx)
    9 S. d$ l  `& b+ R4 C' M7 {& H5 r
  106.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    8 N7 I; G( n" F5 {  v
  107.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;& `* f5 v* g% u3 e: l4 T, v5 l4 J
  108. #endif /* STM32F401xx */
    8 D! [' R. M/ P

  109. 4 d0 E1 u, c4 |+ ~6 Y$ P
  110.     /* Select the main PLL as system clock source */5 ^8 V* H6 H9 q: N; p  A
  111.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    ' z/ {8 Q+ C* o+ ~" ~3 \
  112.     RCC->CFGR |= RCC_CFGR_SW_PLL;, {3 _) ~5 a5 @0 n% q3 D6 s7 }  r

  113. & K- L7 w. p( d7 C( n8 N
  114.     /* Wait till the main PLL is used as system clock source */5 w1 P+ x) v$ y( k1 A( I
  115.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);' \8 b$ ?7 \* t  Q) w/ @
  116.     {- l; Q: I4 m% W
  117.     }3 b  b' s6 H! a8 w+ g& Z3 d
  118.   }
      M7 T! B6 M9 U& j! v* l8 L1 G
  119.   else
    5 Z$ t. ^) a7 a7 f) L
  120.   { /* If HSE fails to start-up, the application will have wrong clock' m' c5 D0 A* E' i# g9 t
  121.          configuration. User can add here some code to deal with this error */% c9 K( B+ q% B  H
  122.   }
    . d7 W( U) S* T4 o; Y1 Q" R
  123. #elif defined(STM32F410xx) || defined(STM32F411xE)
    ; ~, y0 u; p) Y- ]
  124. #if defined(USE_HSE_BYPASS) $ d! ?# \9 k  E5 P. \. s2 o3 J
  125. /******************************************************************************/2 F6 O( \; `6 \! v, u
  126. /*            PLL (clocked by HSE) used as System clock source                */1 a1 u1 g4 {' U0 B2 b
  127. /******************************************************************************/: ^. N3 c% D7 B+ ^$ @9 x3 l
  128.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;9 U( y$ B8 L# _. L
  129. # f$ r& B; k' V; P. a; V9 Y
  130.   /* Enable HSE and HSE BYPASS */# ~2 l6 C3 ~, B( h
  131.   RCC->CR |= ((uint32_t)RCC_CR_HSEON | RCC_CR_HSEBYP);9 R3 r" ]' {: I" f
  132. . J5 u0 j5 `8 p
  133.   /* Wait till HSE is ready and if Time out is reached exit */
    8 {& @2 ^) D4 t* D+ ?$ ?. @3 O! t
  134.   do- e0 W5 G& _6 H0 |5 `$ N- I
  135.   {
    8 \$ m+ |& x9 t: Y2 E' W
  136.     HSEStatus = RCC->CR & RCC_CR_HSERDY;2 ~& V% _9 ], I3 M: O$ [% l& M
  137.     StartUpCounter++;( h" ^4 R1 O6 X: ]( f7 B
  138.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    3 V" R& i4 v- Q+ s7 x

  139. 7 [* P9 y* R# }; B5 Q" m
  140.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
    - O4 j$ s2 T$ N$ Y. ?( g2 w7 E
  141.   {
    ( t6 h" C) _+ S6 r- b
  142.     HSEStatus = (uint32_t)0x01;, k1 {. K. p( u: T) {
  143.   }, X6 r+ ^* U( o; n; c2 Y, A3 q
  144.   else0 Z2 @6 _( D+ F$ |
  145.   {! Y/ e" G  M7 b5 U6 n" ^% q
  146.     HSEStatus = (uint32_t)0x00;! s7 {2 v( v8 ?$ Z2 ]5 ~3 p+ p
  147.   }
    - P7 e. {  D+ L( J. I6 q$ E

  148. * a- L7 H; X" z
  149.   if (HSEStatus == (uint32_t)0x01): B; ~, S% P* v; E
  150.   {
    3 e6 m. X" M: o) M5 T  c* W
  151.     /* Select regulator voltage output Scale 1 mode */  [3 n; }, H- O$ M% v0 O5 K
  152.     RCC->APB1ENR |= RCC_APB1ENR_PWREN;% B+ ^5 L& S9 E% S- L, ?- C
  153.     PWR->CR |= PWR_CR_VOS;
    & p- P" m. k( s9 o. w( y3 ?$ F: u
  154. % i. Q8 v# p- F7 |- h  O* ^1 j. B
  155.     /* HCLK = SYSCLK / 1*/
    ( }9 h" Q0 m. B+ ?+ U' @
  156.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    7 X. N( E, p4 C% h) M8 J) \2 `
  157. 4 |0 b$ W# m% w& S- t+ q1 _: ~1 _
  158.     /* PCLK2 = HCLK / 2*/
    # @* F2 t% Q7 I2 d4 g" B$ n: {
  159.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;% E7 s  c( e/ ?

  160. 4 S7 U! a$ Y& B% p7 r+ {: r- I
  161.     /* PCLK1 = HCLK / 4*/) u/ {( i3 B+ N" @  W
  162.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    ; U. d9 y9 g% r& t8 L

  163. . x0 T) l; _. L# T6 k* }
  164.     /* Configure the main PLL */, L: ?2 I1 I7 ?6 E3 p
  165.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |- J2 i( e. x/ S& C9 a
  166.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);+ {0 Q, f* t1 X4 \0 [

  167. 8 h% i* ~8 [. s( h
  168.     /* Enable the main PLL */
    . U& G$ X& H$ y) B/ H8 |
  169.     RCC->CR |= RCC_CR_PLLON;
    " H1 F$ d4 X4 @7 p! s& S% M( y) f7 G
  170. ( A. n& ]- w" z
  171.     /* Wait till the main PLL is ready */. K( T  h( [. _% `9 y; S% Q( A
  172.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    * t# I: f( m5 _* V% v& [
  173.     {
    3 A* T' Y+ C/ g6 n' {
  174.     }& U$ b% G3 t  o* w2 a
  175. " m4 c) t( h# O8 g; ^
  176.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    % `8 {: e* D' ]( }1 [% ~/ X3 O$ ?
  177.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
    3 _+ j1 o0 l  Q$ l% _
  178. 5 c2 Z9 b3 k5 Y
  179.     /* Select the main PLL as system clock source */
    6 x% J( ~# {3 }
  180.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));! X" y+ y8 a/ c4 w9 n* t
  181.     RCC->CFGR |= RCC_CFGR_SW_PLL;
    - F8 {9 z+ B* W. u4 i
  182. - @5 s. G9 y4 `! Y/ J7 z
  183.     /* Wait till the main PLL is used as system clock source */0 G: ~, D$ H9 f2 S  d
  184.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);- |, p/ L3 T4 u2 K5 [
  185.     {# p. H/ {, l) _( r+ s0 _6 m
  186.     }# i7 C* q. U% u/ e
  187.   }1 F+ O# u2 P/ F) I4 U, A" x! X4 f
  188.   else
    6 m4 h" s1 M; p* h& {+ l2 C2 _/ w8 {
  189.   { /* If HSE fails to start-up, the application will have wrong clock+ i* T, r! s4 c/ w/ U; U7 |$ k
  190.          configuration. User can add here some code to deal with this error */
    ' {  A+ ^% F& t$ @6 F' H7 C9 i
  191.   }
    . B1 C/ t2 Z  w+ s
  192. #else /* HSI will be used as PLL clock source */
    0 N9 A2 Y# w( i6 X! z5 E* l# q
  193.   /* Select regulator voltage output Scale 1 mode */
    * [! o+ P& s0 j* g; y$ O
  194.   RCC->APB1ENR |= RCC_APB1ENR_PWREN;* y: O8 r' Y# `0 o) e
  195.   PWR->CR |= PWR_CR_VOS;
    . D4 S$ x9 T6 ]0 O: h
  196. 9 o. u+ M& ]6 l$ E$ H( }9 ^
  197.   /* HCLK = SYSCLK / 1*/$ u+ J+ j+ x* |# \( c
  198.   RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    4 P( v5 P" C1 b% q* D
  199. + z% C, _- |' `- ^# j( Z
  200.   /* PCLK2 = HCLK / 2*/% C; @" I( b1 U9 ]
  201.   RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
    0 x: f# F2 r, D: ]
  202. ! f! p; ~( @% d, |0 _
  203.   /* PCLK1 = HCLK / 4*/; I: z: h0 Z; t# W! ?. t7 ?" D
  204.   RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    . S1 [' Z+ N  ^3 ~# k  Y
  205. : l! Y0 m. K4 E4 p1 y
  206.   /* Configure the main PLL */
    ' _1 A+ l/ P( ]; I3 q+ ]" Q) R
  207.   RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (PLL_Q << 24);
    / ?! B+ L# I0 _3 A* l+ {* e
  208. 9 @5 J- I2 z, _/ a; U
  209.   /* Enable the main PLL */
    ; v. r0 [" m1 A3 F6 P
  210.   RCC->CR |= RCC_CR_PLLON;! f. H) B! W' O: E' J& D* r4 d6 n* t
  211. 4 C3 A/ j& f2 Q3 U5 l$ M7 m
  212.   /* Wait till the main PLL is ready */- @( k. ?1 N! M! k0 a: z2 I6 D" j  M4 g
  213.   while((RCC->CR & RCC_CR_PLLRDY) == 0)4 ]7 t4 p) h; N
  214.   {
      I1 P3 o% z1 Y/ ?$ {: k7 p) i! e
  215.   }
    3 n5 }, L+ j0 I/ E* @

  216. 0 e( [. M; R( C1 |4 k! P7 p; n3 {
  217.   /* Configure Flash prefetch, Instruction cache, Data cache and wait state */! N9 N9 I* G4 h- `3 V
  218.   FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;+ I8 j6 l2 D) s8 v: S
  219. 0 C# ~9 ^- }: V, V  a9 E
  220.   /* Select the main PLL as system clock source */
    , R/ x2 Q4 u% @' _- E
  221.   RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));( H1 @. A& m) j6 I% k
  222.   RCC->CFGR |= RCC_CFGR_SW_PLL;
    : Q/ T" Z2 {4 N* b
  223. # D# i0 E7 h9 S$ |
  224.   /* Wait till the main PLL is used as system clock source *// ]9 h7 ~  u1 c$ Z
  225.   while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);6 J9 r# e1 \1 @/ B( I2 ?4 e
  226.   {
    ; L, u- [' C$ j* i
  227.   }, B# G/ f* {& {7 d
  228. #endif /* USE_HSE_BYPASS */  : K, h+ V8 u5 k9 Y8 n2 s
  229. #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F469_479xx */  
    : H2 F8 W4 H4 y. t. _8 h: p
  230. }
复制代码
7 u) Y" Y  w, e0 L+ m" f. n6 c  Z
先使能外部时钟 HSE,等待 HSE 稳定之后,配置AHB,APB1,APB2 时钟相关的分频因子,也就是相关外设的时钟。等待这些都配置完成之后,打开主 PLL 时钟,然后设置主 PLL 作为系统时钟 SYSCLK 时钟源。如果 HSE 不能达到就绪状态(比如外部晶振不能稳定或者没有外部晶振),那么依然会是 HSI 作为系统时钟。0 A2 t" J, t9 P, c  ], b9 \1 g  H

5 L3 M( M2 h( V5 l在这里要特别提出来,在设置主 PLL 时钟的时候,会要设置一系列的分频系数和倍频系数参数。大家可以从 SetSysClock 函数的这行代码看出:" \& W' {+ S. a
/ i$ E% K0 f, T1 C0 J/ S4 }! L
  1.     /* Configure the main PLL */
    ! V7 I/ C  Q  a7 i" O/ h
  2.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |* r! S! p" W. F6 \9 u) M" j
  3.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
复制代码

8 v7 a' W0 o6 L) Q# y这些参数是通过宏定义标识符的值来设置的。默认的配置在 System_stm32f4xx.c 文件开头的地方配置。对于我们开发板,我们的设置参数值如下:
" x' n" c1 g& Q& k2 ]& s# z1 r
' M$ t! k; J( s: {
  1. #define PLL_M 8* I7 `) L  b: n& b8 x
  2. #define PLL_Q 7
    / ~9 v) Q' ~! a) \- {5 n" `( j
  3. #define PLL_N 336
    % N0 q  F) `7 r& X/ t0 c* B. j
  4. #define PLL_P 2
复制代码

4 w3 f' O' B; t5 @+ t这里还有个特别需要注意的地方,就是我们还要同步修改 stm32f4xx.h 中宏定义标识符HSE_VALUE 的值为我们的外部时钟:
* m2 _5 o3 P2 X& t, Q1 s" ~- \3 l" J- {
  1. #if !defined (HSE_VALUE)! x- D  d! K( @/ i# |
  2. #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */3 q% B" d( Y* q: c
  3. #endif /* HSE_VALUE */
复制代码
! y+ R. e4 Z5 H& q1 t
这里默认固件库配置的是 25000000,我们外部时钟为 8MHz,所以我们根据我们硬件情况修改为 8000000 即可。
; W: j7 E9 m$ R% E2 q
2 _* `7 j& h6 J04. 时钟配置总结$ M! |$ B- f- t  ~5 o
最后我们总结一下 SystemInit()函数中设置的系统时钟大小:9 Z, M8 q: f- T% ^. o  T" [7 X
SYSCLK(系统时钟) =168MHz
" s8 I" ^5 R) K. C9 Z1 B# n0 kAHB 总线时钟(HCLK=SYSCLK) =168MHz. _$ o& f1 n9 i+ \! p
APB1 总线时钟(PCLK1=SYSCLK/4) =42MHz
3 G- h4 W  K& K$ v, rAPB2 总线时钟(PCLK2=SYSCLK/2) =84MHz
9 }2 P3 y0 [1 Y0 PPLL 主时钟 =168MHz
; {4 c5 x' \% X3 Z, j4 T+ c5 x. C, Q& }( m6 F4 N
! W; o2 T; @. @/ [$ Y
收藏 评论0 发布时间:2022-6-10 20:08

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版