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

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

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

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


$ g6 u# O8 a& Y  ?9 I9 L) M/ a# J" Q

  • HSI内部8MHz的RC振荡器的误差在1%左右,内部RC振荡器的精度通常比用HSE(外部晶振)要差上十倍以上。
  • 内部RC频率受温度影响比较大,如果省电Sleep模式下内部RC会停止工作。
    " {% t0 x4 s9 [. Z/ Y0 ?
    - \0 T* O4 B1 `* @
0 f% V: p4 n3 F* G/ h$ j

3 O+ Q  s5 D5 N  G- x: l" G1 . 时钟系统
9 L9 H0 d2 O: l1 @+ e; f- Z7 @$ O

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

7 y1 Z  R' g8 T3 j& O7 ]

  • HSI是高速内部时钟,RC振荡器,频率为8MHz。
  • HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
  • LSI是低速内部时钟,RC振荡器,频率为40kHz。
  • LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
  • PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
      _2 ~1 r4 O0 l
+ }- f0 U. H7 [/ S* q
1.png

2 S' _1 c; T1 N, G, p# z5 k( r
: U; d, ?! H1 M$ ~
6 r( W0 R) Y# r' V5 u/ }

 用户可通过多个预分频器配置AHB总线、高速APB2总线和低速APB1总线的频率。AHB和APB2域的最大频率是72MHZ。APB1域的最大允许频率是36MHZ。SDIO接口的时钟频率固定为HCLK/2。
- N7 q' P( D8 }5 h  40kHz的LSI供独立看门狗IWDG使用,另外它还可以被选择为实时时钟RTC的时钟源。另外,实时时钟RTC的时钟源还可以选择LSE,或者是HSE的128分频。RTC的时钟源通过RTCSEL[1:0]来选择。+ Z/ w& l5 E! j' m7 b6 _
  STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz。
: c7 R: M4 l2 Z9 g' c6 M: r% v6 \  另外,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大模块使用:


4 \, P% j+ ?6 U% M4 k+ ^4 B, g

  • 送给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)。
    8 e3 z2 J, p) ~. F/ N* o

    , @0 c1 C; u) U7 z# u
* h6 z8 r, v  ^- C9 [
2 . 外部晶振作为时钟源/ J" h" R/ Q1 b4 B. h6 ~

接下来,解决使用12M外部晶振时,如何配置作为系统时钟源。
& j- }7 Z$ T% `: q. W$ K第一步,修改stm32f10x.h中的HSE_VALUE为12000000


" G6 j. @2 j" t: u

  1. /**0 g+ `- a" N+ h4 p8 L
  2. * @brief In the following line adjust the value of External High Speed oscillator (HSE)9 k9 w2 S" R+ t) ^; S
  3.    used in your application : ?$ J; r2 }, ~" s2 H! B, W
  4.    
    & A+ z1 H3 P! z! t! i/ G
  5.    Tip: To avoid modifying this file each time you need to use different HSE, you
    . f" n" W' T3 l5 k& Q0 g1 i& G
  6.         can define the HSE value in your toolchain compiler preprocessor.
    . F! C" v% H5 L
  7.   */           
      s1 F" a) R( L1 y* e$ b
  8. #if !defined  HSE_VALUE
    ! X- m: l( U2 d# P' L" G
  9. #ifdef STM32F10X_CL   ' F& z- Q: z+ f% U
  10.   #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
    1 V9 d4 M9 V6 y& Y, e
  11. #else ) |/ q9 P, |# I
  12.   #define HSE_VALUE    ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */' \4 }  `1 {% x$ _
  13. #endif /* STM32F10X_CL */8 c+ v7 H# O- z  j) J
  14. #endif /* HSE_VALUE */
复制代码
# x( l) F9 x  i  a# w8 J

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

9 u, c' g; H9 H( c) k

  1. /**2 f* v* W& U2 t- r* ^2 _5 i  L
  2.   * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2 . w/ C2 S" H6 `% u/ |, h$ K7 G
  3.   *         and PCLK1 prescalers. 6 i) T) e  H% @5 b2 c1 C, G7 h
  4.   * @note   This function should be used only after reset.
    * o$ M' Q0 ^, M7 v
  5.   * @param  None! ~- m# L3 D4 N  r
  6.   * @retval None
    1 Y. r% |3 t% Z% Y
  7.   */
    ; {& S+ H0 i+ }( ]0 l# @
  8. static void SetSysClockTo72(void)  A7 B' h, M6 B* ^7 {. z, B
  9. {
    0 q3 [. H" Y2 D) M4 m2 L: C
  10.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;* d8 W7 G9 _1 i2 V9 ~# ^
  11.   7 i/ X! T( S  C& _
  12.   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    . P' \7 {! T1 u  b! L" i8 u- }
  13.   /* Enable HSE */    $ X9 y* p- x1 u* ?% S2 A
  14.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);: F3 _  J4 P0 w4 v# D# Z
  15. ) b6 Y( F% f* w; b
  16.   /* Wait till HSE is ready and if Time out is reached exit */3 P) W. o& y1 u# B
  17.   do, |( \) Q  j( L5 w. @# R
  18.   {
    6 p4 B  y' ?8 ?% K
  19.     HSEStatus = RCC->CR & RCC_CR_HSERDY;/ T! O- C8 H% ~- X
  20.     StartUpCounter++;  * f$ i' N* C+ L. Z0 [9 N
  21.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));# J7 L/ `! O8 P/ _8 `. ]
  22. 0 O7 A, V' Q3 V: z8 p5 z$ d; |
  23.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)$ u. N/ U- [) }2 X; V
  24.   {1 l( v# X7 d( f4 _- m% a
  25.     HSEStatus = (uint32_t)0x01;
    ' _: }5 p8 o' ]
  26.   }/ F# j. X0 x% ]. @, B3 Q: B
  27.   else" M7 j8 ?$ c+ k, c, L! o
  28.   {9 n% q% n9 }" B9 H
  29.     HSEStatus = (uint32_t)0x00;
    ) z2 F2 l; i% i$ i' f; x
  30.   }  
      t. m0 S2 E, Z3 @

  31. 4 L( o6 F! d6 Q/ }% `2 v" y
  32.   if (HSEStatus == (uint32_t)0x01)8 U1 r7 ?* f! g; y( J; Q6 r9 _5 I
  33.   {
    ; t$ ]9 X* r; J5 }8 i* j) E
  34.     /* Enable Prefetch Buffer */$ n/ W# n# `2 }7 ]* Z7 A$ s
  35.     FLASH->ACR |= FLASH_ACR_PRFTBE;1 ^2 P6 p3 K; h3 E1 a! ~

  36. : E; b! n& }3 g) s. C
  37.     /* Flash 2 wait state */" V# [) v: h& w
  38.     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);! v, S- m# w! k8 K$ Y  h! B
  39.     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   
    / b! J6 }+ ?& ~4 @  v6 W

  40. ; p) z( s9 H; [2 P
  41. ! ]7 i$ C/ O, U) E, Q/ Q
  42.     /* HCLK = SYSCLK */& q" T# F- ~8 E: J8 [# v% q' ~8 u6 H! i
  43.     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;3 Y" {: i8 I, b+ T9 }  e
  44.       
    & E9 Z) O* E4 D
  45.     /* PCLK2 = HCLK */
    ! q/ q; o6 o  j0 ]2 i
  46.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    ; i$ R; y- e/ |5 q1 G& v% q
  47.     1 O4 e" X/ s, N/ d- C( z9 L, ]" M
  48.     /* PCLK1 = HCLK */; H- m  v; ^9 O% A
  49.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;3 Y9 k  g7 P/ Q" }' \

  50. 3 G2 Q0 `/ O! k( Q0 w, N* p
  51. #ifdef STM32F10X_CL
    1 V& K4 ]/ _5 e, w: S2 d
  52.     // .../ P9 |1 }- I7 _$ x- a% {
  53. #else    % f) t4 N, Q# B* E, L1 P% k# W
  54.     /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    : A. e- K# F2 W+ `* Z
  55.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |. ~5 x4 n2 _7 R$ z& y1 Z/ {$ u
  56.                                         RCC_CFGR_PLLMULL));
    7 F) E9 W" v& }5 I0 J# f
  57.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6); // 12
    8 `- r% m7 X/ e1 H% W
  58. #endif /* STM32F10X_CL */, p' t% K$ p" l/ \7 L* U
  59. 8 o2 n/ B4 z" P3 q
  60.     /* Enable PLL */
    4 j. P! x- v( F& X1 G: ?
  61.     RCC->CR |= RCC_CR_PLLON;4 K; F$ G0 |+ I* g, F
  62. 3 i9 z) |  X  w# l2 k  v
  63.     /* Wait till PLL is ready */7 I9 g/ j$ k7 A% g2 r" R7 n  ?
  64.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    / }% n' a" W4 I6 |) s2 g$ Q3 ~
  65.     {0 b: \5 k+ J# i) i- r" d* f, P
  66.     }
    % L6 y6 p, ~9 t1 n7 }  F7 k: M
  67.    
    , `' T. e9 O  C, F1 d8 P6 ~' l" v
  68.     /* Select PLL as system clock source */* ^3 @- V& Y+ Z! i5 u# L$ ^4 x& U9 v/ e
  69.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    0 e, c5 O5 b1 ?- J  }
  70.     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   
    6 X7 o0 `  n% H+ o$ y  x$ Y" b

  71. 8 ~7 y- u- x8 h
  72.     /* Wait till PLL is used as system clock source */+ `4 {! v; T/ h6 W7 f9 C5 Z
  73.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    1 z* P6 O' P* q: y3 x9 h* `7 N8 ~
  74.     {
    ) a7 D7 J) `# s- j1 a$ D6 A
  75.     }. Z' R- Q# W1 i. s
  76.   }+ \2 d$ K3 o9 J( {  @
  77.   else
    . h3 e3 y. {$ u7 [6 e' {& E8 T0 r
  78.   { /* If HSE fails to start-up, the application will have wrong clock ' [' l$ W, p% ?) z6 y0 C
  79.          configuration. User can add here some code to deal with this error */5 z1 P1 N0 s8 T* D7 [8 X3 W5 Z/ C1 L+ O2 f
  80.   }* I! j8 u$ `: d# X. Y& Q& t
  81. }
复制代码
5 t! P$ K$ P' k/ Q

5 w9 D  Y9 T3 k2 D2 j1 Z3 . 内部RC作为时钟源
5 |* H7 R- z# Q* F

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

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

8 ?" A3 L* Y' V) D( l

  1. //开启HSI  d- S- [& g; Q1 {" }7 _$ W
  2.         RCC->CR |= (uint32_t)0x00000001;   ^+ j- P! Q# v5 \5 Z% v
  3.         //选择HSI为PLL的时钟源,HSI必须2分频给PLL! ~! e7 p; {3 q% K
  4.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLSRC_HSI_Div2; 8 `% a  I9 u- \+ ^
  5.         // 8/2 *13 = 52 8/2 *9 = 36 8/2 * 12,设置倍频" E1 D4 x: `2 H, E+ n7 s
  6.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLMULL12;, \" a2 M. Q5 K$ N& b& ?6 T, H
  7.         //PLL不分频+ V2 d: y" Q6 w* \4 U# W/ |4 m
  8.         RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    : F% T+ M3 h& j
  9.         // 使能PLL
    ' o% r0 K4 W- u
  10.         RCC->CR |= RCC_CR_PLLON;
    . ?4 n: O; {4 r/ i
  11.         // 等待PLL始终就绪
    5 E* D$ g: P  k& \- U9 z
  12.         while((RCC->CR & RCC_CR_PLLRDY) == 0){}. J  M' c& l( P0 q) e( z: p. ]  @$ _
  13.         // 选择PLL为系统时钟源8 O& b0 I# O6 z( c$ V
  14.         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    + {! y. z" W- P2 C$ y
  15.         RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
    * E. }, Y0 }0 v2 E3 B  l& d
  16.         // 等待PLL成功1 ^2 [2 y4 M; I+ l9 T$ u1 w% b# k
  17.         while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}
复制代码

8 ]8 z* x* [3 V/ {  P" E) H9 H
1 @: v# D7 A5 S4 .Keil MDK中Xtal的作用
& n& ]6 R( ~4 i' H: d7 y
  [. q! T7 a7 r$ |: y. ~
2.png
5 [  `. r+ q/ B( V8 h
# J, p9 M4 L7 D$ F, C& {
' t. b' Q9 \& {. b% b# I
- l+ j& @5 q" t; e

+ F7 Z) s- K9 ~1 `% T2 a在手动配置主频的过程中,想到Keil工程菜单应该提供了配置主频的选项,于是又看到这个。百度了一下,这个参数只用于软件仿真的,对于硬件仿真或者直接把程序下载到板子里是没有影响的。
# }7 ~/ V: z* @
& z' `+ E! i9 D! L' y
  Xtal 后面的数值是晶振频率值,默认值是所选目标 CPU 的最高可用频率值 。该数值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间。正确设置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相同。
! o; {. N& O) h& P7 O, S1 a5 C2 Y+ P) P% l5 q" u5 _: ~

; s3 _* _- u5 s0 J1 h

3 ^; u: K, h4 {' o3 J5 i1 K
1 k/ G+ j# h$ R. U/ u# z5 O! u
收藏 1 评论0 发布时间:2020-9-14 12:41

举报

0个回答

所属标签

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