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

【经验分享】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。

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


% o* ~! n6 ~" a' k

301052464747191.jpg

2 {' ], R, ?8 `# x8 g; ^

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

  1. ; Reset handlerReset_Handler    PROC
    ( j1 p# |; w; e; n8 t9 Z6 Z
  2.                  EXPORT  Reset_Handler             [WEAK]6 b! a' X$ x! H3 v1 y, J1 v' L) ^
  3.         IMPORT  SystemInit
    8 e$ B! E0 u! G9 c9 `% l! T1 T0 u+ t- {
  4.         IMPORT  __main
    : e8 N+ V; T( @. n9 C) ~/ H$ O
  5.                  LDR     R0, =SystemInit
    1 j& T$ e6 s& T/ B
  6.                  BLX     R0# j0 K, p& G4 ?3 S
  7.                  LDR     R0, =__main
    ( v5 }& g' ^# w
  8.                  BX      R0' X6 \8 `; X6 X( ?9 S: ~' J7 H
  9.                  ENDP
复制代码
: e# ~7 e  k4 \4 p" u- [

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


" N% p; |, e+ Q, k

  1. void SystemInit(void)
    ) S; ^+ H9 b$ X/ _$ q5 V
  2. {
    ' J8 g9 w* \* n. Z
  3.   /* Reset the RCC clock configuration to the default reset state ------------*/
    8 R7 z3 f9 d2 R8 |( t# A# h& H4 K
  4.   /* Set HSION bit */. c8 _! q+ d- @$ A6 J8 {3 t
  5.   RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ+ t- p) @' [# A$ a
  6. ; F$ g& J+ S% r; R
  7.   /* Reset CFGR register */2 Y. U/ V& A' }7 k7 z1 r
  8.   RCC->CFGR = 0x00000000;    //通过开关SW选择内部高速时钟作为系统时钟16MHZ! ^0 O: N0 K2 V. I
  9.                                                         //AHB prescaler 不分频: r+ Z( [& r! n' Q3 P* q( z' e
  10.                                                       //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ
      D& n# D5 |0 X, R
  11.                                                         //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ" J+ b" s6 H7 S- M/ K
  12.                               //MCO1和MCO2时钟输出等配置可参考用户手册Page95
    - R3 B2 _) X! ]" b" M

  13.   C/ `( l$ I$ h( V: Z
  14.   /* Reset HSEON, CSSON and PLLON bits */" Z- N: U) f  S
  15.   RCC->CR &= (uint32_t)0xFEF6FFFF;3 B2 P4 |" i4 |/ H6 Y0 p) T
  16. 5 `% M( b* N3 m5 M6 a! g
  17.   /* Reset PLLCFGR register */6 ~# t0 u3 A: ^1 x2 L; Z- N8 t+ k
  18.   RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_3010
    / `$ o# ^8 f0 o7 S3 x! Y0 y# ]0 J4 r
  19. ; S; l! V# I% p$ _! [7 e8 _
  20.   /* Reset HSEBYP bit */
    : H* H! l# P4 R, P+ h* E
  21.   RCC->CR &= (uint32_t)0xFFFBFFFF;  //对bit18 HSEBYP 设置为0,外部高速时钟被禁止# Z) y0 M8 l, C( T  ^
  22. 9 N2 I. ^" d& Q+ L! x( N' M( Z
  23.   /* Disable all interrupts */
    9 V; n3 ]. M, |$ X
  24.   RCC->CIR = 0x00000000;  //所有时钟中断都被禁止
    6 g: D2 P/ _: e  s; X/ s* w+ R* S4 j! \

  25.   z1 {) q2 A* t' a* v; Q/ v& v
  26. #ifdef DATA_IN_ExtSRAM, m% `3 Q" k/ ~5 C
  27.   SystemInit_ExtMemCtl();
    0 a( W2 _% t! F
  28. #endif /* DATA_IN_ExtSRAM */
    3 g+ h1 h" Z) P5 P% |) Z5 F
  29.          ! V( `5 b8 t* i6 K
  30.   /* Configure the System clock source, PLL Multiplier and Divider factors,
    5 [7 b/ w# N' H5 `# c! F6 ?/ d
  31.      AHB/APBx prescalers and Flash settings ----------------------------------*/& c( w) T3 V1 M. Q3 @0 R
  32.   SetSysClock();3 Z. j6 P) P: D

  33. / P: F4 E# `" y% ^
  34.   /* Configure the Vector Table location add offset address ------------------*// R  z# `, |1 l  |! u/ {
  35. #ifdef VECT_TAB_SRAM
    / v% n+ f9 z# }0 y0 v, P& `! S
  36.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
    & I: @: K  Z" W9 ]* p! \5 ~
  37. #else$ F% U2 m/ R# D- K
  38.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */& e. z& S; B+ k
  39. #endif# q: L% x+ g% Z) C/ Y5 p1 K
  40. }
复制代码


1 b& y8 r8 i& c0 l% X5 a. g9 w- M- x; t  J

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

  1. static void SetSysClock(void)  g" [. p7 L- @& M6 r
  2. {$ y/ l# {" ~! r' D; `8 K
  3. /******************************************************************************/
    # D9 L* u+ b  f1 a+ D: n9 m
  4. /*            PLL (clocked by HSE) used as System clock source                */; w/ q  j" r5 c$ f
  5. /******************************************************************************/
    0 U; Q  D- k- m7 U& |2 Q
  6.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;" V6 B$ F* }5 P
  7.   " i, w" |- ~$ Q4 d7 a) b- \
  8.   /* Enable HSE */
    ! Q1 ]* ^  P* G1 L4 z% u) e2 B3 c
  9.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);  //外部高速时钟使能,25MHZ
    $ |! w2 l7 a3 f5 |8 A+ f1 b1 D

  10. ' w9 r0 s$ ~0 e% o0 p: Q, H3 m
  11.   /* Wait till HSE is ready and if Time out is reached exit */  //外部时钟使能后,得需要一点时间到达各个端口
    , b6 b8 D3 T' ?2 ~! V
  12.   do, ]& x0 H  J% [7 A6 U% f
  13.   {, Q6 U" K& ?* q$ [  ^+ k
  14.     HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好. `% U6 t# X8 l8 g
  15.     StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时
    7 z) a0 }1 }3 _! |3 s# W) n
  16.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));. p6 M* }' E' G3 R. \& U
  17. : G" M0 i2 x& z1 P
  18.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的( b8 u' Q+ c- ~6 W- D
  19.   {' D% t+ a% Z; T4 I( ^
  20.     HSEStatus = (uint32_t)0x01;   //说明时钟已准备好了,才结束do whlie循环
    & m- J3 G0 k+ }0 A5 e
  21.   }6 o; X; n& `1 _. @/ ^; P
  22.   else- R* v/ x$ ]) L
  23.   {
    ) V8 r1 q* z' s8 D$ s
  24.     HSEStatus = (uint32_t)0x00;  //说明是因为超时了而退出do while循环
    ( Z& L8 D( ?  m) P  w1 t/ y2 ^
  25.   }
    * O. Y" p/ F( f5 O! C

  26. % n6 b0 X  X9 ?7 x) N3 w$ j( v
  27.   if (HSEStatus == (uint32_t)0x01)( {" f$ n. m  _- @& S# o
  28.   {$ ^) L+ h3 r) ]9 s2 w
  29.     /* HCLK = SYSCLK / 1*/
    $ |6 R& W5 @$ \4 {
  30.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M& I9 A3 }* S4 z$ ^
  31.       : [* d' k5 K8 C0 ^% f
  32.     /* PCLK2 = HCLK / 2*/
    3 n1 k2 r( Z6 Y- p6 @
  33.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M# w. o6 L7 t! T8 Z& `
  34.     0 u1 V1 G) c+ J5 A3 c
  35.     /* PCLK1 = HCLK / 4*/+ U1 {1 T8 Y. Q$ A7 v  w3 z- s& N
  36.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M/ X; b: L- Y" j) q* C7 a- S7 @/ m
  37. : m# B- @0 m: u3 ~$ X
  38.     /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置
    ! l; i8 i7 @" p  s. y9 J! z/ Z; Z
  39.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |( J3 ^  _  |, A, t' T2 R
  40.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
    % d0 y+ h4 b! t
  41. //配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能9 B  D+ Y2 k, I2 x" u$ y
  42. //通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M
    - K5 q8 B3 p6 Q* ?6 _
  43. //通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN' o+ k: _# F  k" P
  44. //bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M
    ; [! i! f" a" ?+ I. w
  45. //bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M; i  d$ t6 v) S$ U( |, M
  46. //bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M3 ?3 S& ^# ?3 I9 A" A: i
  47.         
    ( k  K1 Z0 r' I/ l7 }* W6 Z6 ^
  48.     /* Enable the main PLL */! B- h0 r% W( L
  49.     RCC->CR |= RCC_CR_PLLON; //使能PLL9 _- ]9 z8 N, }+ v! }% Y

  50. ; Y" Q4 J/ m% _
  51.     /* Wait till the main PLL is ready */
    * H7 j  D+ ^) h/ ^( f
  52.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    ! q5 a, i5 T* w" w
  53.     {9 S3 B2 s9 Q) \. Q6 ?
  54.     }% \: C) O8 P$ [+ Q+ N) q
  55.         //到这里RCC->CR已配置完,最终值0x030367834 B2 a* {- K' c( {& w7 l
  56.         //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启) T; i- n' W1 D; V
  57.         ' ~7 R% b. Z7 r7 s+ v
  58.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */5 H& R. ]( P' [8 x3 t# p/ q  ?
  59.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;
    5 @5 U: d6 z' p, r, E

  60. % e  V' Z3 u( @
  61.     /* Select the main PLL as system clock source */
    3 k  U8 c5 y* [% R( }1 x8 T
  62.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));! R: w! \; h, I; m# C
  63.     RCC->CFGR |= RCC_CFGR_SW_PLL;6 y0 S0 G5 H9 x2 g  p* J! w
  64.         / S& k# W- @) _! Z, ^- w9 U2 F4 L
  65.         //到这里RCC->CFGR已配置完,最终值是0x0000_940A% c9 q' R9 v% @6 {) }- }
  66.         //通过查看用户手册,知道,PLL时钟作为系统时钟即120M0 w, l% D9 u" N2 D  h0 X. |4 n* X8 e
  67.         //AHB不分频,即HCLK = 120M
    - D8 n4 K: d! m/ P9 K: N
  68.         //APB1 4分频,即fpclk1 = 120/4=30M1 D# c" z, z; f: {* j
  69.         //APB2 2分频,即fpclk2 = 120/2=60M9 e- j& ?5 Z% i: a- \; V# R

  70. 5 M4 [- I. B0 J! ~2 @9 i- \0 i
  71.     /* Wait till the main PLL is used as system clock source */. A& F2 J( w; D1 t6 K- \4 V
  72.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);7 Q1 w# b; U2 R9 \: {$ w
  73.     {
    ; R. q4 C4 a9 j3 J
  74.     }5 [/ u% |( l2 o! `+ R$ }4 O% p. H
  75.   }# w6 Q( P' ^6 v$ G4 O5 `
  76.   else3 P& |* h/ Z, L, B( E7 c
  77.   { /* If HSE fails to start-up, the application will have wrong clock7 \9 y% @0 b( g8 J! ^
  78.          configuration. User can add here some code to deal with this error */% ^! R, q; `0 Z' S/ X4 S/ c
  79.   }
    ( [" K5 q3 M( K+ b+ g  B6 }, T/ H

  80. : Z- W9 I' w+ S# U' r
  81. }
复制代码

6 B: w: a- C0 J

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

总结:

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

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

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


$ c5 R! r+ f+ O( ^, E" Z  u- S+ J0 m1 k& O
% u0 D; u3 n+ W
0 }8 M& n7 h4 |0 w5 F
收藏 评论0 发布时间:2021-12-2 14:28

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版