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

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

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


, l  s8 n/ s6 P/ q- V' T

301052464747191.jpg

8 D1 \2 }- x' a' z: t7 u8 m

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

  1. ; Reset handlerReset_Handler    PROC9 r' I  ~9 L3 W0 A2 }8 ~/ R
  2.                  EXPORT  Reset_Handler             [WEAK]6 p# ~2 G' ]7 ~0 ^6 K  e
  3.         IMPORT  SystemInit
    % L: i7 Z8 G/ p. r+ V+ }0 i, x* |! ~
  4.         IMPORT  __main. z* h- _5 f9 q1 i: z8 ^
  5.                  LDR     R0, =SystemInit
    / p5 E' Y0 z* g1 {
  6.                  BLX     R0
    $ S* D" T) |5 |. k
  7.                  LDR     R0, =__main9 D$ O9 v1 W3 L+ k
  8.                  BX      R0$ q( {  ^, A/ [2 R5 H: b' ?( E
  9.                  ENDP
复制代码

! t5 j6 P- ?. I; C& E0 u" N  f

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


5 K2 J3 u  ~/ X

  1. void SystemInit(void)
    ' Q7 ~% y  f4 ?9 S1 z9 r1 v
  2. {
    & N9 _& p2 E# d- q
  3.   /* Reset the RCC clock configuration to the default reset state ------------*// Y" a: a( H# F: X" k( W: F
  4.   /* Set HSION bit */
    1 \, k# Y; T6 V* U2 q" b7 h
  5.   RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ  a! Q  [! m/ L' g5 g# T4 k

  6. ' A( P6 {2 ^6 k! P% Z* r
  7.   /* Reset CFGR register */
    8 X% w' X  g! W8 W7 G, t5 z/ D
  8.   RCC->CFGR = 0x00000000;    //通过开关SW选择内部高速时钟作为系统时钟16MHZ
    . L$ L7 p) m2 o( Q, L
  9.                                                         //AHB prescaler 不分频
    , m* a" B  [4 D$ P3 k+ p* o
  10.                                                       //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ
    - r' T, s. q; v
  11.                                                         //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ0 K( L, D6 f" j- Q: B- w1 K1 |6 F
  12.                               //MCO1和MCO2时钟输出等配置可参考用户手册Page95: z$ N( H4 F1 j/ i% ?. M4 I6 q; x4 B

  13. ; ^. ]# P# h  F* n; ~
  14.   /* Reset HSEON, CSSON and PLLON bits */
    " b% _; N) b, ^4 _$ a( D' j
  15.   RCC->CR &= (uint32_t)0xFEF6FFFF;# M# g# Z; D5 R. [: r) `6 c2 w, X# G6 m
  16. 2 u- }. E+ ?7 w+ @2 n
  17.   /* Reset PLLCFGR register */. O5 m' R- F6 n' z& ~% I2 b5 y4 {
  18.   RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_30108 t2 ?1 ]/ m0 W, U; \
  19. / n- P) R' e. F4 h) J
  20.   /* Reset HSEBYP bit *// m" E& E  i. N% ^
  21.   RCC->CR &= (uint32_t)0xFFFBFFFF;  //对bit18 HSEBYP 设置为0,外部高速时钟被禁止: v8 r* N6 k& z  s9 c& s0 R

  22. " \# P/ B" Z7 c  Q) P, j
  23.   /* Disable all interrupts */
    0 K9 ^  ~# z& L
  24.   RCC->CIR = 0x00000000;  //所有时钟中断都被禁止1 N( a; E  p5 t8 ^2 w; s; G

  25. % O6 A( c* a' V2 r( @
  26. #ifdef DATA_IN_ExtSRAM
    / D* _6 r3 s& A, A- b7 k, W
  27.   SystemInit_ExtMemCtl(); 8 ?2 K7 g: b9 u: ?1 z, F
  28. #endif /* DATA_IN_ExtSRAM */
    , k) v, |! A5 O1 j7 n+ U# J& y
  29.          
    - O5 [' f0 a2 n' V
  30.   /* Configure the System clock source, PLL Multiplier and Divider factors,
    / b8 s9 Q2 v3 }) a" ~, E6 l
  31.      AHB/APBx prescalers and Flash settings ----------------------------------*/) @7 K! e" ~' k
  32.   SetSysClock();
    / b( ]4 s  j& J
  33. ) W0 O+ f9 f7 ]& [+ Y4 G, ]
  34.   /* Configure the Vector Table location add offset address ------------------*/
    7 }9 f# V3 W; M5 M! K- F* g
  35. #ifdef VECT_TAB_SRAM3 d9 ~8 ^- S3 x. X. Z' ]
  36.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
    : t  T4 @$ a( R# ~1 ?3 ~: h, q8 @  U
  37. #else0 E$ D/ ^& H& a  G/ W
  38.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */) D' K9 F4 c' C6 \( o
  39. #endif' G+ K2 R: Y/ c2 [5 E" s( b+ |
  40. }
复制代码


% X. o  ^4 x) s2 z' \- d

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

  1. static void SetSysClock(void)6 e  l* f/ O# a" `2 w
  2. {$ k+ C# L, \8 q/ E  i+ J4 W
  3. /******************************************************************************/3 D' f+ U% l, E, k3 S% ~+ x
  4. /*            PLL (clocked by HSE) used as System clock source                */- o6 x; R, I* d5 f' j
  5. /******************************************************************************/
    + Y7 _5 ^7 b/ O; Y& B$ g
  6.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    ( [5 j2 T$ h+ s
  7.   # _+ F6 O3 I8 _6 G# l$ m
  8.   /* Enable HSE */* X1 C. p# `. k$ t0 j3 q
  9.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);  //外部高速时钟使能,25MHZ
    % u8 S2 A; E0 O+ Z" k

  10. & `/ K; j  _: E( E7 D  U: Q3 ~
  11.   /* Wait till HSE is ready and if Time out is reached exit */  //外部时钟使能后,得需要一点时间到达各个端口
    / q7 K0 O# [. X  w" f( _) O
  12.   do
    : r% E. n* Q7 y0 T% p* J! J) N
  13.   {4 z5 B- ]8 X2 Z2 c/ X( M$ y
  14.     HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好+ X- p) y8 t* m
  15.     StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时) x7 l' }" g/ c0 F& ^( r0 a+ P8 T6 P, O
  16.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));' H" ^/ o& l6 Z" G+ }: g& o
  17. ( W; C. V, r7 I9 F7 l$ C' V. m
  18.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的
    ; x3 v2 t* X7 [- Z0 `1 {
  19.   {
    ! U* x9 ^, W8 F! G0 j
  20.     HSEStatus = (uint32_t)0x01;   //说明时钟已准备好了,才结束do whlie循环3 |) l# g' f( r( s& x0 ?
  21.   }- }2 j" z' Q/ X' O3 r! A
  22.   else
    # l; O1 r0 c$ |$ Y$ h
  23.   {) q/ q% B& E- d
  24.     HSEStatus = (uint32_t)0x00;  //说明是因为超时了而退出do while循环9 e1 l  \; }* X5 q' q
  25.   }4 W- ~  ?1 W* ]7 {) `* ]3 I( ?

  26. / [' j' W! P; b; a; L3 W2 I
  27.   if (HSEStatus == (uint32_t)0x01)
    9 ~& |+ b& R+ s8 ?# }
  28.   {: \( y  l, u# F, V, \5 r- f
  29.     /* HCLK = SYSCLK / 1*/+ o5 u& Z: C9 d$ @0 e! Q4 G
  30.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M
    4 Z. Q; ^7 h6 f1 p
  31.       / r, \; V- G; e' ?; f3 Z
  32.     /* PCLK2 = HCLK / 2*/
    . r& E$ G7 ^% c2 d1 J; W1 L
  33.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M
    5 A4 L# y9 I$ G9 Y; I! O
  34.    
    ! h4 u/ a0 v! }( J4 h7 b( m
  35.     /* PCLK1 = HCLK / 4*/
    ! p# j+ ]0 Z4 N% M; K* V6 z+ s, D
  36.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M
      _: `! w5 I- j" a3 d$ F' P% S9 l/ ?
  37. ! r4 ^/ p4 v/ _4 B3 E
  38.     /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置
    4 V: r* E7 U) I1 [
  39.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |/ `* ~) M* y, I3 M4 H2 b+ r. N
  40.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
    4 `$ U8 x; A' h5 \9 U+ e
  41. //配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能
      Z- R3 t$ P! {. Q# g# R
  42. //通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M% n" d+ A1 T4 z* ^2 V& |& G
  43. //通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN
    , f! s. H' `$ w" \9 r
  44. //bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M
    7 ^) J4 h1 R/ x, }. q% D# F1 f0 B$ p
  45. //bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M1 z, t+ |& K% C9 b" T, l
  46. //bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M; a; Z# h9 u  Y" v  Z0 n7 Y
  47.         % S5 L9 O* ~( L# k0 F; b
  48.     /* Enable the main PLL */
    0 Y% ?: [$ m* E' q" l0 A# H
  49.     RCC->CR |= RCC_CR_PLLON; //使能PLL
    6 |+ v) b* |. ^3 J/ [8 x/ M! i

  50. : U, V) s0 b& L" {
  51.     /* Wait till the main PLL is ready */  k% b% ~1 z! l. O1 `% q
  52.     while((RCC->CR & RCC_CR_PLLRDY) == 0)) k% P0 p/ o* V7 W  O' }3 n# U
  53.     {0 F8 Q) A& I( Z, Y
  54.     }
    $ v1 E5 t1 E9 l( ?/ r. G
  55.         //到这里RCC->CR已配置完,最终值0x03036783
    : {) W+ d* {; W9 H' ~: F
  56.         //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启
    + _5 a7 X3 O# t: m; _
  57.         
    ( J8 c& s$ ~5 H: S
  58.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */5 Q% [' m8 P" f; ~; d" {4 d
  59.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;6 g3 h9 ?, p/ a' S8 E' G1 ^2 }( V/ j8 G

  60. . l! }, \  o, |) a# [2 F8 c& }
  61.     /* Select the main PLL as system clock source */( y2 Q. G4 G; Y/ [- E
  62.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));* _: ^% R% Z* f5 F7 M9 J! U
  63.     RCC->CFGR |= RCC_CFGR_SW_PLL;
    ) k: V; }; A0 b0 r
  64.         
    " u3 i  h2 @( V- q- k
  65.         //到这里RCC->CFGR已配置完,最终值是0x0000_940A! e8 j! B& m  Q2 T: a: \
  66.         //通过查看用户手册,知道,PLL时钟作为系统时钟即120M
    4 Z& o; o1 u! d& W# ?8 y
  67.         //AHB不分频,即HCLK = 120M% P' t2 R# p1 N* k; E. _
  68.         //APB1 4分频,即fpclk1 = 120/4=30M
    0 [. q8 k6 C& O+ n
  69.         //APB2 2分频,即fpclk2 = 120/2=60M! `! _6 d/ D3 j  P

  70. 5 j, v# y9 x) ^, G+ o
  71.     /* Wait till the main PLL is used as system clock source */2 v0 n2 G  H6 |) V6 R
  72.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);. @# R: F) T' }* U9 \
  73.     {: `! I. G- `6 p3 K% F
  74.     }
    - ^: U$ q& E4 {+ t
  75.   }
    - B7 V/ K: _6 A$ q7 c
  76.   else
    8 E- t0 |" q7 V3 Y$ w( B
  77.   { /* If HSE fails to start-up, the application will have wrong clock/ e) {! q! o0 S7 L: Q( J6 R; `
  78.          configuration. User can add here some code to deal with this error */- {% K: T( y- ~+ X% c2 N& \# Q
  79.   }+ k. ]7 u4 N4 _: C7 R: V

  80. + |( C/ X7 a# |3 y8 E
  81. }
复制代码


5 X& X: y* o/ a1 U& E1 ~2 ^

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

总结:

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

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

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

) s; q* F+ _* T+ q9 T

: o3 l0 l- S# N& b4 m% T, b1 B  J
" F' ]; @" @& `1 |; N; v4 _* _0 u& ~
收藏 评论0 发布时间:2021-12-2 14:28

举报

0个回答

所属标签

相似技术帖

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