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

【经验分享】STM32F205时钟配置

[复制链接]
STMCU小助手 发布时间:2021-12-3 16:00

下图是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。

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

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

  1. <font color="#000000">; Reset handler
    - c* f0 J- y6 Z0 S' N+ S6 Q4 }
  2. Reset_Handler PROC
    2 s5 A3 I$ ?4 q" G, E' {+ e
  3. EXPORT Reset_Handler [WEAK]5 ~; U( r* i/ |  N
  4. IMPORT SystemInit
    + v6 F6 T- N: N5 x8 O
  5. IMPORT __main
    4 Q  N) s- m* R& Z4 p* @$ {
  6. LDR R0, =SystemInit) V4 c4 M1 h+ ~- P( u+ u
  7. BLX R00 N# F7 e4 H. _3 B6 A$ l
  8. LDR R0, =__main
    , X: V6 E( n' s1 P& d% t/ N5 ]9 e8 {
  9. BX R0
    - R7 r2 w/ }% D% J" L% U% L4 q
  10. ENDP</font>
复制代码


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

  1. <p style="line-height: 26px;"><font face="-apple-system, " "=""><font style="font-size: 16px" color="#000000">void SystemInit(void)
    ! C* S& v6 I5 e. a. s! \
  2. {, o" y" m+ ~2 Z/ }
  3. /* Reset the RCC clock configuration to the default reset state ------------<i>/& B6 h$ h" a( m# H7 U% t
  4. /</i> Set HSION bit */
    0 G, T* [4 P# D1 F* j( ^( H
  5. RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ</font></font></p><p style="line-height: 26px;"><font face="-apple-system, " "=""><font style="font-size: 16px" color="#000000">/* Reset CFGR register */
    5 E( n0 u; a$ s/ ]( D
  6. RCC->CFGR = 0x00000000; //通过开关SW选择内部高速时钟作为系统时钟16MHZ
    % u5 V" p0 Y' `' [8 N( _2 T
  7. //AHB prescaler 不分频
    $ N- M( p, @2 N0 ^  C6 v$ |) E
  8. //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ
    , a" t0 k' _4 Y& v* ^8 L  N
  9. //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ
    7 ^- n' p$ G  v
  10. //MCO1和MCO2时钟输出等配置可参考用户手册Page95</font></font></p><p style="line-height: 26px;"><font face="-apple-system, " "=""><font style="font-size: 16px" color="#000000">/* Reset HSEON, CSSON and PLLON bits */
      V9 W8 n! B; u, N
  11. RCC->CR &= (uint32_t)0xFEF6FFFF;</font></font></p><p style="line-height: 26px;"><font face="-apple-system, " "=""><font style="font-size: 16px" color="#000000">/* Reset PLLCFGR register */6 Z+ t" ]1 ]5 Z7 B/ h8 W. P# l
  12. RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_3010</font></font></p><p style="line-height: 26px;"><font face="-apple-system, " "=""><font style="font-size: 16px" color="#000000">/* Reset HSEBYP bit */# Z  O, ?4 _7 C
  13. RCC->CR &= (uint32_t)0xFFFBFFFF; //对bit18 HSEBYP 设置为0,外部高速时钟被禁止</font></font></p><p style="line-height: 26px;"><font face="-apple-system, " "=""><font style="font-size: 16px" color="#000000">/* Disable all interrupts */
    " V# `: I; l! D5 I0 q
  14. RCC->CIR = 0x00000000; //所有时钟中断都被禁止</font></font></p><p style="line-height: 26px;"><font face="-apple-system, " "=""><font style="font-size: 16px" color="#000000">#ifdef DATA_IN_ExtSRAM
    " n, g/ m" U" H$ a
  15. SystemInit_ExtMemCtl();. P* \& o0 `4 K
  16. #endif /* DATA_IN_ExtSRAM */</font></font></p><p style="line-height: 26px;"><font face="-apple-system, " "=""><font style="font-size: 16px" color="#000000">/* Configure the System clock source, PLL Multiplier and Divider factors,
    , J5 N; G! P$ n! c& M. [( b
  17. AHB/APBx prescalers and Flash settings ----------------------------------*/+ z8 `* P3 r9 D
  18. SetSysClock();</font></font></p><p style="line-height: 26px;"><font face="-apple-system, " "=""><font style="font-size: 16px" color="#000000">/* Configure the Vector Table location add offset address ------------------<i>/1 ~' R$ ~0 @! F. j# N
  19. #ifdef VECT_TAB_SRAM
    7 r+ O9 S* `1 N) Q+ J1 M* _
  20. SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /</i> Vector Table Relocation in Internal SRAM <i>/
    9 `& D; R5 O( w; a. b
  21. #else
    , v' ^5 ]$ @' Y5 P8 ?" ]
  22. SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /</i> Vector Table Relocation in Internal FLASH */
    & Z6 B" J) u' r7 ]( ~
  23. #endif
    $ k2 x  K6 @) T9 J9 R
  24. }</font></font></p>
复制代码
8 k$ r4 ^; L* r% l) G

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

, W( @; Z. q( _6 c$ N
static void SetSysClock(void)
2 T) h, f$ i, Z0 f8 i  @8 t2 m) u{
3 J$ \2 P7 K; A/ u/*****************************************************************************/9 Q( ]9 Q8 K) ~$ b9 g" }
/
PLL (clocked by HSE) used as System clock source /
1 w5 y1 i/ W) W+ ?2 b# z/
*****************************************************************************/' L' [) ^3 p8 x' v6 d
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/* Enable HSE */
9 c  S7 w; k; k1 ~1 C7 `  lRCC->CR |= ((uint32_t)RCC_CR_HSEON); //外部高速时钟使能,25MHZ

/* Wait till HSE is ready and if Time out is reached exit */ //外部时钟使能后,得需要一点时间到达各个端口
7 l" v9 \0 I- j( Y" edo; n; t5 l) I; p% M
{
$ I. k) R5 A  M% f1 ^# dHSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好, k' N: X8 Y  h7 @' V9 L
StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时
" L' a% J6 E- Y1 }% ?. w} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的3 @) T9 O+ x; d, F
{
5 k+ v, w  ~6 [) g2 f. S, Z0 l/ O3 [HSEStatus = (uint32_t)0x01; //说明时钟已准备好了,才结束do whlie循环
" o) w3 F/ M; M8 K! L7 M, Z( J% C}
# S8 |% r: G9 U! e' l" O& eelse% u7 T0 [6 J2 z( Y. K0 d
{5 _/ t# u% U% m8 ]! R
HSEStatus = (uint32_t)0x00; //说明是因为超时了而退出do while循环
9 v1 u. `  `8 |% d, s# K- i}

if (HSEStatus == (uint32_t)0x01)
& ]5 B5 R" o- q6 t) [2 [7 ?1 f: t{/ y. m7 c  C7 p, X8 [( N1 I9 ^& d" f
/* HCLK = SYSCLK / 1*/
, t! O' E9 S$ rRCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M

  1. /* PCLK2 = HCLK / 2*/9 o" A7 d4 s, }
  2. RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M
    # E- x) w; i: j; y
  3. ! t2 w; c/ D. K) I# t
  4. /* PCLK1 = HCLK / 4*/7 J$ h7 u/ j" K% G$ {: e: C. h
  5. RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M8 w  s3 s2 k' i: R

  6. . T/ M' W: W. {9 e6 T5 f1 I
  7. /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置
    6 @# r, H- N( X% I6 p1 C4 |
  8. RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    . `/ Y0 x1 m/ B! N8 y
  9.                (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
复制代码

//配置完后RCC->LLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能
4 T' f% w, X* M//通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M
0 K( Q$ }5 z+ i* E( g" h//通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN
0 w$ x7 s2 F! i//bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M
( }$ s3 L: _* r8 m/ w  F$ k//bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M1 C, r. B1 u6 V
//bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M

  1. /* Enable the main PLL */
    - f" T8 b* _% y( A8 e
  2. RCC->CR |= RCC_CR_PLLON; //使能PLL4 D% F7 d$ s$ I9 A
  3. * {  p, P/ C, k
  4. /* Wait till the main PLL is ready */8 |- Z& c0 W$ Q0 M
  5. while((RCC->CR & RCC_CR_PLLRDY) == 0)
    : G! e' R: @: s' A5 U
  6. {" Y; T0 l/ `0 p4 F: D" a
  7. }
    4 h3 q- G* }+ V5 p) ^7 C7 A% z
  8.     //到这里RCC->CR已配置完,最终值0x03036783
    % n" }6 T" P: O) y8 ~3 r
  9.     //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启% |" V3 o$ I) @4 h0 \. }
  10.     1 N3 t/ ^  I1 o% m# S9 i# B5 W" X
  11. /* Configure Flash prefetch, Instruction cache, Data cache and wait state */: I# h/ w) ?- z/ m$ z) D2 u
  12. FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;2 n2 A& W4 q4 t; u  ~% V7 }0 B
  13. : i7 Z- r9 I+ c$ W0 _
  14. /* Select the main PLL as system clock source */
    + m1 X$ |1 X1 w, i  y& d% Q
  15. RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    8 a/ U1 m0 H  x
  16. RCC->CFGR |= RCC_CFGR_SW_PLL;
    , X2 \6 I& {7 n
  17.    
    , m1 Z4 A+ Q+ g) E8 k% ]& s
  18.     //到这里RCC->CFGR已配置完,最终值是0x0000_940A3 W4 h. S5 t  u
  19.     //通过查看用户手册,知道,PLL时钟作为系统时钟即120M% T2 U% Q- Z/ s: H( A; a
  20.     //AHB不分频,即HCLK = 120M6 b; I: k/ ?# C
  21.     //APB1 4分频,即fpclk1 = 120/4=30M
    & S5 R8 j' z  e: j
  22.     //APB2 2分频,即fpclk2 = 120/2=60M
    " h1 o! A6 ]6 t# Y; X. a* a
  23. 4 i4 J) H* ~+ }
  24. /* Wait till the main PLL is used as system clock source */  w( C4 D& n+ W- l' ]/ Q# t8 d
  25. while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);6 O/ ]4 |' S# ^' {" q4 x
  26. {
    7 x4 ^* E2 p$ V9 \
  27. }
复制代码

}
+ W. u8 e: B& Oelse
$ G" L6 M6 C; f6 K+ d! S6 U  w{ /* If HSE fails to start-up, the application will have wrong clock9 w  j. O' Z3 `% I. B
configuration. User can add here some code to deal with this error */" s& j2 {3 C8 a* F: |# B
}

}
% Y' w& D5 H1 T4 G' `
. b6 O# y  o+ l! H0 g8 t

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

总结:

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

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

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

- C2 T1 M( n2 I# I! D" }* C
收藏 评论0 发布时间:2021-12-3 16:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版