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

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

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


1 r  L/ M5 p3 X  T+ T% w; p: P. a

301052464747191.jpg


6 ?& I: e2 n' h# z- M+ N" G! r

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

  1. ; Reset handlerReset_Handler    PROC
    / ]% B# G* C# F3 G
  2.                  EXPORT  Reset_Handler             [WEAK]
    5 Z; M: L& Q2 c2 p( i
  3.         IMPORT  SystemInit
    1 h4 V2 s" Y& `9 A% v
  4.         IMPORT  __main% |- o! [  U) l' p$ Z
  5.                  LDR     R0, =SystemInit3 a4 H6 Q" A2 I% Q
  6.                  BLX     R0
    % t: @7 g, u* Z5 Q9 d) o$ D3 K8 |1 \
  7.                  LDR     R0, =__main4 f% y# O, r: N; d
  8.                  BX      R09 O6 A& b) D" O% w) J
  9.                  ENDP
复制代码

0 q7 k* W* d/ Q

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

& e# z+ v$ C0 P: _5 A

  1. void SystemInit(void)  W( E' c5 E  r" w0 L! F
  2. {4 B' M, ~: L& f4 {* G1 L- E/ i
  3.   /* Reset the RCC clock configuration to the default reset state ------------*/
    ; w1 X, x* Y# _. f3 a7 x; l
  4.   /* Set HSION bit */
    ! E! ^/ S! T0 P, S, j& M) x
  5.   RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ
    * P5 b' a4 J- U
  6. / `/ Y7 ~: E+ E- x. s, U
  7.   /* Reset CFGR register */# q  Q: g( }7 c. e: F% D9 s. g
  8.   RCC->CFGR = 0x00000000;    //通过开关SW选择内部高速时钟作为系统时钟16MHZ
    - C, S8 k3 [+ I, r! `2 R, [
  9.                                                         //AHB prescaler 不分频5 k! N$ {, t; l: ]" R. z
  10.                                                       //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ
    0 D( o* m, A& ?6 B. e
  11.                                                         //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ
    7 K/ R% p: c2 I3 P& G
  12.                               //MCO1和MCO2时钟输出等配置可参考用户手册Page95
    7 i( K; v% L$ ~, q& h& e* \. a
  13.   K! M: K- @1 H) x4 z
  14.   /* Reset HSEON, CSSON and PLLON bits */' G8 w. O' Z0 i4 @- A: b
  15.   RCC->CR &= (uint32_t)0xFEF6FFFF;
    " b( _' E  P2 A6 `
  16. 1 F) l* i% O# d# w3 O6 M3 B0 x
  17.   /* Reset PLLCFGR register */% j3 m8 s/ v! R% ^0 o
  18.   RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_3010( l/ \/ B. N8 ?5 |0 z' C

  19. # O/ g/ U1 z( O$ {% V6 S4 |
  20.   /* Reset HSEBYP bit */. M$ a% K7 {0 k+ B3 v
  21.   RCC->CR &= (uint32_t)0xFFFBFFFF;  //对bit18 HSEBYP 设置为0,外部高速时钟被禁止
    7 v& o5 n, B9 v/ b- ~
  22. 4 ?: d' e4 ?( _0 @
  23.   /* Disable all interrupts */! X1 E3 ~3 D; J/ m. l2 h
  24.   RCC->CIR = 0x00000000;  //所有时钟中断都被禁止  k1 M( X0 ~5 b
  25. * O7 N6 x- J  |% @
  26. #ifdef DATA_IN_ExtSRAM
    4 \- q3 U- }/ |7 _5 S7 L
  27.   SystemInit_ExtMemCtl(); 6 M8 @# {/ o. e8 Y* g3 \8 l' x
  28. #endif /* DATA_IN_ExtSRAM */
    0 L' R  @( s5 h. `7 n. w
  29.          3 U3 L6 u, |. ]* H) R  G
  30.   /* Configure the System clock source, PLL Multiplier and Divider factors, - w  o0 n" Y2 }# S) w
  31.      AHB/APBx prescalers and Flash settings ----------------------------------*/3 R3 s. v, z( m: O- z
  32.   SetSysClock();
    7 f/ |4 F( u, [& U
  33. . C3 H$ J8 K; Y6 P$ t
  34.   /* Configure the Vector Table location add offset address ------------------*/
    0 ]0 W/ K5 ]5 w8 B; a; C! R9 n
  35. #ifdef VECT_TAB_SRAM+ {" @8 v/ r( ~
  36.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */' z% ]3 c$ E$ x4 N
  37. #else' V, ?2 \$ @& H- t/ n
  38.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
    1 Y8 n' D5 ?$ y% d
  39. #endif
    7 t. `/ k- O9 f! U. p
  40. }
复制代码

, ~* R' `# D- y. ]# a8 r7 T3 z

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

  1. static void SetSysClock(void)6 ^3 p- e: F4 @7 _& Q
  2. {
    ! ~( i, s6 M# B+ Q
  3. /******************************************************************************/! Y. V- Z* Q" \/ X* |; M+ i% k
  4. /*            PLL (clocked by HSE) used as System clock source                */, K2 z) {# e+ {4 }
  5. /******************************************************************************/6 a5 V3 a9 E6 }# g: @2 a5 N8 L
  6.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;6 a$ w) I1 p  W  J" ~8 S' j! U3 ^5 B
  7.     M, [" H$ W* B6 {
  8.   /* Enable HSE */
    ( @- L) ?8 {8 B' `; A+ R* F
  9.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);  //外部高速时钟使能,25MHZ; z* |: Q" ~) N- e4 R

  10. # P9 r' i: G! B- a2 n- ]/ E( B7 z: {0 \
  11.   /* Wait till HSE is ready and if Time out is reached exit */  //外部时钟使能后,得需要一点时间到达各个端口3 `( t$ N; x) t
  12.   do
    0 H) E# }, A4 }% V2 S. m
  13.   {
    0 {4 B) k6 k! X5 [  z% W
  14.     HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好: z3 c( A/ g- ~  i! s' ~" T
  15.     StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时
    $ ?* D( L* N3 D
  16.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));$ y; }" p+ v7 W; g; V- |" ]

  17. 2 n& K" a, a) E) R, C7 l
  18.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的
    , L2 I. z$ U2 C
  19.   {6 g) Q/ U2 k" }5 A. K/ s
  20.     HSEStatus = (uint32_t)0x01;   //说明时钟已准备好了,才结束do whlie循环3 b# k( r) l# ?1 Z. {
  21.   }
    : G4 }3 P+ e, V0 n
  22.   else
    - B$ r- v& c- t+ y
  23.   {
    ) ^* ~$ k6 \% f5 B/ ]4 ~
  24.     HSEStatus = (uint32_t)0x00;  //说明是因为超时了而退出do while循环
    ' h/ m, g% J* g7 ?& J' C0 \' G, ]: x
  25.   }
    $ u. f/ C0 _( i: D" F: w6 m

  26. 5 x0 @9 B" h- g7 C4 Y
  27.   if (HSEStatus == (uint32_t)0x01)
    % {# p, o% `/ G+ O
  28.   {
    : m$ O: w2 W! s& N9 F" ^
  29.     /* HCLK = SYSCLK / 1*/+ j1 _8 ]7 m6 N/ k5 C, g" N( m
  30.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M
    / l+ C$ Y6 W/ k* o9 \; ?3 a" F0 |
  31.       
    ; p2 g0 |- H% w. i
  32.     /* PCLK2 = HCLK / 2*/
    $ J7 o! z) F! P, W. ]8 C$ Y  D
  33.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M
    ' p7 i6 J. E; Y' t# |
  34.     : l7 s0 `6 m! ^) J+ F
  35.     /* PCLK1 = HCLK / 4*/
    & P4 c$ h5 F) v2 C) m
  36.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M
    8 }5 u1 b7 w* o7 L8 }: H7 k
  37. ; o( ?9 `" s2 N
  38.     /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置! C/ ~9 J# ], }* {# t: m) E6 O& L9 e
  39.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |$ X  s) f6 T2 @6 Z) m4 k; q
  40.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);: s6 s/ z, F; w; j" k8 n4 J
  41. //配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能
    1 |7 M% ^% R: r* E) b$ s
  42. //通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M: ^7 |$ z( M1 T6 ~
  43. //通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN1 c* M7 p6 S) ^8 }, K& M
  44. //bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M. y, j3 E: S4 [. `4 ^
  45. //bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M
      \# r; R* Y& ^6 z9 X$ b& ?
  46. //bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M
    9 S, c6 y* d$ s( M+ M" Z" h1 }& }
  47.         
    ) m7 v$ g; ~% p+ v- r8 @
  48.     /* Enable the main PLL */. X  h5 {# s8 n
  49.     RCC->CR |= RCC_CR_PLLON; //使能PLL
    ! x; B' S, t& {/ S4 {. A: E% g# g
  50. / j& Y9 I8 r  i  i  U
  51.     /* Wait till the main PLL is ready */
    $ F! k9 }: Z( R  A- I+ ?" H: E; h9 l
  52.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    . T1 |& I7 Z5 Y5 }
  53.     {
    6 z9 i. v: F0 u/ M% s2 F# x$ u
  54.     }
    4 z- u$ Q8 A  V$ P$ L9 J
  55.         //到这里RCC->CR已配置完,最终值0x03036783& |9 s9 m. _) i7 @
  56.         //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启9 b* o% B* }  P2 ~* d  b# F* X
  57.         
    ) D! r- w) R& B, b! a
  58.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */) i6 S. f& N% V- a# R* v. s6 e
  59.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;
    ' `/ ^5 ~# w2 z& l  L3 T/ d0 y3 k1 ?
  60. - p2 M+ @0 {7 M: |
  61.     /* Select the main PLL as system clock source */
    2 q) U4 C0 s3 V' R
  62.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    5 c  s  M* {- S1 i
  63.     RCC->CFGR |= RCC_CFGR_SW_PLL;2 t' s, S+ h, ^& B6 s
  64.         
      e. `- A- _1 v! w  d% I$ l& Q
  65.         //到这里RCC->CFGR已配置完,最终值是0x0000_940A" e8 X, h& R! ~! D
  66.         //通过查看用户手册,知道,PLL时钟作为系统时钟即120M% Z  Q/ C: M% y$ u
  67.         //AHB不分频,即HCLK = 120M
    ) G4 o8 g' z5 m. C5 F6 Z5 u3 p7 C
  68.         //APB1 4分频,即fpclk1 = 120/4=30M
    5 }3 L! D- M, _3 G
  69.         //APB2 2分频,即fpclk2 = 120/2=60M
    ' M+ r* F6 z/ y: O
  70. $ G$ p" @3 U/ _" h
  71.     /* Wait till the main PLL is used as system clock source */0 A# o1 X2 ?" R! g, L/ v# K: g, f' t
  72.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);# t8 O% E; X, F* }9 j
  73.     {
    ) {+ R' i8 m' J4 ?
  74.     }1 ]$ ^8 `) W: ?
  75.   }
    + U5 l* A7 k; h  B+ u5 Z
  76.   else/ N4 |) J. `( Z
  77.   { /* If HSE fails to start-up, the application will have wrong clock; G/ Z! S. h. x
  78.          configuration. User can add here some code to deal with this error */0 Q9 {( J2 }* T4 ]$ a9 {( W
  79.   }. Q3 w/ Q1 v  \
  80. 3 ~. [5 v9 ?: k5 j! k  _" Q. C
  81. }
复制代码

- r6 n, k7 |% N8 E" x

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

总结:

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

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

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

" k- H! i9 ^6 B
' A; s3 x. s9 O- U. ^
' f5 J: E+ l* E- f) T3 I
2 ^4 f' J% [4 Z5 g! V# I
收藏 评论0 发布时间:2021-12-2 14:28

举报

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