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

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

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


+ q1 l' ^3 Z! J

301052464747191.jpg

" v5 x# X/ E% f

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

  1. ; Reset handlerReset_Handler    PROC+ ]5 h+ i* x5 g  u
  2.                  EXPORT  Reset_Handler             [WEAK]
    3 A  m# a' Y$ N; X8 e
  3.         IMPORT  SystemInit+ Y' _$ l# D7 k. q; b# ]7 m
  4.         IMPORT  __main
      x8 Z! T- ]; S: k8 r& d6 O4 P
  5.                  LDR     R0, =SystemInit# P- p: `3 f. k' {, h
  6.                  BLX     R0
    $ |. H7 f+ h' Y7 k- k% |
  7.                  LDR     R0, =__main; e0 k% f) x5 A7 K! f
  8.                  BX      R0
    6 f  D0 h- v3 v3 b
  9.                  ENDP
复制代码
: ~- b- c- F3 }/ s7 A  N

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

' R9 Q1 P# V% t1 A5 H$ T

  1. void SystemInit(void)/ ~6 j: @4 f, V0 y
  2. {
    : g# [: a7 ]9 p
  3.   /* Reset the RCC clock configuration to the default reset state ------------*/5 w& A7 q/ A: A& k5 T& u
  4.   /* Set HSION bit */
    5 `1 }( Q' s$ ?7 c6 s3 `  M% E5 F! B2 R
  5.   RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ
    : D  Z' _# a0 a; E+ H9 a
  6. 9 U' j, d( h. K- Q' A. O/ q
  7.   /* Reset CFGR register */
    , A. z5 y7 y5 U- M4 W# T
  8.   RCC->CFGR = 0x00000000;    //通过开关SW选择内部高速时钟作为系统时钟16MHZ1 Q9 T1 Z( d9 [
  9.                                                         //AHB prescaler 不分频
    3 n0 m) S. }0 ^" Q5 e, z
  10.                                                       //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ( A  B2 j/ i! o: x* B" m* M$ y4 _- ?
  11.                                                         //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ0 g8 L4 R8 t- d5 S) L4 G& J  R
  12.                               //MCO1和MCO2时钟输出等配置可参考用户手册Page95
    , s" b) l$ b6 X9 v9 Z' }5 [

  13. + `9 _6 d4 _9 k% ]
  14.   /* Reset HSEON, CSSON and PLLON bits */  {$ ?$ l0 Z2 K! ]+ d
  15.   RCC->CR &= (uint32_t)0xFEF6FFFF;: h( ~2 g7 A  \

  16. : J3 A# O. w' f9 l% }
  17.   /* Reset PLLCFGR register */
    + W, T" b2 {5 `7 l& ?
  18.   RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_3010, c+ @+ C& h. Y2 }# v+ r
  19. 0 s1 d3 j" ?/ y
  20.   /* Reset HSEBYP bit */
    7 ~# Y3 Q) q' M
  21.   RCC->CR &= (uint32_t)0xFFFBFFFF;  //对bit18 HSEBYP 设置为0,外部高速时钟被禁止
    & ?& ]' R" r% x2 }. Z6 S) l, a1 A7 o) V

  22. 0 |  I) u+ H' `( |
  23.   /* Disable all interrupts */, }  \4 y1 X4 A! p# V8 K+ H+ {5 T* B
  24.   RCC->CIR = 0x00000000;  //所有时钟中断都被禁止7 M' x& x1 l! E$ u

  25. ) N7 U0 O; a6 m1 ]" q& a
  26. #ifdef DATA_IN_ExtSRAM
      x8 \- P. k: o0 d4 s- ?
  27.   SystemInit_ExtMemCtl(); 8 S5 L! N: G& x8 r7 E1 t& Y
  28. #endif /* DATA_IN_ExtSRAM */7 _) m/ i& k, a1 ^) C
  29.          
    7 j6 U+ y/ I/ B$ `
  30.   /* Configure the System clock source, PLL Multiplier and Divider factors, ' K; [$ V3 s1 |2 m8 F4 C; p
  31.      AHB/APBx prescalers and Flash settings ----------------------------------*/
    ; i2 j! w+ V+ p
  32.   SetSysClock();" b/ r  @" e, z, Y) _3 L4 S8 q

  33. 6 ^9 o( B, j4 B* q5 n
  34.   /* Configure the Vector Table location add offset address ------------------*/
    8 I8 ^& J6 P. D! \5 t
  35. #ifdef VECT_TAB_SRAM
    4 t, K: N7 o8 p/ [
  36.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */- _$ L5 D: E, N: d# A
  37. #else
    $ l: [4 A0 j. b; G
  38.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */$ V: w$ v% K0 a; m3 j  }
  39. #endif
    , M9 r" c; a5 ~) R: E1 O: l% _1 y
  40. }
复制代码

6 q8 g) J1 C# [* H2 n0 B  X" o# v

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

  1. static void SetSysClock(void)* ~, c# T8 d; p9 x; W- k+ _
  2. {
    - l) D& ]6 Z2 ^" W
  3. /******************************************************************************/9 g0 l7 T+ W- ^
  4. /*            PLL (clocked by HSE) used as System clock source                *// Q. L: C+ Z/ U! h
  5. /******************************************************************************/6 }8 {; H! x, t' R" W& o0 s
  6.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    * ~2 t$ H6 K6 A* ^# N1 Q
  7.   $ @1 T" }) V7 r& F* o. m8 l! A& |# `
  8.   /* Enable HSE */* N/ H  R( v! H3 r4 B' ~4 r
  9.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);  //外部高速时钟使能,25MHZ* V, j0 R/ f' a( ^7 t. p, ?

  10. $ o: B7 l- [0 c4 A6 }7 L
  11.   /* Wait till HSE is ready and if Time out is reached exit */  //外部时钟使能后,得需要一点时间到达各个端口
    6 a; |. `% {. O5 l+ I
  12.   do0 \6 E7 k/ k! A' Z5 Q# p# }
  13.   {
    ( N9 r% s8 s4 q/ B1 Y
  14.     HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好
    & a. P' b& g5 }! y6 P, c$ c; T
  15.     StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时
    7 S& ?* s3 v( C* O# C4 X
  16.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    . R4 v4 G% n. S7 {% X4 r

  17. 4 R. A" W+ r- q; f0 P2 ?+ `- h! Q  H
  18.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的
    4 ~) Z' C, K3 s. w$ f; u
  19.   {
    " [2 I6 L& U" ~6 a! P: u, f
  20.     HSEStatus = (uint32_t)0x01;   //说明时钟已准备好了,才结束do whlie循环, z; ^9 Z# `/ J9 y/ T3 a* R
  21.   }3 N  }8 ]5 \% W/ E6 [) ]& }
  22.   else
    : {, L$ g% }7 o' e4 |9 E& r" P
  23.   {
    / w6 P$ B$ d) _. `, M
  24.     HSEStatus = (uint32_t)0x00;  //说明是因为超时了而退出do while循环# k% e, r5 I$ _
  25.   }; h! }8 C' t  ~$ _

  26. 8 j9 U) U- F- t# b; D5 ?- o4 F
  27.   if (HSEStatus == (uint32_t)0x01)" C$ Q3 O5 z9 W/ r% \
  28.   {) W* P) Y& I/ E5 J) Q
  29.     /* HCLK = SYSCLK / 1*/- W; x9 A+ E8 k4 M' v, ]
  30.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M
    * q! M: E% Y: w5 j; X
  31.       
    " Q* o0 U2 i% c0 D/ L  ]2 e
  32.     /* PCLK2 = HCLK / 2*/' u9 Q+ R. ]* \( e! Y
  33.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M
      I5 n: o% G1 k" A; L
  34.     % z5 {  p8 D, m5 U( x+ ]0 N
  35.     /* PCLK1 = HCLK / 4*/
    & _6 s$ J# w4 b4 v, S0 F
  36.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M: w3 F2 N5 W- P& E( j6 G
  37. 6 p* Y7 F' p: C6 z( J! F- Y
  38.     /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置+ _: Y0 V4 Y" h
  39.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |2 W: f7 h  ]( r" K; Z' N
  40.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
    1 ?) b3 c& P; {# Q) w( s1 g
  41. //配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能
    - X, q' }% i- o! K) {6 |
  42. //通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M
    " o' `! O" G" N
  43. //通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN
    . K# v: Y; J+ U; E# c
  44. //bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M
    : y; [  b1 ~3 d8 Q
  45. //bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M
    - G- d5 |/ v0 j$ [# L2 u+ k- g% h
  46. //bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M
    1 h% z( X2 K0 j6 m. g2 A
  47.         4 y; v6 W& Q. L% C" n/ Q
  48.     /* Enable the main PLL */1 J  M: A% m( `' A6 {! c
  49.     RCC->CR |= RCC_CR_PLLON; //使能PLL2 s& g+ V7 A% l/ B0 b6 }

  50. ( ~/ h" U6 c# h
  51.     /* Wait till the main PLL is ready */( I, |& o4 y4 N0 m- d
  52.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    ' k; W% R: V, \. t9 b
  53.     {
    3 |3 M1 r! W# _3 _+ ~& P
  54.     }
    % x! s1 n" W7 z& `: u
  55.         //到这里RCC->CR已配置完,最终值0x03036783$ b1 i3 D- d+ X- H+ _5 v
  56.         //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启
    : b: P) l$ j' W/ a( `7 l
  57.         ! D$ ], \) l' |
  58.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    ; x/ k( U0 ^% q+ R7 g9 H
  59.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;& E$ E3 B; V4 Z: }. g3 d' x

  60. % n) H) Q3 u4 Z
  61.     /* Select the main PLL as system clock source */
    5 g, w# h' I3 w7 k5 X% i6 [
  62.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));; \% W& j* R# U, V
  63.     RCC->CFGR |= RCC_CFGR_SW_PLL;
    - A% o/ i" ]9 Z1 X7 ]8 Y9 g4 o
  64.         
    : a  ?1 f- Y7 ^3 j8 [
  65.         //到这里RCC->CFGR已配置完,最终值是0x0000_940A" K3 h. [' O5 F4 ^+ ~1 m" s% L
  66.         //通过查看用户手册,知道,PLL时钟作为系统时钟即120M. H) X8 x; C2 ]: R* X0 p' o9 `
  67.         //AHB不分频,即HCLK = 120M9 @: A# v1 Z* D# h2 D
  68.         //APB1 4分频,即fpclk1 = 120/4=30M
      l2 j( _3 f* U/ V( R0 }# |
  69.         //APB2 2分频,即fpclk2 = 120/2=60M
    - ]- ~% F6 X5 f  Q- u: q  ^

  70. ; P. w# x+ f9 }7 P
  71.     /* Wait till the main PLL is used as system clock source */
    1 e  U1 `% b. T& p% }4 j  X4 ]
  72.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    2 H) F- J7 e7 @* H" o5 v
  73.     {2 L- ~! D  l) Y* i. V
  74.     }
    ' ^8 z2 o4 I, H, V' w. |% z5 B
  75.   }
    6 d  f- q  I2 T& r  c
  76.   else8 s6 @0 J6 |& D9 |
  77.   { /* If HSE fails to start-up, the application will have wrong clock* g& z' `6 Z# S4 h0 V$ Q
  78.          configuration. User can add here some code to deal with this error *// a. i6 e, q6 L0 y* F
  79.   }, F1 `1 a5 _# c, m( H$ N2 H
  80. ; E/ C. Z0 g4 i+ {' x8 C& }6 m
  81. }
复制代码

( {9 N  s3 _: f) I

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

总结:

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

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

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


) L; O! m" m: h2 F( Y- n3 I4 N/ b8 C* L3 c0 u/ |% R- b
# G8 X* g/ X, [7 \2 V% M% O4 s
$ K; k; j4 }' t; P  ^* |
收藏 评论0 发布时间:2021-12-2 14:28

举报

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