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

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

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

% V: L0 ]; g7 s+ t# [; F

301052464747191.jpg

! S9 X+ E& V3 h! R6 N

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

  1. ; Reset handlerReset_Handler    PROC! ~% [; l) u' G% m& Y! [
  2.                  EXPORT  Reset_Handler             [WEAK]
    * c2 F6 W* d% Z+ j
  3.         IMPORT  SystemInit
    5 K* e+ ]5 q6 }4 g8 b4 G9 d
  4.         IMPORT  __main
    $ Q+ D0 L$ j/ i; Y5 `. `1 V: V1 P. _
  5.                  LDR     R0, =SystemInit: N: |' X& a3 F# J! D7 |2 b
  6.                  BLX     R0
    0 a: t' {4 G4 }& q& A
  7.                  LDR     R0, =__main2 U9 |0 N* e; [  E9 @% B6 p
  8.                  BX      R0  l- a/ O$ F5 ]) ?5 b. {
  9.                  ENDP
复制代码
1 a2 d, C4 G7 W+ q0 n! H

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

$ M; C. B3 W3 t& r, p) L

  1. void SystemInit(void)+ N2 ~5 s6 q  q8 f. k( D* q' R
  2. {9 J9 E+ i0 w+ C" C
  3.   /* Reset the RCC clock configuration to the default reset state ------------*/
    & `* h! S; \' c7 d5 B* A& z
  4.   /* Set HSION bit */
    1 T! I# A7 r0 u+ o: f2 c, q# R
  5.   RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ% U  V7 s: A% P4 N" m6 w( k+ O  [
  6. - V, E, O$ H5 O; S0 l! `
  7.   /* Reset CFGR register */
    ; _9 }2 `- `* E2 V5 h1 f- e2 J2 y
  8.   RCC->CFGR = 0x00000000;    //通过开关SW选择内部高速时钟作为系统时钟16MHZ1 [: z" ]6 s: f- ^# K
  9.                                                         //AHB prescaler 不分频% u9 [% B& A4 k
  10.                                                       //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ
    ! g; l0 b- [9 o1 E* Q5 d& A
  11.                                                         //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ& L2 C# ~2 {8 \: t) t
  12.                               //MCO1和MCO2时钟输出等配置可参考用户手册Page95
      v. l$ c0 J  A+ u/ }0 I
  13. ' ]( `( y( {& a6 C7 {  ~. \
  14.   /* Reset HSEON, CSSON and PLLON bits */
    ( w6 ?) h2 H9 s: P8 s
  15.   RCC->CR &= (uint32_t)0xFEF6FFFF;9 ^! b9 i- O1 W# ?6 q1 X
  16. 0 V1 l  @, ?3 W+ v7 t4 {
  17.   /* Reset PLLCFGR register */
    # ^3 a' w% q2 N$ v1 {5 `) F
  18.   RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_30106 C% m9 b8 K/ L
  19. ; n% Z2 ^/ K. n* c% O( V
  20.   /* Reset HSEBYP bit */# D, q% ^* T4 |* {( D
  21.   RCC->CR &= (uint32_t)0xFFFBFFFF;  //对bit18 HSEBYP 设置为0,外部高速时钟被禁止
    4 d" t0 D. U+ B. `
  22. . s# H% k9 F7 u+ ^. a
  23.   /* Disable all interrupts */, X$ G2 U/ M* O6 J4 \) t( t
  24.   RCC->CIR = 0x00000000;  //所有时钟中断都被禁止- c9 O& T5 @  ^0 p
  25.   ~3 ]8 |& }& s  f3 r" @
  26. #ifdef DATA_IN_ExtSRAM
    4 P' L: k9 J( e1 l- t  v
  27.   SystemInit_ExtMemCtl(); 9 _7 m2 f/ ^$ p2 G% P" i7 F+ O
  28. #endif /* DATA_IN_ExtSRAM */* h) p3 L9 b5 Z6 V7 }' a4 a+ n
  29.          : }1 s7 J( `3 S, C+ Y# m7 U
  30.   /* Configure the System clock source, PLL Multiplier and Divider factors, % w+ ]0 P2 F2 i( i/ X
  31.      AHB/APBx prescalers and Flash settings ----------------------------------*/3 I1 `' p% _) L; O
  32.   SetSysClock();* `% S& B; [9 n, @5 t* i

  33. 0 P) z( E" ]. a& V+ G, W% t% `6 H
  34.   /* Configure the Vector Table location add offset address ------------------*/
    3 J( O7 ]2 j& [$ \6 I
  35. #ifdef VECT_TAB_SRAM+ h6 q0 f+ ^, u2 W* y7 o
  36.   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */- m3 y. ?% ], c% U4 \* l
  37. #else
    * `' X  z) O4 k5 k( O# J/ N( B( }
  38.   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
    % i2 e7 d* o" P$ E+ o0 c
  39. #endif& `9 p0 a8 \$ w8 K
  40. }
复制代码

9 {! v0 P2 M; w* \, m

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

  1. static void SetSysClock(void)5 G% @0 z: ?, Z
  2. {2 [& x& \8 {$ i7 k$ }3 e
  3. /******************************************************************************/
    0 y' _1 O  \: a
  4. /*            PLL (clocked by HSE) used as System clock source                */* a4 V/ @0 w% J0 S0 Q) [
  5. /******************************************************************************/
    # u3 p) \- A1 D) \$ c7 c" P) G
  6.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    & D2 E- V2 V4 ?$ T6 b6 n! P
  7.   
    8 V3 Q7 S0 G* U) P7 l
  8.   /* Enable HSE */
    / C  ~+ F4 R  E& H1 y
  9.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);  //外部高速时钟使能,25MHZ
    % l+ N& q9 Z' e  |" b# G

  10. 9 k0 ]1 ~( o: i5 `
  11.   /* Wait till HSE is ready and if Time out is reached exit */  //外部时钟使能后,得需要一点时间到达各个端口
    1 J6 `) @! z9 a0 v& V
  12.   do
    ! ^% F+ x" s3 d5 x! H$ D
  13.   {
    & M2 H; r1 L7 n- r/ o- Z- q, A
  14.     HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好
      d2 K3 A0 O$ S' M; N
  15.     StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时
    $ Z3 ^2 G1 g+ g5 _, N( _5 x) g
  16.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    . u& V5 X7 U3 s7 S
  17. . G* v+ [# L1 N" N
  18.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的1 @% l4 H3 ]) w1 q6 r: \. h) E
  19.   {
    ! ]4 S; A/ i5 m0 D6 @: ^
  20.     HSEStatus = (uint32_t)0x01;   //说明时钟已准备好了,才结束do whlie循环
    4 S: W! O* F2 m" k# W5 d5 k
  21.   }
    5 r  [( U5 Z2 {7 @) U$ J
  22.   else
    ! N- ~3 X$ r: q5 C/ g8 s
  23.   {, b: b" L3 `4 l6 C2 k8 L5 D; n
  24.     HSEStatus = (uint32_t)0x00;  //说明是因为超时了而退出do while循环7 Z% I; R# b  D8 E/ W+ W: V
  25.   }
    . j, Q1 r. d1 s6 j$ n/ s

  26. ( [/ s, f, e/ x2 r
  27.   if (HSEStatus == (uint32_t)0x01)
    4 J- B+ ^- B# C, s2 D; C
  28.   {
    0 g& S" l5 _1 \) f. L5 x+ _) Z# {1 U
  29.     /* HCLK = SYSCLK / 1*/
    " Q2 X. K" {- A. b) O* X
  30.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M
    , @6 d' T& q  H3 U& Z+ l$ A
  31.       4 x# M. P9 C$ @
  32.     /* PCLK2 = HCLK / 2*/4 }0 J: V- E' t1 M6 Q9 @) E
  33.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M
    " P; F) k+ I* T' H
  34.    
    # y1 r( N1 f9 z3 M; s) ?  N# t- p
  35.     /* PCLK1 = HCLK / 4*/* w' P: p* Z# n. g
  36.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M
    - ]1 M- k/ \/ f' i
  37. ) b9 x9 @& F; @
  38.     /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置$ L0 T) W4 J: a9 [1 E! }! d' o( F
  39.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
      A( Z( `# D/ o0 A
  40.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);5 q0 X5 N1 q1 h: n
  41. //配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能- k9 H! N- o# y* F( a% H
  42. //通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M
    - t) U; W; Z4 y. F3 d# u- N8 {- G; f& P
  43. //通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN/ w( ?2 q4 s4 K1 `9 R; w+ C
  44. //bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M
    & Q, C( N% q2 R0 [0 b8 b3 M
  45. //bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M- O3 d5 X7 t8 \6 z) t9 _
  46. //bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M5 y6 ^, L. t& Z8 i1 H: {4 I) E1 H( i
  47.         
    4 t4 s% i, Q1 ]7 l9 s& B4 G
  48.     /* Enable the main PLL */  y" \2 v5 W6 T3 }1 \, n
  49.     RCC->CR |= RCC_CR_PLLON; //使能PLL+ h% R. a: }) I7 Z1 _! B. o

  50. . I. u2 S* ?, h9 [9 e3 O
  51.     /* Wait till the main PLL is ready */
    - k% c0 M$ Q0 }2 X  b6 ^. O
  52.     while((RCC->CR & RCC_CR_PLLRDY) == 0)" Q* B( ^4 @) s; _0 i
  53.     {
    : e; B1 u5 K9 p: }8 u
  54.     }
    & X" B. W5 T" C6 j4 Y1 M
  55.         //到这里RCC->CR已配置完,最终值0x03036783; t% _9 x$ ]  \6 t+ _) _
  56.         //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启
    ! {& Z( q  S+ T- x0 w
  57.         
    0 h. }4 ?. U4 `2 n
  58.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */6 @4 _2 r9 T( H9 D( W: W( D4 U
  59.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;! X0 G1 p; @/ V- @+ Y/ F. Q) _
  60. ' W$ m7 p8 B* E
  61.     /* Select the main PLL as system clock source */4 i- D/ r/ n+ U1 m1 x) Y
  62.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));$ n4 Q; _9 M+ o) o5 I( c
  63.     RCC->CFGR |= RCC_CFGR_SW_PLL;3 d: M- V! s' w# W: T
  64.         6 l% A' y2 _5 i3 J
  65.         //到这里RCC->CFGR已配置完,最终值是0x0000_940A$ o; \- R$ X, H/ O
  66.         //通过查看用户手册,知道,PLL时钟作为系统时钟即120M
    , |% f3 L  Q$ L
  67.         //AHB不分频,即HCLK = 120M  p/ E! X# c# ~3 G7 S
  68.         //APB1 4分频,即fpclk1 = 120/4=30M, D* h+ `! s+ b& Q1 u
  69.         //APB2 2分频,即fpclk2 = 120/2=60M8 y4 ]% G7 Z: H" d8 V8 `* b
  70. 0 o) Q+ D* C$ g$ N/ M' z
  71.     /* Wait till the main PLL is used as system clock source */& q. |( R, m* I- K3 a( v" }
  72.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);+ o% D8 i$ `2 Z. }1 N, i
  73.     {
    2 j9 V  l; A8 {. J
  74.     }" k! D4 n0 a, Z9 A
  75.   }" k3 G- N9 s$ [+ m! W$ N( X; r
  76.   else8 M4 l+ p+ N, Z+ d  D8 H* O- [" u4 E
  77.   { /* If HSE fails to start-up, the application will have wrong clock; l1 ]2 h) B0 w3 ^$ u
  78.          configuration. User can add here some code to deal with this error */# H- ]7 ?# N9 G& u2 U0 g, t0 Z
  79.   }
    5 B, D& |& p, m. U6 i- c  i/ I
  80. . r( d# M' S/ m  s
  81. }
复制代码

- s; I5 X6 z$ \  `

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

总结:

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

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

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

4 u$ H' B1 x. h3 b4 s8 f3 e) k
  t- {4 R+ P! J' t4 }

, h1 A2 j/ s: n- S) h. [" I5 p0 ?8 x3 U  j& W- r: Y1 X& O9 K
收藏 评论0 发布时间:2021-12-2 14:28

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版