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

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

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


! k0 e/ b3 L7 ~% [" @

301052464747191.jpg

# K) \; h  o3 L5 l# y8 c7 n  M

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

  1. ; Reset handlerReset_Handler    PROC; d4 U  ]; t. A+ \1 E/ {- H/ v5 S
  2.                  EXPORT  Reset_Handler             [WEAK]
    + `8 s# J+ M* ?
  3.         IMPORT  SystemInit3 D# [1 t/ I  B! Z
  4.         IMPORT  __main" F& }) f" |$ A$ }3 D
  5.                  LDR     R0, =SystemInit
    - b# q. Z3 l, P( z9 o
  6.                  BLX     R0
    0 d$ `( i' j& S/ {. ?
  7.                  LDR     R0, =__main
    ) P( B: ^4 N4 [: `
  8.                  BX      R0
    $ p5 X  n9 B& ^0 v8 B
  9.                  ENDP
复制代码

( Z; s  T& r4 f0 V# f7 ^+ S: b, K! W

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

# J! [% m! Y- ]# M

  1. void SystemInit(void)
    4 B. D& s' d: q* h( [; Z" a& Y1 a
  2. {* D9 b+ P4 N4 q
  3.   /* Reset the RCC clock configuration to the default reset state ------------*/$ @  {! ]- E+ f/ _, m
  4.   /* Set HSION bit */
    & k7 x  \* l. [9 d& R: J! @. h: H
  5.   RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ
    # Q' G' _# i4 N
  6. 9 G# E% F2 [, x9 ?# J; g
  7.   /* Reset CFGR register */# ^1 ~# w6 Z, d0 H" _& q" ~- z" U
  8.   RCC->CFGR = 0x00000000;    //通过开关SW选择内部高速时钟作为系统时钟16MHZ6 z# L5 w/ A; L
  9.                                                         //AHB prescaler 不分频
    % d4 `4 |1 g! b) H7 \+ Y
  10.                                                       //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ7 V' n. o5 M, W& a1 i9 U% w$ w
  11.                                                         //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ8 n1 }8 T* r- y+ K" @
  12.                               //MCO1和MCO2时钟输出等配置可参考用户手册Page95+ \4 D- t# x  y% ~7 C
  13. 7 i- I* o" q& c  e0 a3 [
  14.   /* Reset HSEON, CSSON and PLLON bits */
    0 p. n  w! V# V. v- b' `' g" }
  15.   RCC->CR &= (uint32_t)0xFEF6FFFF;
    % p0 D: v0 a! q( j0 f# g6 E3 d# T
  16. 4 U$ @7 _( \% |8 J% D, W3 u
  17.   /* Reset PLLCFGR register */9 ]2 C1 ?, g0 s0 U
  18.   RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_3010" g' |, P& C9 e# ~& `
  19. & m* J0 S& R7 F. ^1 a5 Z# g
  20.   /* Reset HSEBYP bit */3 y3 m5 x# q- ~- q
  21.   RCC->CR &= (uint32_t)0xFFFBFFFF;  //对bit18 HSEBYP 设置为0,外部高速时钟被禁止( a( G; q+ \- d0 ]
  22. 6 A3 T% w5 o6 i
  23.   /* Disable all interrupts */
    ' ~2 ^& m5 _! X5 @- g
  24.   RCC->CIR = 0x00000000;  //所有时钟中断都被禁止" `8 R1 v4 q! H

  25. 3 n/ e, I' d( _) l
  26. #ifdef DATA_IN_ExtSRAM
    % C3 w+ j8 g7 F1 U" r3 x
  27.   SystemInit_ExtMemCtl();
    ! i5 X( x- j2 ~- \0 g4 ^* ]3 J8 `" P
  28. #endif /* DATA_IN_ExtSRAM */$ _6 z% p$ _3 A; }
  29.          6 H1 Z% U) T/ {0 r1 A
  30.   /* Configure the System clock source, PLL Multiplier and Divider factors, " ~6 z0 w4 U- g
  31.      AHB/APBx prescalers and Flash settings ----------------------------------*/
    0 Z) }1 C) S- ~* T/ I. j
  32.   SetSysClock();1 p6 c( M* ]( l, p
  33. + M- k  J' b) H
  34.   /* Configure the Vector Table location add offset address ------------------*/, u$ a. l- @* z$ Q$ ?  D5 L) T$ {
  35. #ifdef VECT_TAB_SRAM
    2 a) o8 H& V" L# z
  36.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM *// P. B) {' |9 i1 {7 e: W% [! t
  37. #else
    , I# Y% h% {9 J! s
  38.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
    8 `* C5 Z7 H5 B
  39. #endif* N% _) F" a3 c
  40. }
复制代码


) }- Q5 S* [2 v9 _) U. T+ v  X

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

  1. static void SetSysClock(void)
    $ ?  a7 ^+ U9 {. `. ~5 ~
  2. {
    ; z" i1 N4 R. b7 |- K
  3. /******************************************************************************/
    & \8 ^; Z% L. u4 P3 Q. L$ e
  4. /*            PLL (clocked by HSE) used as System clock source                */1 I2 p9 ^5 b* ?& t# B
  5. /******************************************************************************/8 \# y" r: F3 t4 v; l* d2 X4 u
  6.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    + i/ @* K1 G3 R( F3 _* B  ~
  7.   
    / C% e/ J: M. `- C  ^
  8.   /* Enable HSE */, L3 v: S! p- l$ J+ h
  9.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);  //外部高速时钟使能,25MHZ7 t2 ~6 U2 t' v5 \" F( A

  10. 0 j. E' ^% t) u* f' ~- v4 X
  11.   /* Wait till HSE is ready and if Time out is reached exit */  //外部时钟使能后,得需要一点时间到达各个端口
    8 K8 N8 P  f# j/ v( m. y6 f& B; ^
  12.   do7 `& ~" J7 U% U, P
  13.   {
    - t2 e+ F0 J2 H7 [6 s
  14.     HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好
    / D6 p% k9 A. J9 P
  15.     StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时0 G- ^# y# t, [. C  q, Q0 j
  16.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    ; O- D5 M1 S' T4 h
  17. 1 d/ P$ S9 g  l4 Y$ o/ V, f: v' h
  18.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的" g& ?7 d1 L" H2 T5 ?; H6 k0 v
  19.   {
    7 w( w5 f9 k6 R; c" g: [# `1 M
  20.     HSEStatus = (uint32_t)0x01;   //说明时钟已准备好了,才结束do whlie循环
    * F2 Z6 k  F8 A- ]. z4 e# R9 a8 X
  21.   }
    3 z- C! B/ D+ o/ @) C6 R, p  H
  22.   else; s7 r4 S  m( s% k0 m( f9 i( i
  23.   {5 h8 |* E- v- Q  h. L; @, ?
  24.     HSEStatus = (uint32_t)0x00;  //说明是因为超时了而退出do while循环
      |& R& [  U0 s0 A6 a! p
  25.   }4 r. P# W" F8 S5 Y4 r
  26. 4 Y8 x& u" p6 S- a3 t$ G
  27.   if (HSEStatus == (uint32_t)0x01)
    7 ?9 Z# G5 Y, L, `+ n; F7 V
  28.   {
    - e8 n: p5 w2 g9 B1 p
  29.     /* HCLK = SYSCLK / 1*/
    : T  u7 _6 u) E
  30.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M
    3 Y7 t# f7 ]0 F7 y2 i% x
  31.       + n: o  S4 i! z% M- G4 }# D
  32.     /* PCLK2 = HCLK / 2*/
    $ b9 t5 u8 N. A+ R% [
  33.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M! l/ v' g. N6 X9 H' H2 z1 u
  34.     0 k, v+ g& b; H. a! b0 A
  35.     /* PCLK1 = HCLK / 4*/, x2 p7 ~, d/ S) {, S3 U  H1 j: _
  36.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M5 w( V& B' D" h) j- _

  37. * f8 _# Q- L$ R6 F" P
  38.     /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置
    - D) ^( b6 U) I* t* \9 R6 f
  39.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    : V5 _3 J5 c5 ~3 l: U
  40.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);5 h, C% j' R# @; L; [7 W* {
  41. //配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能6 T; D6 K) J6 ^! l8 z% D
  42. //通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M
    / j: B6 M8 K( }9 o
  43. //通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN* \- ~7 O) B; g% ^
  44. //bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M
    & i+ k& t; {0 d) V! y1 q3 i2 W7 {7 n
  45. //bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M" W6 f7 d+ M. T8 A1 W% t/ w. D  Q
  46. //bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M
      O( R8 X8 g$ q7 ^& q; V; e; _
  47.         ) c4 {7 U* q5 ]* f9 y
  48.     /* Enable the main PLL */
    1 Z- G# [% g6 r6 ~+ B
  49.     RCC->CR |= RCC_CR_PLLON; //使能PLL* i3 G- t- g# w  i

  50. / ]% r! q+ T' V/ S
  51.     /* Wait till the main PLL is ready */$ J  ^! v* B' p
  52.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    * m/ h/ v$ k/ B# L. r. o: n
  53.     {
    0 y" }7 y. x. M/ E) c9 n1 o
  54.     }
    1 J7 Z7 z* C; i: ]  Q
  55.         //到这里RCC->CR已配置完,最终值0x03036783
    1 b& ~; J# t' Z- O3 ~! i, L/ `
  56.         //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启( j* X& e9 `; [3 g1 W- x4 [
  57.         ) |$ M% U# g; n  ~' T% A: [
  58.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */" p; x. j3 l& M! |9 x0 Q, u
  59.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;- W: x* _; I0 N4 X3 Q2 p- M" `) N% L

  60. : u" Z2 v, i" g. ~3 |: Q+ D
  61.     /* Select the main PLL as system clock source */9 D7 p% s! n8 K% K
  62.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));. T$ m  _  d% Q" ]( N8 a2 @/ |6 s
  63.     RCC->CFGR |= RCC_CFGR_SW_PLL;
    3 U* D9 q; }7 g+ F7 L  W
  64.         
    ) B9 T0 C- w* a0 f  g$ k
  65.         //到这里RCC->CFGR已配置完,最终值是0x0000_940A$ P# s9 Y9 @! q; ?( @& s
  66.         //通过查看用户手册,知道,PLL时钟作为系统时钟即120M# U6 ]" _& w% y5 L% s
  67.         //AHB不分频,即HCLK = 120M
      B" `: [1 l' K; ^  r7 W
  68.         //APB1 4分频,即fpclk1 = 120/4=30M" ^7 G- Q0 B2 L+ d7 o
  69.         //APB2 2分频,即fpclk2 = 120/2=60M4 M% t& C4 q" i2 h; O0 F7 @9 k2 B. ?

  70. - S9 v9 \. R. }* p, r  m
  71.     /* Wait till the main PLL is used as system clock source */
    6 E1 ^7 Q1 i' v
  72.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);. j' R9 f. s# c4 i: R4 |% h3 [
  73.     {- y$ y' T' P* z
  74.     }8 l  l; O1 m7 ^3 S, N( p
  75.   }7 _$ X; W7 n- Y8 R8 E
  76.   else
    " }) x% C8 d. K2 W2 T& V
  77.   { /* If HSE fails to start-up, the application will have wrong clock
    - a/ f4 S- R9 S- b" Z3 s: e
  78.          configuration. User can add here some code to deal with this error */* ^5 Q( `% E5 j4 H
  79.   }$ B2 A& s/ }3 @1 i( g1 |8 \
  80.   C9 t5 p$ o/ M# }0 z
  81. }
复制代码


; G2 D; o) a" R- m. X; f8 c

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

总结:

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

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

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


; X- X' M2 R2 A, e1 m( l
+ j# V" v( }% a, b/ C! d+ V! G. U
, d; n+ C/ \9 \& ~1 E4 v' Y& t& n
收藏 评论0 发布时间:2021-12-2 14:28

举报

0个回答

所属标签

相似技术帖

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