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

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

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


" I' \/ I7 M1 w2 f* |

301052464747191.jpg

" j9 E# D% ^# B1 ~5 s7 ]

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

  1. ; Reset handlerReset_Handler    PROC
    - l1 h3 ]8 P% w% M
  2.                  EXPORT  Reset_Handler             [WEAK]
    : |) w& w: ]# N
  3.         IMPORT  SystemInit# n, `( `/ M4 n  Z
  4.         IMPORT  __main
    % ?; |% O- `. r: x, l2 m
  5.                  LDR     R0, =SystemInit( m; k  ~5 _" L( W+ D
  6.                  BLX     R0. n: [& T1 h0 h
  7.                  LDR     R0, =__main
    $ [! c; w- _5 [) }  _6 _
  8.                  BX      R0
    + @3 r8 @, Y) x1 m
  9.                  ENDP
复制代码

6 D4 h7 `: u- l

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

$ \4 V' Q7 N, G* {/ ]3 ~! W* \

  1. void SystemInit(void)
    ( A: I  z. l6 _  a( T  z# J& v
  2. {9 q' K( q+ U2 I4 n6 C' K$ S& {" w6 _6 c
  3.   /* Reset the RCC clock configuration to the default reset state ------------*/
    - [! U8 h7 r0 Y) m" i
  4.   /* Set HSION bit */
    8 H5 ^6 J# q0 d- f0 |8 |6 ]
  5.   RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ
    , N* P9 ^/ L4 J9 f$ S

  6. * w% y& @2 Y' A; |) J/ K
  7.   /* Reset CFGR register */
    0 r9 @" D, H, K. k1 g6 }8 j
  8.   RCC->CFGR = 0x00000000;    //通过开关SW选择内部高速时钟作为系统时钟16MHZ
    , W# ^* a1 }4 S/ b1 ?. i: l
  9.                                                         //AHB prescaler 不分频1 w7 W6 @1 E# h- i
  10.                                                       //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ0 s8 A$ [" M7 `* l' G+ L' ]# x
  11.                                                         //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ! `' N, I) `! y+ G* s! M  a: h
  12.                               //MCO1和MCO2时钟输出等配置可参考用户手册Page95# [  H7 K4 d7 C& e

  13. # o$ y2 J! i! w0 I
  14.   /* Reset HSEON, CSSON and PLLON bits */
    8 u- _) B4 ?: ~' T  _; E, j5 B6 z! V
  15.   RCC->CR &= (uint32_t)0xFEF6FFFF;) w; s' I8 ~: l. R; D
  16. 0 k9 \- R; n. m5 \  K1 C' g
  17.   /* Reset PLLCFGR register */
    0 @5 x. T! Y9 u& Y* a
  18.   RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_3010
    3 ?% A; ^( }* x5 m7 I

  19. 1 R1 Y$ H8 i2 o8 P9 q
  20.   /* Reset HSEBYP bit */( K7 L1 O+ `3 J( I
  21.   RCC->CR &= (uint32_t)0xFFFBFFFF;  //对bit18 HSEBYP 设置为0,外部高速时钟被禁止1 z" U' U$ W0 G1 t' X  B: w/ x

  22. 5 F# y# {0 @& m# T
  23.   /* Disable all interrupts */
    7 |+ r# S! X! D( `9 a
  24.   RCC->CIR = 0x00000000;  //所有时钟中断都被禁止
    1 s5 c! `+ s$ u3 x

  25. . J4 m8 m' w: `! h1 s' k9 U
  26. #ifdef DATA_IN_ExtSRAM5 T# U# m( r5 o& z& [7 ^
  27.   SystemInit_ExtMemCtl(); / S( h' C$ w; `, W! o& e
  28. #endif /* DATA_IN_ExtSRAM */$ e  w, j8 u7 _2 u( w5 H
  29.          
    9 z4 `/ q) F7 x6 o
  30.   /* Configure the System clock source, PLL Multiplier and Divider factors,   e$ v0 p- G% E& q* c+ c
  31.      AHB/APBx prescalers and Flash settings ----------------------------------*/
    5 I# H3 k0 A- V
  32.   SetSysClock();$ ], x5 S/ D6 H8 k+ W! q

  33. ) y) i. E7 x3 s. G' l% U
  34.   /* Configure the Vector Table location add offset address ------------------*/
    ' m) l* I. M" G2 G9 [' }* J- s
  35. #ifdef VECT_TAB_SRAM# i4 v; o! C; Z/ l  m/ h
  36.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */0 P: [8 Q3 a+ o
  37. #else
    9 R, g! `4 j1 A
  38.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
    % ?" h5 j( k  d
  39. #endif8 z$ t7 K! g2 I  g
  40. }
复制代码


, s0 t% h8 d% f( t" N5 M

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

  1. static void SetSysClock(void)
    * `. t7 s& ^4 _$ S, s/ w- ^% c
  2. {
    . a# I* r: q  I6 S9 ^7 s/ m
  3. /******************************************************************************/
    ( n# I) m7 c( J
  4. /*            PLL (clocked by HSE) used as System clock source                */4 \; L$ ?6 Y6 U2 `% M8 Y+ [1 r9 D
  5. /******************************************************************************/8 X% C' S' G6 }# }/ L2 b/ E
  6.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;0 z4 w2 a$ f1 E6 D
  7.   
    8 Q  @' e& B& l
  8.   /* Enable HSE */& F2 ]; g( U. U: J: z2 u0 O
  9.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);  //外部高速时钟使能,25MHZ8 d1 D: B' ~) d1 o% p. M

  10. + ~2 e1 c4 ]6 j7 I4 n9 [3 x3 o
  11.   /* Wait till HSE is ready and if Time out is reached exit */  //外部时钟使能后,得需要一点时间到达各个端口' |# @2 v5 K8 S& W" o
  12.   do
    3 [  n6 x% _0 z6 ^% q' x
  13.   {
    % F4 l! w% c, E7 w/ [( O
  14.     HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好% R  l; |$ r  A" ]8 p  E# q2 T
  15.     StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时
    + B# n  T. T" \/ R
  16.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));: K9 o; U6 P/ Y7 }6 l7 r5 k: U0 Z( A

  17. " n+ f& t, X8 D( {3 H
  18.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的
    ) H# J! t8 j) X- ?% I, Z
  19.   {
    8 M4 Z( b" t# }3 Y& I; {
  20.     HSEStatus = (uint32_t)0x01;   //说明时钟已准备好了,才结束do whlie循环( z, y  j4 H& d/ e4 a
  21.   }
    1 g0 c# _5 H5 Y0 U3 @& s3 N* P3 ^
  22.   else5 t% i* q6 `: f# e$ r' l4 g& N
  23.   {
    * k6 |, M+ T! l; Y* x, d" m3 e
  24.     HSEStatus = (uint32_t)0x00;  //说明是因为超时了而退出do while循环  Z! u0 o( v- `6 z1 j  {
  25.   }
    ! v0 c/ D' a- r8 B3 a& d

  26. 8 U5 B) x4 s- \* o: o
  27.   if (HSEStatus == (uint32_t)0x01)
    / k+ z7 _5 ?7 v
  28.   {+ C/ o' y& b9 o. S% L3 ?
  29.     /* HCLK = SYSCLK / 1*/5 Q! R+ H+ b2 A# E0 Z# m2 c
  30.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M) e+ Q% [0 Y) F4 }$ M
  31.       - N. W# q. `3 g  H
  32.     /* PCLK2 = HCLK / 2*/  D) Z0 s- S1 @* E7 G" @
  33.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M
    1 Y5 M9 {+ l  J1 \6 o
  34.    
    7 o" Q+ u; n: ]5 d: {! y5 U  m
  35.     /* PCLK1 = HCLK / 4*/! F7 _8 `: }9 w% v/ j
  36.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M! ]' w  ~+ a# i5 t

  37. 5 ^; F/ s6 P/ e2 k7 e# e
  38.     /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置: O4 p- B  R' h8 R! |
  39.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    : ^, e+ o3 V0 k; v
  40.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
    ' `0 V; _9 W! q3 A( T6 A) @
  41. //配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能! y( M* g! r( _0 e& R: J
  42. //通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M' \" l9 W% W* M3 O& i- ]; ~, i
  43. //通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN
    5 K( j0 {' z9 B" B, X' \6 @9 C  Z
  44. //bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M
    : n+ N$ s7 C2 ~. h# v
  45. //bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M
    8 r* `, U1 I0 I; z6 m  @- [
  46. //bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M7 ?3 _& }. J# o. W) `% Y
  47.         
    & C5 p9 _# O  g9 I8 w. o
  48.     /* Enable the main PLL */
    ; {8 }; J4 e* P
  49.     RCC->CR |= RCC_CR_PLLON; //使能PLL
    4 `2 L; i( _! K, ?: F% Y6 R

  50. . G( _. J4 i) |3 o, W
  51.     /* Wait till the main PLL is ready */; }4 f; A. p2 a/ \2 r% D# u
  52.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
      L) r/ s. G$ i' x* B# ?; d
  53.     {. {7 R" t: M+ N. b3 f
  54.     }# s% o0 T2 t: t- A1 t* D3 ~
  55.         //到这里RCC->CR已配置完,最终值0x03036783
    " i9 C* T+ x5 A* L
  56.         //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启0 K8 J4 f8 k! l: r3 b" ?
  57.         % _7 i+ Y6 U% |9 Y! z) Y# h
  58.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    9 U( t6 ~6 T; z" X
  59.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;
    4 d! a5 d- m: s# q
  60. 4 E  p0 Y/ x  D3 d6 Q& m6 @6 `
  61.     /* Select the main PLL as system clock source */
    . {0 M% G! i! j* C
  62.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    , W1 @6 a# X+ K: @9 l" \
  63.     RCC->CFGR |= RCC_CFGR_SW_PLL;$ ~+ y$ \  h2 M
  64.         
    2 A7 u4 V' }5 [5 ]: q* a
  65.         //到这里RCC->CFGR已配置完,最终值是0x0000_940A
    9 Q7 h0 |, ^! x! o
  66.         //通过查看用户手册,知道,PLL时钟作为系统时钟即120M
    4 q; r' m' s- u' ^4 \0 Q* D
  67.         //AHB不分频,即HCLK = 120M& ]1 M0 \: U. X* l# N% R: t; @
  68.         //APB1 4分频,即fpclk1 = 120/4=30M' J# e" ?' Q' O: l% D% L
  69.         //APB2 2分频,即fpclk2 = 120/2=60M
    2 t! w$ ]6 ^" C/ r8 ~
  70. 4 Q- ^& {1 [7 K# _& h/ L' X# d
  71.     /* Wait till the main PLL is used as system clock source */
    * `1 ^6 [0 P: M/ w0 i% S: l
  72.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);+ y2 f: Z3 u* C. N6 W# X
  73.     {: R8 T0 J) E- ]2 e
  74.     }
    - _" _# Q8 D3 Q8 _- A
  75.   }
    * M, T, o5 z  i! |8 i, k3 b
  76.   else) v1 ?* ^1 c8 i1 k5 w
  77.   { /* If HSE fails to start-up, the application will have wrong clock
    1 I. L0 n7 M( p9 h$ w- v/ L0 }
  78.          configuration. User can add here some code to deal with this error */4 f( X& S4 H' g1 N3 `) W$ h
  79.   }
    7 C4 x2 Y( r! Q
  80. ! I" P  z! a! f9 Q
  81. }
复制代码


. }+ \3 Y' V# R

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

总结:

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

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

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

5 y6 ~: L# E5 o+ T1 y9 j

5 R. R% h2 _$ k6 y
' A2 e6 l' f) H3 J4 s* h9 k" Z- H- `7 I
收藏 评论0 发布时间:2021-12-2 14:28

举报

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