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

【经验分享】STM32F2系列系统时钟默认配置

[复制链接]
STMCU小助手 发布时间:2021-12-2 14:28

有个项目要用到STM32F207Vx单片机,找到网上的例子照猫画虎的写了几个例子,比如ADC,可是到了ADC多通道转换的时候就有点傻眼了,这里面的时钟跑的到底是多少M呢?单片机外挂的时钟是25M,由于该单片机时钟系统较为复杂,有内部高/低、外部高/低 、PLL锁相环时钟,又有AHB总线时钟、APB1/2时钟,而例子中很少讲到系统时钟的默认配置是怎么配置呢?那么就发点时间研究下这个单片机内部的复杂时钟系统吧。

下图是STM32F2系列的时钟树结构图:

1、内部高速时钟HSI、外部高速时钟HSE和PLL时钟PLLCLK时钟都接到了SW开关处,通过SW选择哪一路作为SYSCLK,SYSCLK经过AHB分频器进行分频得到HCLK,APB1和APB2是挂在总线AHB上的,通过APB1和APB2分频得出fpclk1和fpclk2。

2、PLL输入时钟源主要是靠外部高速时钟和内部高速时钟作为时钟源,通过PLLCFGR寄存器的bit22来选择具体哪一路作为时钟源。选择好了时钟源进入/M分频器,也就是PLLM进行分频,送入VCO,在通过xN,进行倍频,也就是PLLN1)通过/P进行分频(PLLP)得到PLLCLK;(2)通过/Q分频(PLLQ),得到PLL48CK。

然后边看代码边对照结构图进行分析,看软件如何给单片机配置系统时钟的。

& J" b. L9 R' @

301052464747191.jpg

# ]& [! S9 l6 G

然后找到启动代码“startup_stmf32xx.s”,该代码是用汇编写的,可以看到,在调用main函数之前,是先调用了SystemInit函数的,该函数是在“system_stm32f2xx.c”中

  1. ; Reset handlerReset_Handler    PROC
    * d& v4 H5 B. W3 |1 z
  2.                  EXPORT  Reset_Handler             [WEAK]( l% l! @) M% y2 r
  3.         IMPORT  SystemInit
    $ k* X0 N! G8 r% S7 Y# J. F
  4.         IMPORT  __main; T. h! T2 w1 j( f) g; S
  5.                  LDR     R0, =SystemInit
    : x, L8 G( y; l; t# o8 O' H
  6.                  BLX     R07 L- ?6 A" Y+ t2 b6 s# X7 K" B6 J
  7.                  LDR     R0, =__main- x  l6 e3 T6 l0 h
  8.                  BX      R0, E( |" N& F( k5 g, ?; u
  9.                  ENDP
复制代码
; T# ^, s( _0 {9 z- b% h

代码如下,变量直接赋个16进制的数,都不知道是啥意思,目的是干什么的,不知道,所以看下面代码时最好对照STM32F2x用户手册。当然这个只是一个初始化,待会主要看SetSysClock();这个函数,在调用该函数之前,我们知道单片机是先启用了内部高速时钟等一些配置。


; M/ c6 m9 i  U; u+ Z

  1. void SystemInit(void)
    - i, a, h5 ^0 P7 @- a! P5 d
  2. {
    , J. V1 d* @& [3 }( v: I$ q
  3.   /* Reset the RCC clock configuration to the default reset state ------------*/
    " g* J2 D/ w2 A& X4 {
  4.   /* Set HSION bit */
    9 U1 a/ T( U4 ?: a. ~# F3 {- [
  5.   RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ  ~2 R. f* ]( O2 v
  6. ( O8 `3 ]7 j1 \* F
  7.   /* Reset CFGR register */
    ' P% G# S& [, L& \
  8.   RCC->CFGR = 0x00000000;    //通过开关SW选择内部高速时钟作为系统时钟16MHZ
    ) B$ S, |. @3 B$ Z
  9.                                                         //AHB prescaler 不分频
    8 x# i5 C/ [7 b9 W( _4 q0 l& N
  10.                                                       //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ
    8 ~7 Q" h5 H( u8 B& x7 @
  11.                                                         //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ
    3 b) A; c/ U0 c) y  s5 g" [5 A9 o6 c
  12.                               //MCO1和MCO2时钟输出等配置可参考用户手册Page95  r! o; Q- _$ K) n5 E" C

  13. . l- A" m! C4 o1 O
  14.   /* Reset HSEON, CSSON and PLLON bits */$ t2 N/ k9 `$ |5 j, z, c
  15.   RCC->CR &= (uint32_t)0xFEF6FFFF;
    6 `- H7 c: e# q! [( }# ~( Y) [

  16. $ x3 U7 k4 A: e& W5 Z" Z
  17.   /* Reset PLLCFGR register */9 G1 o* r( ]- p" H( {0 ]; c6 ^2 _- D" K
  18.   RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_3010% M: @+ B4 {* P! N

  19. ' N6 O; z7 V% u8 D# u+ ]
  20.   /* Reset HSEBYP bit */
    ; R- {4 z9 y* C7 e
  21.   RCC->CR &= (uint32_t)0xFFFBFFFF;  //对bit18 HSEBYP 设置为0,外部高速时钟被禁止$ z. \! e5 W- J4 }; ^* U  t
  22. & f/ M: a) J* R
  23.   /* Disable all interrupts */
      i, A6 E' {7 j
  24.   RCC->CIR = 0x00000000;  //所有时钟中断都被禁止4 ?/ `0 M, ^& I# H5 j$ Z

  25. 1 f+ i$ f5 X$ L2 h6 k
  26. #ifdef DATA_IN_ExtSRAM
    5 T( O8 D* q, q1 X: `  [
  27.   SystemInit_ExtMemCtl(); " T' u1 y) d$ T$ p- n0 o
  28. #endif /* DATA_IN_ExtSRAM */
    9 a! m  r# C6 d  b+ n
  29.          
    2 C* h1 M( |" o, W% N. l
  30.   /* Configure the System clock source, PLL Multiplier and Divider factors,
    * o6 u% o8 @) o
  31.      AHB/APBx prescalers and Flash settings ----------------------------------*/
    : X, x, L/ h# |0 I# j
  32.   SetSysClock();5 g6 ^  ?4 p# j8 _, ?4 ]3 l) G8 g
  33. * B2 q1 `! k0 ?6 ]0 d5 S) V
  34.   /* Configure the Vector Table location add offset address ------------------*/
    2 }: k- j  O& v/ w/ R0 p8 T
  35. #ifdef VECT_TAB_SRAM% h) j/ l( o8 ^1 I* R4 j4 H
  36.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */, N& G# U! Z5 B( R
  37. #else
    $ f$ ?1 W! t( n1 d8 s4 v0 L8 K* `, Q
  38.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
    9 g" q7 G3 n. ~; Z& I
  39. #endif4 u4 L  O) H4 O
  40. }
复制代码

, Z' j4 _1 l0 ], }/ z. F

在SystemInit(void)函数中在配置完一些参数后,还调用了SetSysClock()函数,该函数代码如下

  1. static void SetSysClock(void)
    ; ^8 B9 m2 f! u7 u+ Y# e
  2. {
    1 [& Q4 H: J" c1 Q' ]7 f
  3. /******************************************************************************/4 \$ j& v. b: F% ^) _
  4. /*            PLL (clocked by HSE) used as System clock source                */+ b& d$ h9 i. f8 V7 R7 u& t
  5. /******************************************************************************/
    * v( S) @; @2 Z: {6 Z- `5 ~
  6.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    ) a; ?+ L  r9 i5 X  }  ?( q# Y6 ^
  7.   6 g3 H/ p* T/ u% U2 A  Y, M" W+ p) z5 H
  8.   /* Enable HSE */# g% a5 S! I. I
  9.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);  //外部高速时钟使能,25MHZ
    " i4 \. R  ?+ `

  10. 9 k- B! y: s) P; K4 H  g
  11.   /* Wait till HSE is ready and if Time out is reached exit */  //外部时钟使能后,得需要一点时间到达各个端口3 Q# I8 S' T& z% T( Z# I- F$ x
  12.   do
    4 X: m4 {& M4 o
  13.   {
    , H5 M, b+ F1 N7 m
  14.     HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好) b- }2 h) U1 L( P
  15.     StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时& f. w- S0 B# U- `, f
  16.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));, l. z  d& I1 {4 T2 Y' l

  17. . f) N+ K( G5 v! I' J
  18.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的
    5 ?5 u0 J! T: [
  19.   {1 K5 k4 g5 {0 M- _
  20.     HSEStatus = (uint32_t)0x01;   //说明时钟已准备好了,才结束do whlie循环
    6 T( n7 X/ D. r( v1 @: P6 a8 U
  21.   }# @; n- n7 D: y& z+ D
  22.   else
    3 t  l2 \* i, s5 F: Y3 J/ j, D+ _) Z
  23.   {7 v8 e" Y; d: T9 \9 h$ V" w6 z; S
  24.     HSEStatus = (uint32_t)0x00;  //说明是因为超时了而退出do while循环" w' U; e( w9 h" `2 u
  25.   }
      {5 Q1 o0 h3 @, r' c! H
  26. : p& q; o' ^* k" |% z& m
  27.   if (HSEStatus == (uint32_t)0x01)
    + w5 {. C2 y: L3 X
  28.   {0 h1 {6 X' W0 p# Y1 A
  29.     /* HCLK = SYSCLK / 1*/
    $ Z5 q: Z: |8 J# r  L7 j* E: L
  30.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M
    6 r) A& i9 L, n3 a
  31.       , s5 n. A( G$ u" G
  32.     /* PCLK2 = HCLK / 2*/9 u: I- s' n8 f2 V: Z3 [4 }  m1 K
  33.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M2 q9 |) t9 ^( z7 P, I0 ?6 t" h" P( l
  34.     ! M' M; W- ]( w7 w
  35.     /* PCLK1 = HCLK / 4*/) ]- s+ z2 s3 i1 p9 t* Z' f+ P3 F
  36.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M
    ' x. B' ~9 l( Q& g( U2 G" c

  37. ; X2 n& R+ V! x/ j! O  Y
  38.     /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置
    5 e7 h4 Z( t0 o  P; B
  39.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |6 `. K! J8 E, C- k8 S3 {% Y" t
  40.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);. M/ h0 j- s% d4 [% ~
  41. //配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能
    2 {: f" }3 K) H
  42. //通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M
    / q2 a2 i4 p: F+ N$ ?+ f
  43. //通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN
    + G) r9 O8 }8 E
  44. //bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M' G" |7 W$ u/ P+ b
  45. //bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M
    ' g# W1 x) E- F; T9 K+ {/ I" w
  46. //bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M' S8 q+ g1 p) [. E& \5 F- j
  47.         
    * N% J: H( S! t8 U
  48.     /* Enable the main PLL */
    0 }% Q) i+ S. Y0 L; `* r
  49.     RCC->CR |= RCC_CR_PLLON; //使能PLL9 l( C1 R1 G9 W  M" {0 c* j3 r
  50. " H+ z4 o6 d1 Y/ {; c
  51.     /* Wait till the main PLL is ready */' E2 H  n7 o0 g- m5 N
  52.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
      I( N/ }: S7 @" ]' A  ^
  53.     {
    * {: o, d- U8 t9 F+ o4 F( X; E# L
  54.     }
    % Y6 L8 w, _. r' K" [
  55.         //到这里RCC->CR已配置完,最终值0x03036783
    9 {5 A$ `& c. w0 n8 K* f
  56.         //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启6 Z9 K. }! Y6 b8 e" U5 S
  57.         
    ) h, `# I" E: v: e4 i. ?# p3 Q% ^
  58.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */; H  E5 e# u( v% @" Z) \5 R0 X* m
  59.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;
    ! B* D+ U  h1 m- w# \% a! v2 D

  60. . \) _- J0 v9 @; J
  61.     /* Select the main PLL as system clock source */
    , B; }$ o* ^) A- X
  62.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));: c  O, |% D6 n% R, _6 p
  63.     RCC->CFGR |= RCC_CFGR_SW_PLL;" M, I' k2 b9 b+ K- [1 r( b
  64.         6 H3 O, b3 k  j+ _$ [
  65.         //到这里RCC->CFGR已配置完,最终值是0x0000_940A
    / X# E* T" z) X; R  z. V1 ~
  66.         //通过查看用户手册,知道,PLL时钟作为系统时钟即120M0 H2 P* ^; d, i! U; v
  67.         //AHB不分频,即HCLK = 120M6 Z9 N1 h% v* h' U1 S
  68.         //APB1 4分频,即fpclk1 = 120/4=30M
    * d4 s' \" N1 G0 _6 |
  69.         //APB2 2分频,即fpclk2 = 120/2=60M8 i0 n) A  ]+ P1 F3 `7 D
  70. $ C4 x3 x* g. ^  z; m
  71.     /* Wait till the main PLL is used as system clock source */. D* |5 ]6 j* r- c5 j4 C
  72.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);% _/ _8 s: S  _# G! t( M1 `
  73.     {8 w) l: `2 l9 Z) Z  Q$ y
  74.     }
    ( y" E; ~" U- Z7 J
  75.   }" s& j$ S" v$ K( v5 e. Q
  76.   else6 U) x$ G( \0 l- R3 x+ ]' c0 I
  77.   { /* If HSE fails to start-up, the application will have wrong clock, z4 {& b- e+ p7 @5 @1 T6 c+ m
  78.          configuration. User can add here some code to deal with this error */
    ) O3 ]! h" E# S' [- F
  79.   }
    - s- M7 \1 Y" S. |/ {

  80. 5 K! y. v' S7 U: M6 m/ d. [9 G
  81. }
复制代码

3 Z0 t' h4 a; V- Z, b

OK,分析完这段代码后,调用系统固件函数后,现在知道了时钟树结构图中右边出来的时钟是多少MHz了吧。

总结:

1、使用的是外部时钟25MHZ,通过PLL进行分频倍频分频得到PLLCLK 120M,PLLCLK作为系统时钟SYSCLK。

2、APB1出来是30M,也就是FPCLK1。

3、APB2出来是60M,也就是FPCLK2。

& W, ^6 S7 x2 Q5 _. K4 `

# M9 R% j4 v* h, X: g3 ?* a+ A' Q; q7 ]8 v* G8 @, S
. P+ M, c2 K5 ~; ~, M- r# C5 X
收藏 评论0 发布时间:2021-12-2 14:28

举报

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