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

【经验分享】STM32F207时钟系统解析

[复制链接]
STMCU小助手 发布时间:2021-12-3 17:00
板子使用的是25M无源晶振,下文将介绍STM32F207的时钟系统如何将25M晶振时钟转换为120M系统主频时钟的。
6 W  f0 R' u- J* w# ^9 X* C) i* Q5 @- L: ~9 L
01、时钟系统介绍5 c# U7 h& W1 E. F& n6 @' O3 F/ q0 [

' u9 I' Q6 ]8 F% a( Y
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

8 ?7 f( g1 W9 M, Z                                                                    ▲时钟系统专业名词缩写
% k8 q/ C( k6 d4 }: n7 H
2 X5 c1 t+ d1 W  c时钟系统关键组成部分
: m4 N$ R0 s$ z; `
( O0 M+ t7 g) {4 |  h) Y' Y01 内部高速时钟(HSI): o  c! |/ \3 Q9 L5 t& s

- R6 f; @8 a. `& @9 u4 p. PHSI时钟信号可以通过内部16MHZ的RC振荡器产生,可以直接用于系统时钟或者用于PLL输入。
: p0 P2 n- K3 q8 v" Y1 j
. o) b) M2 i% W/ u4 gHSI的RC振荡器的优势是:在最小成本(没有外部器件)情况下提供一个时钟源。它的启动速度要比HSE晶体振荡器更快,但是即使校准频率后,它的精度仍然小于外部晶体振荡器或陶瓷谐振器。1 x/ \% T. J! C) T6 C

+ ^, d% P! ~- Y02 外部高速时钟(HSE)
8 B# f1 t( D" D) j2 Y1 Q2 c- k  y% L0 `; F" I, n
外部高速时钟信息(HSE)可以通过两个时钟源产生:
2 J0 ^! g! ~' R7 _  y2 H2 `% \9 {  S
① 外部晶体/陶瓷谐振器4 {" @1 ]; ^8 t4 {+ y5 h
; D8 a2 Q9 {, ]/ T& p
② 外部用户时钟3 E0 E1 Z) y& n" S+ W. I

2 j( G/ w) O+ O; g
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
" v! R6 o: \6 v' h
4 m% b4 p7 t- U8 \8 A/ F
▲两种时钟源接入示意图
5 k$ S5 d  X( [& X$ U8 l
- |8 I9 U/ W; q1 G- o+ T% j6 m
/ J. W3 \& d' Q: A03 主锁相环时钟(PLL)& P' r( R9 ^9 P5 }& u6 F
% z# W% P# y* U+ E/ z( `/ B
STM32F2xx具有两个PLL" E9 L1 D2 n' J; Y' z+ j$ V
0 @& Z8 }- q$ ~3 E2 K2 S+ [# x
① 主要的PLL通过HSE或HSI提供时钟,并且有两个输出时钟;) o) w+ R! K* ~: ~) B

* c8 b" e8 p5 a, {7 f0 S" K7 x② 专用的PLL(PLLI2S)被用于产生一个精确的时钟去实现高质量音频效果在I2S接口;
. V7 c* j9 u; Y3 x" d7 v
: Z6 W+ D& v) q4 @5 c' Z4 t- a
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

& n) }8 V! b. Y4 P% h( V9 Q" e& \/ L7 p) }2 z8 A# Y
! j6 U6 _1 v# ?7 K" s3 b. t. R
HSE/M*N/P得到PLL时钟
% \' R3 w! v0 x, g( j& ]( i! F4 m! n# s0 d8 J3 |( }1 Q- R8 M1 p
关于PLL锁相环说明2 E1 R/ ]" b$ |$ k4 q! B2 H+ q3 t; R0 D. S

* a  h0 y1 u: W. r- _- I  M
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
4 }& \/ v5 _  j7 w! P2 G

& x( d" ?. v7 f, w. ~* Z, \% D+ A6 M1 g& a$ z
从1处输入,3处输出是1的N倍。
, Y  M8 N& Z5 e9 n" @4 ]
  M5 b. V( r+ b( b& z7 D+ U$ j! R3处除以N又作为输入,当1和2的频率一样,就锁定了。(之所以图上是xN,因为从2看向3的)
& Y+ ^' x( U2 _( O, D5 ]' ?8 Y3 _; ^( ]) B& M7 a! g$ y5 e& {; r
2 U' g, k/ \) A, d7 B" @8 s0 Q7 H* v
1 b# x1 N9 |/ w# {/ c$ N* {0 j
04 低速外部时钟(LSE)
% f# e6 N  J' R) `8 p, A: X$ y. @6 ]: H! K, W4 V+ E
LSE是一个32.768KHZ低速外部晶振或陶瓷谐振器。' E8 M3 k8 v" p6 \: X6 s" [
0 n; s! b' G- V% @$ ]2 x0 v
它的优点:提供低速但是高精度时钟给RTC外设,为时钟/日历或其他时间应用。! V3 }) E6 X1 c% ~2 C) J7 B

/ k- {# w* n- ?, w  ]$ Z7 A, M& P" C0 C# k5 o% {
05低速内部时钟(LSI)
6 V7 {: \- _% _# S  h! Y$ Z1 n/ Z8 f; H: B  }
LSI RC作为一个低速时钟源,它可以运行在停止和待机模式中给独立看门狗(IWDG)和自动唤醒(AWU)。它的时钟频率在32MHZ左右。$ J1 m& k. r* X( z

- D' I: B5 U$ @; E# S) s02、代码分析. A; V8 c9 Q# L" R  `1 m) ?
时钟初始化代码在system_stm32f2xx.c文件中,大部分时候我们不需要修改时钟代码的,各个总线的频率我们可以在文件头看到。8 v' B) g7 I6 Z' }4 c  k
- B6 X+ h# |% w! s4 L; F6 K; M
  1. =============================================================================
    2 ^8 n" G: {7 T$ U7 P- j
  2.   *=============================================================================
    5 u; ~. i: e. ], A% M9 c2 W9 }2 ~
  3.   *        Supported STM32F2xx device revision    | Rev B and Y
    . c5 j; Y+ r& Z
  4.   *-----------------------------------------------------------------------------+ ~4 x! G/ D: C
  5.   *        System Clock source                    | PLL (HSE)
    # @6 ~3 ~. ]: o
  6.   *-----------------------------------------------------------------------------
    " W- ^+ [# H% G
  7.   *        SYSCLK(Hz)                             | 120000000
    & n% v) u$ O) V
  8.   *-----------------------------------------------------------------------------
    0 Q; k, M/ G! J: s% C5 V7 Z
  9.   *        HCLK(Hz)                               | 1200000002 p3 w+ |+ [/ u$ M! H6 i
  10.   *------------------------------------------------------------------------------ J' ^7 e8 r0 e4 y* I3 e
  11.   *        AHB Prescaler                          | 1% {& V# O% H  f% x
  12.   *-----------------------------------------------------------------------------4 p5 C" z# l- _* u
  13.   *        APB1 Prescaler                         | 4
    5 B' Z: `) t) j4 L+ ~
  14.   *-----------------------------------------------------------------------------
    / `& }- i9 v: y: q7 I9 w6 n& }, ~# L
  15.   *        APB2 Prescaler                         | 2
    2 q3 b. o$ z, [! c' m. @
  16.   *-----------------------------------------------------------------------------
    % |0 G) ?  |, u3 V
  17.   *        HSE Frequency(Hz)                      | 25000000
    2 k$ }1 C" c7 Y' P- D* A( |; G) E5 L
  18.   *-----------------------------------------------------------------------------) I8 s& D/ U" M/ n+ V2 [
  19.   *        PLL_M                                  | 259 \" ]" o: B7 w7 H
  20.   *-----------------------------------------------------------------------------8 e3 p1 J9 E  m0 W& e$ d
  21.   *        PLL_N                                  | 2401 c% R) I  B: a! p  c2 O( f* ~
  22.   *-----------------------------------------------------------------------------
    9 X& ~) c4 l5 @, t% j6 R# A& u) P
  23.   *        PLL_P                                  | 20 k' H# s: F+ H/ W% H* c: y
  24.   *-----------------------------------------------------------------------------
    # v& T) q0 R! o: U3 ]/ }8 i4 i- ]
  25.   *        PLL_Q                                  | 5. Q; n, |  B# v+ X
  26.   *-----------------------------------------------------------------------------) `8 h  t8 V6 H  t5 u( A  N3 D
  27.   *        PLLI2S_N                               | NA0 p' A( K; Y: L
  28.   *-----------------------------------------------------------------------------
    " t4 v. ~1 d2 D3 E2 z. I) ]' E
  29.   *        PLLI2S_R                               | NA. A6 b9 ?& S9 b3 F. x* E- X
  30.   *-----------------------------------------------------------------------------
    0 `5 I/ y: r, \8 q
  31.   *        I2S input clock                        | NA) p$ |. m; g( e9 |  B! {9 t
  32.   *-----------------------------------------------------------------------------
    ( Q8 F6 l! w6 ?! ?
  33.   *        VDD(V)                                 | 3.3
    / \( M- }7 B& V: o
  34.   *-----------------------------------------------------------------------------
    2 @- [% B/ \. e8 q+ d
  35.   *        Flash Latency(WS)                      | 3
      |, Z  r; N: H0 A$ f5 j
  36.   *-----------------------------------------------------------------------------0 ?% g* n% q) C' t; a
  37.   *        Prefetch Buffer                        | ON: s- E7 w  P4 A- }
  38.   *-----------------------------------------------------------------------------2 q. q) \; h6 ~+ ]( [8 _* i
  39.   *        Instruction cache                      | ON+ g) ^2 F, X( e& w, w, q
  40.   *-----------------------------------------------------------------------------% D) C8 N, `8 ]! j* y" [: o
  41.   *        Data cache                             | ON3 g$ a; m( t" \% z5 z: J  F  q
  42.   *-----------------------------------------------------------------------------
    ) K: Q0 R$ i# K2 C: B8 c
  43.   *        Require 48MHz for USB OTG FS,          | Enabled1 e) N* I2 |" m. R
  44.   *        SDIO and RNG clock                     |) x7 S! Q' u' j
  45.   *-----------------------------------------------------------------------------9 c/ [3 ]/ T' T: K9 E- @9 {; B
  46.   *=============================================================================. m. \2 I( m. M% b! ^; I% z
  47.   ******************************************************************************
复制代码
在文件开始定义的有系统时钟频率的全局变量SystemCoreClock,其他地方需要时钟频率,可以直接使用该变量。
+ t) O9 [9 }8 J7 r
  1. uint32_t SystemCoreClock = 120000000;
复制代码

6 z# f% J+ k. [( T: `' S" W+ h9 Q时钟配置从SystemInit函数执行,调用SystemInit的在汇编文件中startup_stm32f2xx.s(Keil编译环境)。
, A* B7 r! A: [! L. ]+ R8 B2 J. \" ?. i
  1. IMPORT  __main8 g! s7 {0 r2 q. t7 Q
  2.     LDR     R0, =SystemInit
    0 f* d9 J3 J& }, v& w
  3.     BLX     R00 }) S6 O. }: {) V' `
  4.     LDR     R0, =__main
    1 i5 d4 r/ Q* |
  5.     BX      R0# T( M) ~7 N7 q. @: q
  6.     ENDP
复制代码
* `( Z. p/ n7 O: p$ q& e
在这里说明一下文档版本的问题:# z: E( d8 ^* L+ L
0 V: S# ^. F) f' B  V3 O2 W
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
) s# g6 c# t$ n$ H+ h

/ J* d' N  c4 Z. m- ]1 r/ B5 n+ x▲STM32F20X_User_manual的V7版和V8版对比图* f% L4 }! k" F& S+ s% h3 }9 }
: z, ]/ t- I! X" }
上述两图的区别是系统最大时钟从120MHZ变成了168MHZ,我的理解是同样是STM32F20X,ST由于技术进步或其他,使得新版STM32F207芯片超频支持168MHZ。
$ y" {. @, I( g' k' Y- G6 X9 Q' c, s: Y& ]
下面我们主要分析SystemCoreClock的120M时钟怎么从一个外部25MHZ的HSE得到的。/ t, E" z, I2 a7 s& k2 ?
* N! o/ f/ @# X& ]6 m8 a5 Q
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

9 E- R/ |8 {2 D; ^; h$ v" W' N# ]: F0 A2 v
我们要从25MHZ的外部时钟得到120M的系统时钟,需要上图中标注的重要4点:
8 Y) q# _% |4 K, o3 G  E# z  f1 y3 f" g
1、使能HSE
6 p3 Q( a5 [( l' j6 U3 v7 H/ w; Z7 w9 {
2、选择HSE作为主PLL的输入时钟
0 g; j8 ^) h, a, G7 d# p/ I+ y7 I9 L- _9 F, m+ n
3、主PLL倍频后得到120MHZ时钟
3 r  @" B# R$ j' ~3 ^" `) c: _% b1 R9 K0 K* E: e2 ^
4、系统时钟选择主PLL时钟输出作为系统时钟* N6 l6 U) K" S1 n
) \0 N0 U  u6 x
我们找到对应的代码
! x2 s8 V7 A# A8 k' g) N4 S
5 ?: P- m6 ~$ E. E! w; S" m  1、使能HSE4 W* J+ i2 h) `) n0 S7 I" D
  1. /* Enable HSE */. `( z- u1 F+ A
  2. RCC->CR |= ((uint32_t)RCC_CR_HSEON);
复制代码

' W+ d( C4 l1 M& w' Z在RCC_CR寄存器(RCCclock control register RCC时钟控制器)中,有打开HSE的控制位
! b- h% y7 s" X! q9 w
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
% q, i6 ]. H) ?; G; t* g
2 Y$ [/ Y. F  j
2、选择HSE作为主PLL的输入时钟( Q$ y7 F4 Y+ O' V) T1 g
  1. /* Configure the main PLL */- |8 y+ t' l, h: P' z" e- q
  2. RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    / k8 d# M: B" x5 Y
  3.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
复制代码

: @( T) Q4 }7 n; ]2 M/ q2 i3 Y& V# }RCC_PLLCFGR_PLLSRC_HSE就是配置HSE作为主PLL的输入时钟* C8 _3 W5 F1 {7 `4 e8 Y/ m

' d6 C$ \. P/ n  C) q5 d0 x  3、主PLL倍频后得到120MHZ时钟" R5 a3 o6 i+ u, L
  1. /* Configure the main PLL */
    ! }/ Q% D$ k3 C' g+ a
  2. RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    ' r  {7 {2 f4 L/ U0 l. A
  3.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
复制代码
' W8 x4 M5 ?9 T) D7 N" V) J9 }
4、配置主PLL作为系统时钟的输入时钟
% e# b- S4 k( P& ^6 C. c5 {+ X
  1. /* Select the main PLL as system clock source */
    - r5 Y) `6 j& G' L( G1 Z% z& \
  2. RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));) d8 A9 J' Z& ?/ }, [  e. _% P
  3. RCC->CFGR |= RCC_CFGR_SW_PL
复制代码
) l- u' n) ~) c3 t& N4 g% a& q6 h  A
对于主PLL的配置寄存器,在RCC_PLLCFGR寄存器中有说明
0 F9 h: k+ M" _! h# A  H, z% `/ g) N, W7 _3 Z4 c* F
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
2 Z4 s" A/ F, Z3 M! u

" i: a0 T0 l( ^$ Y整理后得知f(out)=f(in)* N / M / P
0 d, O3 Q: O! j8 z9 \2 s2 I
  1. /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
    ' P6 X6 {+ y) Z, c# ^1 Y
  2. #define PLL_M      25
    , r1 ?! A4 @/ b; R
  3. #define PLL_N      240& p+ x8 b7 F; X8 }2 S4 K
  4. /* SYSCLK = PLL_VCO / PLL_P */
    ( q# Y7 ~* \+ o( B
  5. #define PLL_P      2
复制代码

+ ~7 |5 ?! g3 X8 R8 y$ C" |这样就获得了120M时钟
  ^3 D" p: \% k3 ], `
7 Z9 w: Z6 u$ o注意:) r/ t+ W9 d+ c9 d0 ]
2 `( o8 r+ o  i& l9 n
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
" F$ V9 j, b, N) V  P
& d' l: U/ r/ @+ b5 c: T: N
PLL_M大于等于2且小于等于63+ M; g3 j$ X% }3 R" m8 g+ u7 P
7 u6 J+ i# u: p
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
( @! N2 e0 ^: Z+ D# ~
) b9 ~3 }4 l9 D
PLL_N大于等于64且小于等于432
5 Z& H) p7 O- v  F0 J
* c" [5 V( Q1 {
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
0 H- W2 i2 n6 t+ s
  g+ L4 J/ P# h3 l( V; }5 q
PLL_P只能是2、4、6、或8( ?' _; T$ \' E5 d
/ g- a7 [+ J  P0 B3 T$ m( t
但2对应0,4对应1,6对应2,8对应3。
* G* ~) V2 ^0 s( J  z7 F4 [
- F' Q( X' t8 [ST并没有使用if或case语句判断,因为对应的数据除以2减去1就是寄存器这两位的值,所以可以按照下面这样写,这种写法值得我们学习。! V5 r( J- Z1 @$ z

7 s  N% k" |5 A( B(((PLL_P >> 1) -1) << 16)
$ F; X6 A0 u+ {# c0 H' _! n) ~4 X$ V其他外设的时钟配置时
2 D! m/ E7 E, H' q
  1. /* HCLK = SYSCLK / 1*/4 g2 N3 }: U/ j: A7 i7 X
  2. RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    8 V0 V( O: @% z* \3 x
  3. /* PCLK2 = HCLK / 2*/1 J  h+ [3 ?# E
  4. RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
    9 x1 O4 b* P7 K+ @, c- _' q& }
  5. /* PCLK1 = HCLK / 4*// r9 i* R  [6 z( E" N
  6. RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
复制代码
$ \) T7 f- T8 \, W1 k
03、备 注
8 I: M+ V# w1 k5 ]
时钟中断
8 [: }. g; v1 W3 J1 s' \* a5 [5 J: h+ V5 Y
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
& a& {; F& w; X  D7 Y

) D# H6 P, G* y! h可以配置外部晶振出错时的中断,还有RCC中断,因此我们可以在外部时钟出问题时,切换为内部时钟,不至于整个系统挂掉。具体见ST给的官方代码。' ]  |+ _1 j  V  u

4 j" v7 I5 X/ X  J" d" D9 t 无源晶振不起振
7 I. x4 r1 D$ Z. g, B! h3 f$ }; N  C3 N0 Q' Z6 ]" j( H
没有程序,无源晶振是不起振的,需要配置RCC时钟控制寄存器的HSEON位打开或关闭HSE振荡器。具体可以看之前的文章《晶振原理解析》。; G& j3 a, N1 E! @) N9 M4 Z/ f

/ Z+ c6 K+ ]5 ]9 V+ m 关于APB和PCLK- O& J6 ~$ e- l, D. ~$ Q

0 Q- V$ \, P4 C" }# S) h7 T, GF207是时钟图没有显示PCLK1和PCLK2,应该就是APB1和APB20 e1 m. D" V% ~7 C: ], n" O0 c9 R2 C
6 u5 g. d/ u) A/ O  U/ g9 y7 ~
应该指的是一个PCLK应该是PeripheralClock的简称,看F105手册
( d: E% `9 E( s: x% m  r/ K0 ^7 B- O/ z
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X2pwZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.jpg
4 i: L5 m$ z0 d; y  B# P' i
6 q$ k$ H. ~+ k/ F" L

2 K( A; p. ?0 W' G
# C4 D: h' `" \: U3 [1 d/ e: C5 U% N8 m1 K( Q9 O( d9 z

1 v; F: B7 V7 x0 x, ]! C( P
5 ?. B, S; e# K  }, _& b$ t- ]2 h
收藏 评论0 发布时间:2021-12-3 17:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版