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

STM32~配置时钟频率[一文带你解决STM32主频配置]

[复制链接]
STMCU-管管 发布时间:2020-9-14 12:41
前言

  最近开发项目,对MCU主频要求比较精确,尝试了两种配置主频的方法,掌握这两种方法也就熟悉STM32系列主频的配置方法了。分别是,使用外部晶振作为时钟源;内部RC时钟作为时钟源。介绍两种时钟源的区别:


6 k! C3 ^& w1 v* ]

  • HSI内部8MHz的RC振荡器的误差在1%左右,内部RC振荡器的精度通常比用HSE(外部晶振)要差上十倍以上。
  • 内部RC频率受温度影响比较大,如果省电Sleep模式下内部RC会停止工作。
    2 x4 I2 T; E' s

    3 T2 c/ h3 a: |0 j# v$ Q
- z; u- D! P: `7 [) s
, {' M4 _1 I% X) Y: W6 ]5 z' z( p. r
1 . 时钟系统' B* Y! d1 T) O! ^# i

  在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。


. s# v% P& R/ }9 @

  • HSI是高速内部时钟,RC振荡器,频率为8MHz。
  • HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
  • LSI是低速内部时钟,RC振荡器,频率为40kHz。
  • LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
  • PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。# B# t% r8 J3 |6 _7 W. y4 R
( [/ m' p, H+ M% @
1.png
: I. j/ p- C$ Q* L6 O( E- H9 d1 r

6 W4 V$ Q0 p/ w: t) P6 \
0 U5 e0 }1 i6 ]8 Z- P& V

 用户可通过多个预分频器配置AHB总线、高速APB2总线和低速APB1总线的频率。AHB和APB2域的最大频率是72MHZ。APB1域的最大允许频率是36MHZ。SDIO接口的时钟频率固定为HCLK/2。* O7 L) L% i$ Z
  40kHz的LSI供独立看门狗IWDG使用,另外它还可以被选择为实时时钟RTC的时钟源。另外,实时时钟RTC的时钟源还可以选择LSE,或者是HSE的128分频。RTC的时钟源通过RTCSEL[1:0]来选择。. ~6 w4 }) `# Q4 ?% w
  STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz。
. _2 S! t# o+ Y' W8 X  F  另外,STM32还可以选择一个PLL输出的2分频、HSI、HSE、或者系统时钟SYSCLK输出到MCO脚(PA8)上。系统时钟SYSCLK,是供STM32中绝大部分部件工作的时钟源,它可选择为PLL输出、HSI或者HSE,(一般程序中采用PLL倍频到72Mhz)在选择时钟源前注意要判断目标时钟源是否已经稳定振荡。Max=72MHz,它分为2路,1路送给I2S2、I2S3使用的I2S2CLK,I2S3CLK;另外1路通过AHB分频器分频(1/2/4/8/16/64/128/256/512)分频后送给以下8大模块使用:


3 |$ N9 o  ?% ^! [

  • 送给SDIO使用的SDIOCLK时钟。
  • 送给FSMC使用的FSMCCLK时钟。
  • 送给AHB总线、内核、内存和DMA使用的HCLK时钟。
  • 通过8分频后送给Cortex的系统定时器时钟(SysTick)。
  • 直接送给Cortex的空闲运行时钟FCLK。
  • 送给APB1分频器。APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给定时器(Timer2-7)2、3、4倍频器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2、3、4、5、6、7使用。
  • 送给APB2分频器。APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给定时器(Timer1、Timer8)1、2倍频器使用。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用。另外,APB2分频器还有一路输出供ADC分频器使用,分频后得到ADCCLK时钟送给ADC模块使用。ADC分频器可选择为2、4、6、8分频。
  • 2分频后送给SDIO AHB接口使用(HCLK/2)。6 n. e) I5 b) H/ ]$ k8 X

    & A( }# \! f3 N2 Z

8 Y& A3 E/ c/ l, \" G$ k: h2 . 外部晶振作为时钟源
" ]1 L  y8 ]6 R' j! P

接下来,解决使用12M外部晶振时,如何配置作为系统时钟源。
2 {$ V/ ?+ k0 Q6 _. R第一步,修改stm32f10x.h中的HSE_VALUE为12000000

: E; f5 Y5 {) Q, Y8 ?; g) `

  1. /**
    ! a9 z0 E8 K- M1 q1 H# C
  2. * @brief In the following line adjust the value of External High Speed oscillator (HSE)
    ( U- k2 \6 B+ Q, P2 u
  3.    used in your application 2 u9 \- o$ z# w* I
  4.    , j1 _' [. V5 x% A7 ]1 H
  5.    Tip: To avoid modifying this file each time you need to use different HSE, you
    6 U: g. d0 [7 h9 g8 B5 Q
  6.         can define the HSE value in your toolchain compiler preprocessor.2 @& e! T0 e" ]7 p0 G
  7.   */           * [& c. q/ Q  b, d# d
  8. #if !defined  HSE_VALUE0 G' K% j6 e5 _: P8 }$ h
  9. #ifdef STM32F10X_CL   
    + i2 p" A% {" L; q" f: p4 d
  10.   #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */- A$ G7 F6 m$ D3 R* ?
  11. #else ! p. u! M! r4 ^; V# ~
  12.   #define HSE_VALUE    ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */
    4 [3 E4 R) I0 I
  13. #endif /* STM32F10X_CL */: R$ n5 k# v$ u" s
  14. #endif /* HSE_VALUE */
复制代码
2 a( N( j% i* c9 c' b* q; K- b

第二步,修改system_stm32f10x.c中的时钟配置,先找到void SystemInit(void)—》SetSysClock()—》SetSysClockTo72(),将9倍频改为6倍频,12*6=72MHz

) C4 i+ |; S& E9 F! T/ }+ W& `

  1. /**& W- |7 H/ r1 g6 l
  2.   * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2 6 b9 W9 j( X0 K( [; B3 w+ P
  3.   *         and PCLK1 prescalers. 2 }2 }6 n1 ?  v. b( r
  4.   * @note   This function should be used only after reset.+ I, M+ w9 J6 T0 L" `
  5.   * @param  None
    ' h% l' V, W4 R& B1 p. C
  6.   * @retval None2 r5 {6 g5 t- B  P+ v. ^& N1 A
  7.   */9 J$ i9 p/ n/ D" @( h
  8. static void SetSysClockTo72(void)
    : @6 z5 e6 \8 W6 p$ z% B
  9. {  S1 r2 A) Z0 C5 t
  10.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    $ s& u- k1 O* e5 v% l) Q! C$ A8 d- t
  11.   
    $ X8 I0 r, M0 H* G0 h! ~& r
  12.   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    , v3 y* I3 ^! O( C' B, ?$ Q
  13.   /* Enable HSE */    4 \: k. i* n; l1 R( ~
  14.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
    + {* k/ h. ?& j% W
  15. ) R( _, l' M, {( ]
  16.   /* Wait till HSE is ready and if Time out is reached exit */  |3 U& p9 g7 r, }! h* {8 }. }
  17.   do
    * v1 f9 h4 T  R6 u' d
  18.   {5 ~' l& S% c4 C" j4 e/ C
  19.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
    3 Q3 W5 f6 J3 p, N/ ~
  20.     StartUpCounter++;  / r& b7 l; V3 b
  21.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));- ]2 S# B9 @9 d4 D

  22. # l1 O5 f& X3 g7 f/ q
  23.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
    ' J1 {8 ]; ~) c# r) A
  24.   {2 Q; T1 h6 k: B9 [7 b3 h
  25.     HSEStatus = (uint32_t)0x01;4 _# W) x  j: v4 ]  Q
  26.   }- e" T+ W& F2 F; d
  27.   else
    6 W- @% m8 y9 u3 b1 P
  28.   {6 Z) ~- |9 ?, T" _: R6 V
  29.     HSEStatus = (uint32_t)0x00;
    " c: N4 i: U: J2 b. U
  30.   }  
    : l8 o% S; b$ D& K
  31. 0 {: P6 ~* Q: X/ M9 d* X8 ?" K
  32.   if (HSEStatus == (uint32_t)0x01)
    ) h9 N7 g1 K; J& M3 A1 M3 O
  33.   {
    ( ]% m/ w. A: Y1 d$ h6 _" X% T
  34.     /* Enable Prefetch Buffer */
    ( p! }  N; v3 @/ g% i
  35.     FLASH->ACR |= FLASH_ACR_PRFTBE;
    , s: L% F! C% Y
  36. % s' ?0 T* e% x8 M5 p( h4 ]
  37.     /* Flash 2 wait state */
    8 |2 V4 P' O) E. G- H& x6 Y
  38.     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    ; ?  L  u, z. F, Z
  39.     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   
    5 r. q' Y2 n; a  u( a

  40. 3 |' N8 k) S! M( i- {) O+ s# m# f. t! p. }

  41. & n+ k9 E( [6 o. D  Y* n
  42.     /* HCLK = SYSCLK */9 _+ V; v5 W' w
  43.     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    3 u$ {* m+ u8 x, ]- H
  44.       * |) Q1 D8 H9 D- M- E, F
  45.     /* PCLK2 = HCLK */. }. q+ x1 Y% t$ @
  46.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    ; A9 l9 g4 o, `: r- \. h& E
  47.     ) q4 ]6 k$ G1 J/ w, |7 H
  48.     /* PCLK1 = HCLK */
    * j, o* X2 Y% [3 M* s
  49.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;) k1 p! {5 [* B( a3 t
  50. * y+ [/ v4 i; y1 X7 ^( s. l5 X1 v: ?
  51. #ifdef STM32F10X_CL& G$ x0 z8 n+ V' A- {
  52.     // ...8 Y: D  D) V# O$ b% Y
  53. #else    8 T+ b$ Q5 ?2 w2 X2 D: r& Y6 w$ B
  54.     /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    " V0 Z8 x. J2 R5 u$ `$ T
  55.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
    ' x" x8 {2 ~8 F0 b/ B
  56.                                         RCC_CFGR_PLLMULL));! t! Z5 ^) V) ]1 ?$ T! F) P
  57.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6); // 12# b$ q- O! H2 V( z1 f, Z
  58. #endif /* STM32F10X_CL */0 Y; v1 h) g( a& }" g1 `
  59. 4 v, }$ _. `5 O  L7 x  G( Y. y
  60.     /* Enable PLL */0 U; c# }8 b! @. _8 ~
  61.     RCC->CR |= RCC_CR_PLLON;1 A3 q4 Y/ L$ f) k: K

  62. 6 M( Z% D, C$ s2 _
  63.     /* Wait till PLL is ready */! }/ ~9 b1 _% I% f" \( K' U  T
  64.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    7 q: g( G- s, O3 U4 i
  65.     {
      Z8 E1 \- n2 M9 _" a
  66.     }
    * g& [6 t- r' o! D# T1 _& `( N) y8 q
  67.     9 r; D! B1 }# W2 ?- x) s: q$ {9 Y
  68.     /* Select PLL as system clock source */
    " S. u( Y/ t6 H0 a+ e
  69.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));2 K1 P9 I- j' |: z
  70.     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   
    1 ]6 d- r9 p; o. \

  71. , \+ d; k. f9 O
  72.     /* Wait till PLL is used as system clock source */
    ' b1 h: |" V9 w3 h0 T
  73.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)& _8 g: H* c/ V
  74.     {8 {; U2 h, T. s/ s
  75.     }
    ( _1 S% z. A( G+ |1 k
  76.   }$ y! s6 V' A: s% `
  77.   else
    ) P( \! K. g3 n7 b% `# R- w
  78.   { /* If HSE fails to start-up, the application will have wrong clock . p# {7 Y" K7 ?: g9 b
  79.          configuration. User can add here some code to deal with this error */
    0 H+ x  D- \; E' r3 Q! G% F
  80.   }8 l& E& n$ z! O% ~+ k3 R
  81. }
复制代码

2 f4 w$ Z/ P2 X! h0 k& ]$ u* s& T  B' O- P
3 . 内部RC作为时钟源

# F8 y! h7 F1 f' S* J/ G: a& w

  实际开发中使用内部RC振荡器主频不能达到72,我使用的是STM32F103C8T6,库函数最多支持16倍频也就是8/2*16=64Mhz,实际测试芯片跑不起来功能没有正常工作。使用内部RC振荡最大能达到52M,不信大家可以试验一下。
5 V9 E8 w/ n4 n

在system_STM32f10x.c中,找到函数void SystemInit (void){} 注释掉所有代码,添加下属代码。

8 L& b. S8 U& |

  1. //开启HSI. F) N! o5 O1 ]0 D6 l  {
  2.         RCC->CR |= (uint32_t)0x00000001; & h! G: H& S3 L! J2 ~& t
  3.         //选择HSI为PLL的时钟源,HSI必须2分频给PLL
    # p& O: M/ m* l: p$ h
  4.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLSRC_HSI_Div2;
    7 r" I) Z1 ?3 c, q/ b. H- E
  5.         // 8/2 *13 = 52 8/2 *9 = 36 8/2 * 12,设置倍频
    # G: G% @/ z0 w3 W& ~# C, O
  6.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLMULL12;' ^5 O. J6 T6 o& j
  7.         //PLL不分频9 C1 x7 f3 y' S2 p- ?& \7 C  e
  8.         RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;6 \* y  ?/ u0 U9 h$ F7 x+ d3 g3 |2 L
  9.         // 使能PLL
    . Z! G# M- z6 x$ q9 C! T  |
  10.         RCC->CR |= RCC_CR_PLLON;, }7 D/ ^, d* B6 `9 ^. {
  11.         // 等待PLL始终就绪0 [  Y$ f2 W8 s0 z* u
  12.         while((RCC->CR & RCC_CR_PLLRDY) == 0){}
    2 q$ L" c; R4 k  n2 {. f0 K
  13.         // 选择PLL为系统时钟源
    ! m4 F- T. k8 x3 }
  14.         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    5 L, n6 I( u0 o4 M4 [; O
  15.         RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
    # F+ R: @: C# Z7 a2 W8 R2 |
  16.         // 等待PLL成功
    1 E$ `) O: ^* {
  17.         while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}
复制代码

- ]- A) W- h+ v0 C2 V
4 V2 t2 q  w3 M) S" _4 .Keil MDK中Xtal的作用

! _5 N& K; y- o* m
0 @! V  @2 C7 O. O" }' E" Y
2.png

- J/ U3 s" B, |4 A/ r3 r9 a0 w5 _- J* N1 O

# [  U- @  j# \3 L3 p; g; n6 b! Z6 O% c0 Z6 Y8 O: E# g0 {% f) [

( r: U" K* k: _+ @9 i$ y* j8 o在手动配置主频的过程中,想到Keil工程菜单应该提供了配置主频的选项,于是又看到这个。百度了一下,这个参数只用于软件仿真的,对于硬件仿真或者直接把程序下载到板子里是没有影响的。
" b1 _' C/ Y8 B" ~
2 f* T* L# p$ Y& l$ R; Z8 f
  Xtal 后面的数值是晶振频率值,默认值是所选目标 CPU 的最高可用频率值 。该数值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间。正确设置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相同。) j+ l4 s- K, M, o" M; h
; }5 _( ^& E  h8 t& i5 h

$ o* D  D; [7 F# F. i2 h% _9 m
. ^, ?% B" m7 i1 p4 s9 E# W1 w
- d9 C; T/ I1 z- ]
赞 收藏 1 评论0 发布时间:2020-9-14 12:41

举报

0个回答

所属标签

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