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

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

[复制链接]
STMCU小助手 发布时间:2021-12-3 17:00
板子使用的是25M无源晶振,下文将介绍STM32F207的时钟系统如何将25M晶振时钟转换为120M系统主频时钟的。/ Z. D& k+ D) V6 E1 b
8 \* R" J% Y) R0 {2 t6 i
01、时钟系统介绍4 M+ E2 y, D7 o4 I' J5 j. L9 ^  @  R

8 o* f% D9 R4 v+ n; j, E0 Y2 B+ d6 G8 N. L
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
% g7 H2 u+ K& ]5 n9 m
                                                                    ▲时钟系统专业名词缩写
4 {. N; \; V; A; x! H! Q: ]9 D% H( s- d: [/ t& {
时钟系统关键组成部分) N' P% ]3 u  v6 V1 N! t
- F$ N% F  s3 k" \2 n' A" N
01 内部高速时钟(HSI); S. y8 n# h4 f. \0 j8 o

2 g6 R% Q' J+ [HSI时钟信号可以通过内部16MHZ的RC振荡器产生,可以直接用于系统时钟或者用于PLL输入。! t, T2 ]1 Q! I" ~" Q
  x( P3 ]+ s8 o. n$ v
HSI的RC振荡器的优势是:在最小成本(没有外部器件)情况下提供一个时钟源。它的启动速度要比HSE晶体振荡器更快,但是即使校准频率后,它的精度仍然小于外部晶体振荡器或陶瓷谐振器。8 k5 W2 H2 d! b4 w4 s

+ V5 Y% h+ ?/ m5 z4 g1 ?02 外部高速时钟(HSE)
# U  v9 a3 R3 c- B$ {
, U* j" E: u, z3 g外部高速时钟信息(HSE)可以通过两个时钟源产生:
( ?( i6 T6 H. E9 Q7 w$ w
2 D, v: x4 B# O' c$ y& W① 外部晶体/陶瓷谐振器5 e4 s' v) d3 R% M/ t0 {- |7 L& l

, }, B" y$ j* r/ `" C/ J② 外部用户时钟4 B3 J0 D7 @9 x$ _- C: [
6 v5 w8 Z% `2 T$ {1 \
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

% h4 h# U8 Q% c  W0 p6 l: G0 d( ?5 y  L0 O- I) t, p% a5 b
▲两种时钟源接入示意图# l3 o  ~+ L' P7 b/ s! l

+ a% G; Q% k- F$ ^
+ Y$ E5 Q8 O6 e2 m6 Y+ D/ T03 主锁相环时钟(PLL)
. b6 }- g$ r% u* p4 @/ h, M, o5 x3 d2 A0 k8 i! \
STM32F2xx具有两个PLL
* n$ `& U) [! F2 r- a5 M8 {, O% o+ t6 B: G+ T( }  n; ?
① 主要的PLL通过HSE或HSI提供时钟,并且有两个输出时钟;  u7 k3 e+ ]3 Y2 P4 k
% W( [; f+ g: ~% m# [
② 专用的PLL(PLLI2S)被用于产生一个精确的时钟去实现高质量音频效果在I2S接口;( N; ]: v6 B2 D5 _

8 a7 y4 f+ K9 k! |; _0 y
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
2 }3 P' j% n" e: W8 r# i2 |$ M

5 b% s0 |7 o* ]6 U: h) ^! h& i
, ^7 i% i+ n- W/ yHSE/M*N/P得到PLL时钟
8 ^# b: Z9 _: C8 |; D! g
( X5 Z" A2 {. k; _$ D4 x, E关于PLL锁相环说明
) P/ D" I/ I; I& X7 ]2 a# |
  U" d5 }% K( a( x7 K# A5 }) V
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

( ]& y3 `7 x4 \' f- J" x) K1 r# Y

4 k" f, L+ |! e) s& z/ I  H从1处输入,3处输出是1的N倍。
+ f+ ]0 j5 }+ d) V2 z9 t# g& m+ Z$ t/ B/ i  H4 I& I
3处除以N又作为输入,当1和2的频率一样,就锁定了。(之所以图上是xN,因为从2看向3的)2 t. a$ ~# Y3 t- l, \: d) ~+ [3 Z( s
; _2 y  E+ ~: s* q. A& s

8 Y" a% W0 Z& s5 Q2 p
* i, l7 c; J6 G7 \' w  |7 p04 低速外部时钟(LSE)
8 I% L0 g3 R" A* k/ }. f) k6 _8 \" ^6 U4 e: e7 U7 E
LSE是一个32.768KHZ低速外部晶振或陶瓷谐振器。$ |& W2 s& u* i5 P' L& d
2 _4 G0 j) s/ h7 A8 S
它的优点:提供低速但是高精度时钟给RTC外设,为时钟/日历或其他时间应用。
/ M& p  P4 p, z! k/ K: T- g
# T) W( ^7 P* `9 n3 z1 |; `7 B& T! i( S( l4 E2 p/ T" [8 `
05低速内部时钟(LSI)
$ ^) Q& Y* d! m3 G
* e! {2 F' K, h) ~& j# u# QLSI RC作为一个低速时钟源,它可以运行在停止和待机模式中给独立看门狗(IWDG)和自动唤醒(AWU)。它的时钟频率在32MHZ左右。
- u* R  Z* R( Y0 i& P! w+ o- i/ M1 S% _3 ~% Z
02、代码分析- g6 Y, m( \# u( ~! p
时钟初始化代码在system_stm32f2xx.c文件中,大部分时候我们不需要修改时钟代码的,各个总线的频率我们可以在文件头看到。
2 `7 C. j5 K4 N# D9 n& H& |; }0 A7 r$ v' b- q
  1. =============================================================================' P) l' z( p$ Z# y. _5 q
  2.   *=============================================================================
      M- N+ {6 r, x) t: N' r
  3.   *        Supported STM32F2xx device revision    | Rev B and Y
    7 y6 S! {* @' [
  4.   *-----------------------------------------------------------------------------
    / Z! m$ A3 ?" Y7 n  D& e
  5.   *        System Clock source                    | PLL (HSE)5 E( K# ]' J% c" L& U2 T) E
  6.   *-----------------------------------------------------------------------------/ }- B' s8 h5 X7 O. r: X6 T
  7.   *        SYSCLK(Hz)                             | 120000000# `: y. r& }7 |, \! i, y
  8.   *-----------------------------------------------------------------------------! a2 _* C5 B8 D& R: s; s
  9.   *        HCLK(Hz)                               | 120000000/ y) M. V! O# H3 u+ c
  10.   *-----------------------------------------------------------------------------
    / g8 e! B* f3 g8 K. |
  11.   *        AHB Prescaler                          | 15 c, @6 G' \+ q/ Y: k6 V. D$ R
  12.   *-----------------------------------------------------------------------------$ h0 }, W: p0 |9 `
  13.   *        APB1 Prescaler                         | 4
    ; a9 G: i) Z. r
  14.   *-----------------------------------------------------------------------------9 ~- I$ }6 j1 }' H
  15.   *        APB2 Prescaler                         | 2
    9 M( q- }8 ?4 |& V. ~" I$ i5 ?" Q
  16.   *-----------------------------------------------------------------------------
      A  s# I8 Q  P' W, X( ^8 u0 s
  17.   *        HSE Frequency(Hz)                      | 25000000" c* ~+ Z+ N9 k# F$ @* R) I2 I
  18.   *-----------------------------------------------------------------------------9 R; r1 `3 N0 f- j- L' y" `3 B
  19.   *        PLL_M                                  | 257 D, w" ~0 b* }4 B8 @
  20.   *-----------------------------------------------------------------------------) k/ H8 U3 v4 G% s7 C
  21.   *        PLL_N                                  | 240
    ; C$ i. w. Z* l, Z7 C4 [& ]: t
  22.   *-----------------------------------------------------------------------------& C$ `; q+ ?$ j9 ?9 Z; C' M
  23.   *        PLL_P                                  | 2# m( [- u) y2 a$ }6 I+ U
  24.   *-----------------------------------------------------------------------------
    6 b% u" f( L4 T  i5 W3 G
  25.   *        PLL_Q                                  | 5
    8 D) P+ s$ w8 H( N- A& f4 J
  26.   *-----------------------------------------------------------------------------
    $ @  L& O9 c" p
  27.   *        PLLI2S_N                               | NA
    9 l! L' O  S# A6 L+ ]* ~0 r; }
  28.   *-----------------------------------------------------------------------------
    0 B3 E( V/ P6 S* n1 j; i. h
  29.   *        PLLI2S_R                               | NA
    : m$ L' L" l. f. ]9 J) w
  30.   *-----------------------------------------------------------------------------4 p# M! ]$ `' A
  31.   *        I2S input clock                        | NA
    ! A, g+ h/ E, Z. h
  32.   *-----------------------------------------------------------------------------
    , k) b' N' n: i" L' q5 l2 Q. z
  33.   *        VDD(V)                                 | 3.3
    0 L& G- v( q( v: C
  34.   *-----------------------------------------------------------------------------
    - j4 f7 d: |$ P% o$ S
  35.   *        Flash Latency(WS)                      | 3
    , u# Q2 U8 ~3 A/ e6 {  P
  36.   *-----------------------------------------------------------------------------2 k, H. ^7 \+ ^3 d& O4 T
  37.   *        Prefetch Buffer                        | ON' L$ `! b. b) m' X+ N
  38.   *-----------------------------------------------------------------------------
    ! Z# `" V7 Y' n1 f) Y
  39.   *        Instruction cache                      | ON! [" a9 u( T/ B+ E7 @4 t$ C- e' @4 V
  40.   *-----------------------------------------------------------------------------: i6 C8 F" n9 ?+ l+ M& v1 j
  41.   *        Data cache                             | ON; D& U, o4 Z# o9 W9 i
  42.   *-----------------------------------------------------------------------------+ x3 K7 }8 v; s4 U8 ?" p
  43.   *        Require 48MHz for USB OTG FS,          | Enabled
    - K0 W$ ?' G8 W( W' U, [+ Y" P
  44.   *        SDIO and RNG clock                     |6 S" y5 o, e1 n6 D
  45.   *-----------------------------------------------------------------------------
    2 J8 b( t* G9 e. G
  46.   *=============================================================================7 M* d4 w  i; O
  47.   ******************************************************************************
复制代码
在文件开始定义的有系统时钟频率的全局变量SystemCoreClock,其他地方需要时钟频率,可以直接使用该变量。
1 ^  y2 N6 \* c1 x" g! A% j
  1. uint32_t SystemCoreClock = 120000000;
复制代码
4 K6 M8 v5 H1 L  m* f
时钟配置从SystemInit函数执行,调用SystemInit的在汇编文件中startup_stm32f2xx.s(Keil编译环境)。
# c; j( u. w5 Q4 I/ i' o  O; `" l" S
  1. IMPORT  __main
    # [6 a5 G0 H4 M2 `8 b
  2.     LDR     R0, =SystemInit
    " \5 M) Y2 J" r0 ?$ G
  3.     BLX     R06 ?; ~" Z% _( L! E7 @
  4.     LDR     R0, =__main+ z( Z9 R/ ^* o9 E1 W5 a5 k
  5.     BX      R0
    8 X# j1 U5 k) C. u
  6.     ENDP
复制代码
/ v9 U4 {1 G0 V' H6 e6 `( [
在这里说明一下文档版本的问题:- g" J0 i  |/ T

2 c$ u) h3 T' R! a( `! T5 E
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

* }9 A; N9 p0 g2 y$ W" f$ k( W* Z1 W6 q) t
▲STM32F20X_User_manual的V7版和V8版对比图
1 O4 h5 X' \1 V) Y5 V
2 A8 {" I0 l! K$ a( Q# c上述两图的区别是系统最大时钟从120MHZ变成了168MHZ,我的理解是同样是STM32F20X,ST由于技术进步或其他,使得新版STM32F207芯片超频支持168MHZ。
3 p! `: p* l% w0 n2 G$ T# s* v7 n$ ?0 a% O- q0 J; e- o
下面我们主要分析SystemCoreClock的120M时钟怎么从一个外部25MHZ的HSE得到的。/ _' o( Q$ B" |) Z; N
/ ?- J7 z( W4 g  H! X3 q
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
8 f$ H4 X; i7 g6 J5 q+ G3 R
: |6 b, j( E' o3 S
我们要从25MHZ的外部时钟得到120M的系统时钟,需要上图中标注的重要4点:9 ~9 T& H7 g6 o7 o) [- R  z4 d  V

: \2 Y# T0 L7 }1、使能HSE
- R7 J) h. i3 w( c; _
) ]9 h& N2 J+ R  |: V( _2、选择HSE作为主PLL的输入时钟
3 e1 q+ ^4 ~/ u' |
7 E" e, D6 k  a7 ~3、主PLL倍频后得到120MHZ时钟) P7 i, t& |& Y3 S* Q" b/ ^, X+ o
& l# A% T" L' i7 O1 B
4、系统时钟选择主PLL时钟输出作为系统时钟
: f0 c1 v. y  N" J9 b( h/ M8 z' o3 |( l% Z& X- p! l5 x  J/ F
我们找到对应的代码
" B' y3 o- H* W8 _( I2 }& `4 K7 P7 M# m5 {
  1、使能HSE
; k% P/ f; h# r% o; Y
  1. /* Enable HSE */4 z- k. J4 `, @. s6 q3 Y( Q& ?7 N
  2. RCC->CR |= ((uint32_t)RCC_CR_HSEON);
复制代码

. v: k& W/ Y; m) L3 u( O0 C在RCC_CR寄存器(RCCclock control register RCC时钟控制器)中,有打开HSE的控制位
6 \+ a* {  ]. i4 ^5 [) L0 k6 n
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

' Z5 O$ v$ G  @& Z0 Y, s2 J& J0 m
2、选择HSE作为主PLL的输入时钟
; K& G: g3 k; w
  1. /* Configure the main PLL */; }$ A; c$ u2 e  r! K4 {
  2. RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |) u. R- J5 F$ H; \0 K7 n) k; {  E
  3.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
复制代码

6 h* Q* o6 z* d( V9 g* iRCC_PLLCFGR_PLLSRC_HSE就是配置HSE作为主PLL的输入时钟$ R. c, ]) [/ J& G

' q' U1 N6 n7 l/ e- T! n  3、主PLL倍频后得到120MHZ时钟
0 m6 b' h" j2 y
  1. /* Configure the main PLL */" q6 s8 p/ l! N9 k9 j- g5 C
  2. RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |4 B1 b* x0 A  s- v8 ]
  3.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
复制代码

6 K' B4 n7 N$ L( B1 z) U' T4、配置主PLL作为系统时钟的输入时钟+ h+ ?9 O8 l! `$ Z* g
  1. /* Select the main PLL as system clock source */
    ' z; n/ f0 k- C  j
  2. RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));9 @# O  a  [+ a# H8 d3 P' u
  3. RCC->CFGR |= RCC_CFGR_SW_PL
复制代码

5 i& k2 c1 _; j4 J3 @1 a, z* E对于主PLL的配置寄存器,在RCC_PLLCFGR寄存器中有说明
, @( Q" H0 |/ z8 w
$ V; q" C, S, G& h' V. \
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

6 x8 j% i1 [/ c# m
, ?' M2 f) l# G" M& G4 N整理后得知f(out)=f(in)* N / M / P
6 z/ H8 W1 F3 R2 M; e1 E% @& s2 z( |
  1. /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
    # x, @3 |+ k; V7 R
  2. #define PLL_M      256 i) \7 @: R9 R% z# j: G
  3. #define PLL_N      240
    # D- b5 k$ Y/ B- M2 d
  4. /* SYSCLK = PLL_VCO / PLL_P */  L& S$ O# L) u
  5. #define PLL_P      2
复制代码

' u5 s8 @) ?- f这样就获得了120M时钟
+ y- o$ v$ x2 a, F# }1 ?, w3 g
6 D$ W$ g& T* M7 h& {& U注意:% D: b7 Q- \# F

6 L+ {  h* R% t% \' B7 h+ X
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png
$ ^5 a3 {$ i( n9 F1 }$ G- O
7 u$ S: m9 I; D7 G8 V/ p# X5 r
PLL_M大于等于2且小于等于63
2 X, s6 o% q$ b4 A- c) N
" `: c' ]- L& }% h) l+ O& f
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

- @8 M; g- b% w0 J3 i( J$ M4 j' ?5 a6 I# L+ e" E( s9 o+ {( X
PLL_N大于等于64且小于等于432$ m2 W0 L# }, \* M+ ~1 @

0 X6 Y6 K8 l( V( |
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

' `$ i. b% l* ?5 V) T" _1 S8 D! g) p4 O; E
PLL_P只能是2、4、6、或8. ~) s% z' }* w' G- T  ^% @

: b: W4 S! I# C) Z- Z/ |5 j但2对应0,4对应1,6对应2,8对应3。
/ q* |( w- x0 Y6 W  S; h/ t; i
# q4 a7 E6 h& Q  H7 V) _2 Q; rST并没有使用if或case语句判断,因为对应的数据除以2减去1就是寄存器这两位的值,所以可以按照下面这样写,这种写法值得我们学习。
; |3 \0 F8 M6 h1 N8 t% K+ N
% |" j: |6 v+ b) @2 h! L(((PLL_P >> 1) -1) << 16)
- |* H+ y, S1 h" h% Y其他外设的时钟配置时( |+ w+ m7 \8 ]; \& y
  1. /* HCLK = SYSCLK / 1*// H4 |4 K% c# @' t9 |
  2. RCC->CFGR |= RCC_CFGR_HPRE_DIV1;0 L& T2 }7 [6 r# U3 j0 ]
  3. /* PCLK2 = HCLK / 2*/* h$ w8 x3 t$ o4 I6 K, w
  4. RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;* G- [5 D4 g: V3 ]1 q* @- F
  5. /* PCLK1 = HCLK / 4*/* j; }2 i0 r+ M4 E7 c1 g
  6. RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
复制代码
" N: g6 ?1 g4 @* Q! J
03、备 注
# S, @, F0 Q; X! v
时钟中断
0 d3 A' M5 M# A- J$ ]2 K. K* r; y- a0 w, N0 i
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.png

: {' u+ ]5 M& G  b; `+ ^1 i7 _0 X0 _# x' Y' O' y* ]
可以配置外部晶振出错时的中断,还有RCC中断,因此我们可以在外部时钟出问题时,切换为内部时钟,不至于整个系统挂掉。具体见ST给的官方代码。
1 @3 m. Q! G. G9 C# a( Y( F$ P  K- n! ?% I. v/ i4 d5 s+ u
无源晶振不起振
  y# s& c/ B% K& K/ k0 s( k5 b+ Q8 s4 n6 z
没有程序,无源晶振是不起振的,需要配置RCC时钟控制寄存器的HSEON位打开或关闭HSE振荡器。具体可以看之前的文章《晶振原理解析》。
7 ^  q/ T6 }1 ^5 b( A7 Q# Q  E6 D. A. h0 n/ }
关于APB和PCLK& t$ i' A% v; j8 t- U+ g: e$ ~

5 |, F1 u& \. h- M- b& a, c* IF207是时钟图没有显示PCLK1和PCLK2,应该就是APB1和APB2
( A& J! ~/ b6 l0 z; v4 k1 _! B/ d% t
应该指的是一个PCLK应该是PeripheralClock的简称,看F105手册7 W- I2 j+ G& [- s  p2 N+ B" {

" b; ]$ q/ A/ |- }5 I
aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X2pwZy8wUmc4RGRwQWliZlVxc2pZQ3lEVzVKQUZpY3NG.jpg

* g. F: g) m* R$ u, n( t
* y3 N- ?3 E* r' R. U/ M
! d3 O/ y& t9 A- J9 ?2 d% F% g! T9 R# e1 |( u2 N: `
( D" u9 a* R. E* W7 w# U

8 v1 e; a% h4 d. Q1 z* m0 a- r/ U0 v

# E- e6 p1 i0 Y4 m1 ?, |* a9 X* V! v) t
赞 收藏 评论0 发布时间:2021-12-3 17:00

举报

0个回答

所属标签

相似技术帖

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