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

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

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


9 p! @8 r5 [  i' m

301052464747191.jpg

# z* t4 U+ w) j, Y1 k6 x

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

  1. ; Reset handlerReset_Handler    PROC
    0 b9 l% I, a% f: c4 u; E
  2.                  EXPORT  Reset_Handler             [WEAK]( v& g4 O. T( W" L/ k* @0 \
  3.         IMPORT  SystemInit- j7 d# |2 [1 t1 J+ I' ?
  4.         IMPORT  __main
    $ P) d. r, `+ D- Q+ |, [
  5.                  LDR     R0, =SystemInit& g& U) W" q# f' O& a2 q  ~5 Q4 }
  6.                  BLX     R0* J) ?* e6 {0 d- }5 b* j& W
  7.                  LDR     R0, =__main9 P9 P5 y6 S4 T5 T: P3 ^
  8.                  BX      R0  K9 F" w2 {3 W1 K3 S( q! i
  9.                  ENDP
复制代码
$ m) D# l+ l/ D4 g. X

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


2 [/ Y- Q* c9 {+ H- G' Q+ ]! G

  1. void SystemInit(void)$ o# P) I) ?# p& R0 a6 p$ b
  2. {* E% @- `" U' J  E% o# [
  3.   /* Reset the RCC clock configuration to the default reset state ------------*/
    3 H( T# c1 U1 l1 L
  4.   /* Set HSION bit */
    : Z. D8 r* ~+ x; p
  5.   RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ
    ) K0 i+ R! Y8 g* C7 j0 T7 J
  6. 6 R$ y( U$ t$ e( C6 A' w6 `
  7.   /* Reset CFGR register */
    / _- i( h- P( J9 M1 r3 K; D
  8.   RCC->CFGR = 0x00000000;    //通过开关SW选择内部高速时钟作为系统时钟16MHZ8 M* e/ e& F% h' n$ q+ o
  9.                                                         //AHB prescaler 不分频: L0 ]7 Y+ o4 q! @
  10.                                                       //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ
    0 `! q  Y( ]) @+ Y  G4 M: m
  11.                                                         //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ
    $ D8 c- \" G* K/ T  f
  12.                               //MCO1和MCO2时钟输出等配置可参考用户手册Page958 G5 i9 t, t& f/ f

  13. ! p( t% E0 t& y7 |) k' h+ T, r
  14.   /* Reset HSEON, CSSON and PLLON bits */
    + ]8 `" |0 v7 ?3 |  y
  15.   RCC->CR &= (uint32_t)0xFEF6FFFF;
    , R+ e" i/ s& B+ K9 C) F0 `

  16. * \. h, Z" u0 K: ]0 M5 W
  17.   /* Reset PLLCFGR register */' p1 q8 M) A& N
  18.   RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_3010% q. q' }# B* B* k0 U0 f- k

  19. ) X" _& u* K2 k/ K
  20.   /* Reset HSEBYP bit */
    9 P7 x% `3 O/ _: ~* i  w
  21.   RCC->CR &= (uint32_t)0xFFFBFFFF;  //对bit18 HSEBYP 设置为0,外部高速时钟被禁止; Q! Y8 G2 J+ P) F: q7 j) s! i
  22. 9 D3 f# `* v% W& b; O
  23.   /* Disable all interrupts */8 X( B% s" E9 U; R6 n4 G
  24.   RCC->CIR = 0x00000000;  //所有时钟中断都被禁止
    - m, \) P5 o% ~. s/ i
  25. % A2 h) ]( j/ y
  26. #ifdef DATA_IN_ExtSRAM
    ( q& Q. ]* _: E! L
  27.   SystemInit_ExtMemCtl(); 3 e# F  s; f0 n2 c7 D
  28. #endif /* DATA_IN_ExtSRAM */- T6 U2 x6 {* J$ S
  29.          
    1 L7 z# X, q0 y0 ~3 r
  30.   /* Configure the System clock source, PLL Multiplier and Divider factors,
    - l: J2 c7 [# F0 l! H
  31.      AHB/APBx prescalers and Flash settings ----------------------------------*/  J, l1 O1 S+ g" _/ ?- X
  32.   SetSysClock();# S" A+ Q0 ^, l: Z

  33. # B( T3 Z* }! {  v$ s
  34.   /* Configure the Vector Table location add offset address ------------------*/; U! |, W6 Q9 E0 q- r
  35. #ifdef VECT_TAB_SRAM+ y. S9 Y/ ^8 A5 Q! {  }5 x; v7 n
  36.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
    " g. t5 x. B$ W1 e
  37. #else
    5 X) ^) s3 l8 X
  38.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */4 X' s4 R  i( U/ P0 H5 C
  39. #endif
    / ?( x% C( z% w: s
  40. }
复制代码


" g' l1 ?) q, A- z

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

  1. static void SetSysClock(void)' @) G  `/ n$ N; w: F, C
  2. {
    2 R% q- Z2 V& J+ |1 o8 r% I
  3. /******************************************************************************/
      U* l' B5 ?5 e  y& `) s! h
  4. /*            PLL (clocked by HSE) used as System clock source                */
    " h/ |. Y; g+ P. F  V
  5. /******************************************************************************// D. r% W5 z" k6 H2 i) }; e
  6.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;, O4 }8 r3 j, P9 N* y
  7.   
    $ b) n  O  z7 o
  8.   /* Enable HSE */7 m$ @# o3 u- A
  9.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);  //外部高速时钟使能,25MHZ
    , n3 s+ J' M+ ~) ~1 K' r: ?" k

  10. " G9 r" u5 ~" L0 Z$ H
  11.   /* Wait till HSE is ready and if Time out is reached exit */  //外部时钟使能后,得需要一点时间到达各个端口
    # h- K1 h* U: L9 c% _  b) r
  12.   do; E$ i7 \5 ?: x2 x2 H) R
  13.   {7 Z3 n4 P) a* O+ q
  14.     HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好
    * N" E6 i2 U- G4 u% M
  15.     StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时
    6 r7 y/ \7 ^7 w. F+ c) V
  16.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    * I% T2 H5 c1 w6 r' C! ?; x5 z
  17. 1 S! e0 x  J# \$ W4 C
  18.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的" U; u% S1 r0 r, t1 P7 Y
  19.   {
    - e' B) w$ x+ K
  20.     HSEStatus = (uint32_t)0x01;   //说明时钟已准备好了,才结束do whlie循环
    1 C/ G/ `) F& G/ Y7 }$ |! n
  21.   }
    ' z/ w: g" H2 {% G! Y* X  m
  22.   else
    6 R; s4 o& s4 M- {% ^- d7 U
  23.   {! ^: z# r# P, w9 w" P, K/ y
  24.     HSEStatus = (uint32_t)0x00;  //说明是因为超时了而退出do while循环2 b2 Y0 e' s$ n. c+ P
  25.   }0 ~: ]) t) d- I: J( W2 v% L
  26. : R4 H3 r% _* p( Y( l3 A1 \
  27.   if (HSEStatus == (uint32_t)0x01)
    8 w# Z/ Z1 O/ J6 R6 `3 |' ]' Y, N. _
  28.   {
    7 F2 l# T( `3 Z& @3 E. |
  29.     /* HCLK = SYSCLK / 1*/1 x  D! A% B7 W' ~
  30.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M
    % v  G( [! @) s+ d# p* R5 y2 G
  31.       " F: C, [6 Y' L- P' v, n
  32.     /* PCLK2 = HCLK / 2*/) N; K+ m; K1 G5 Y
  33.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M
    3 a* J, ^5 ], b1 ^$ C  u
  34.     1 x3 T! ^8 J/ F; h
  35.     /* PCLK1 = HCLK / 4*/+ m! C, ^, g! \# ]4 B
  36.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M
    $ t; {' `7 c6 ]. o2 V, S3 Q
  37. 8 `' a" Y: m3 J1 D
  38.     /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置
    $ s# N# {" o2 z5 t
  39.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |7 \4 T9 Q3 @5 J* |" Y; ~' {' ^
  40.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
    0 G$ E* s4 w/ r, l* z
  41. //配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能$ J/ s. S" z8 K( U
  42. //通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M3 }7 [( h' [0 G& A) b
  43. //通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN
    7 S. u/ i$ _+ _* R
  44. //bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M- d$ v, p; k* t$ @0 d. k8 S
  45. //bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M
      X; g- [) Q9 F' @: T& |
  46. //bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M
    * c* K4 p# E. J( |* C7 U; \
  47.         " H$ e) H- u9 E+ Y& M- {
  48.     /* Enable the main PLL */
    ( Y6 e$ v# B8 R4 A; p
  49.     RCC->CR |= RCC_CR_PLLON; //使能PLL
    6 C. Y( Y  c2 r6 I

  50. * q6 K- [8 r6 n; x# u; j
  51.     /* Wait till the main PLL is ready */4 g& v2 y' Y7 ?  i, X$ y
  52.     while((RCC->CR & RCC_CR_PLLRDY) == 0)# |! @7 }7 F9 |# D5 H/ z) _
  53.     {# S" C* H# E/ Z  o( ~; w
  54.     }
    , Q7 o+ z' }! t0 i
  55.         //到这里RCC->CR已配置完,最终值0x03036783
    4 K8 f- g$ o4 s
  56.         //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启7 ?* M: K8 L8 P+ K1 V& u, x) ?- {4 e
  57.         + r  e0 Q1 X! K+ f5 _
  58.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    / b% I" i' X6 d8 H6 R& W
  59.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;
    2 E4 ~( k" \. A" @* F3 \; L

  60. $ p8 h, i1 O; W
  61.     /* Select the main PLL as system clock source */2 s0 t% u7 B) z! n& ~0 o1 b/ O
  62.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));8 A( P0 m. T5 ~8 g
  63.     RCC->CFGR |= RCC_CFGR_SW_PLL;, n6 Z# \: u4 E+ z3 \3 K1 m
  64.         & o( V# C- ?) G$ @
  65.         //到这里RCC->CFGR已配置完,最终值是0x0000_940A
    $ g$ m) J1 d# D" q: N6 q, X
  66.         //通过查看用户手册,知道,PLL时钟作为系统时钟即120M
    " {* ]% y  ^0 Y" b; z& @
  67.         //AHB不分频,即HCLK = 120M
    ! e8 J& ^. j& D: [& a& C
  68.         //APB1 4分频,即fpclk1 = 120/4=30M
    1 ]9 |/ m5 Y; w! |* I% e# a
  69.         //APB2 2分频,即fpclk2 = 120/2=60M
      z8 j5 i+ g6 ?2 l" u( l
  70. 9 e8 x! v1 D& g0 ^, M
  71.     /* Wait till the main PLL is used as system clock source */0 s, |( @5 j9 }7 x
  72.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);; C; O6 D& c: @2 j3 |
  73.     {/ ]' L# ^: V/ }& }8 r$ q" h
  74.     }% T& {5 L+ Z( h/ E; ~
  75.   }4 F( P+ G' ^/ L6 ], j1 o: j
  76.   else9 |) q; G4 w: b7 u' c
  77.   { /* If HSE fails to start-up, the application will have wrong clock
      a' Y. P5 ]; y# q
  78.          configuration. User can add here some code to deal with this error */- R+ K2 ^5 C9 P# p6 J3 _5 W4 C, y
  79.   }
    9 H/ ~& M8 c% |

  80. # |- h7 k+ `9 X5 z  T8 O
  81. }
复制代码


  l' M; b3 I, H% O9 R2 c; Y& `5 v

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

总结:

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

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

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

& r, N% j& f% \( w" ^2 [

, c: I8 S% M% T& N! C/ f
$ }/ h! ?$ y# v) f7 `, E6 T7 E8 O5 Q
赞 收藏 评论0 发布时间:2021-12-2 14:28

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版