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

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

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

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


8 H$ M; E* O! {/ ^  N, [

  • HSI内部8MHz的RC振荡器的误差在1%左右,内部RC振荡器的精度通常比用HSE(外部晶振)要差上十倍以上。
  • 内部RC频率受温度影响比较大,如果省电Sleep模式下内部RC会停止工作。8 h0 |1 X/ D1 k5 {4 N9 b/ d
    + q6 d& l* |) Y; V! d/ M7 ]

1 R' @4 ?& S* r7 @; x9 B
3 ~# S. J# V) D! b" @+ d- {' h  b
1 . 时钟系统
2 P. [' E# K7 H; D

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

; O* x8 e1 R' [0 `; e, n8 A

  • HSI是高速内部时钟,RC振荡器,频率为8MHz。
  • HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
  • LSI是低速内部时钟,RC振荡器,频率为40kHz。
  • LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
  • PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
    5 V& X+ m! p& q9 r3 G; [. _! L. |
& \% E5 a* {5 |( W3 h. O, k  S/ j
1.png

( Z& N7 _6 y# N- A" w+ u) m. P" D5 W1 J9 S3 P3 z' ]
/ `1 Q' Q' M% j; o0 `

 用户可通过多个预分频器配置AHB总线、高速APB2总线和低速APB1总线的频率。AHB和APB2域的最大频率是72MHZ。APB1域的最大允许频率是36MHZ。SDIO接口的时钟频率固定为HCLK/2。" T/ I& M0 ~8 R3 }
  40kHz的LSI供独立看门狗IWDG使用,另外它还可以被选择为实时时钟RTC的时钟源。另外,实时时钟RTC的时钟源还可以选择LSE,或者是HSE的128分频。RTC的时钟源通过RTCSEL[1:0]来选择。
- Y0 S; b0 M* q! b$ p, k& I3 j  STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz。& D3 q& V& Z# `, w( Z
  另外,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大模块使用:

6 [. O6 |8 i% \" W, S, ^5 [1 }+ P

  • 送给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)。
    1 X" [  l  f1 G6 J/ g- c
    & N0 J9 P8 J- l; R/ q; q. R& G
: `4 B+ R) U- A" K; C3 c
2 . 外部晶振作为时钟源+ l1 c7 u- f7 c8 n. i9 t4 m

接下来,解决使用12M外部晶振时,如何配置作为系统时钟源。) H$ k, L! z" T
第一步,修改stm32f10x.h中的HSE_VALUE为12000000


4 C2 |) v8 t2 i. |- z

  1. /**0 ~* k, h* Q5 S, h
  2. * @brief In the following line adjust the value of External High Speed oscillator (HSE)
    " p2 h0 r; r6 t2 A  a
  3.    used in your application 9 k% M+ z; a. I3 `
  4.    
    4 ?' C( F& p* b
  5.    Tip: To avoid modifying this file each time you need to use different HSE, you# W# k/ ^$ F( n- I% w4 w
  6.         can define the HSE value in your toolchain compiler preprocessor.1 ~% E* }6 u* t5 B+ i
  7.   */           
    ( N0 q6 y& e% q. s
  8. #if !defined  HSE_VALUE  ]. O2 F* |; L' f" O2 A5 `1 l
  9. #ifdef STM32F10X_CL   
    ; F+ X6 l; ~: K6 k1 A3 \
  10.   #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */  x+ _0 A0 m% Y1 Y* z
  11. #else
    ) E8 s* S# s, ^5 Q5 C
  12.   #define HSE_VALUE    ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */
    ! c$ c( Y# d$ J0 S9 @5 ?$ E; t
  13. #endif /* STM32F10X_CL */; t. I  e+ W: k* d* g* {
  14. #endif /* HSE_VALUE */
复制代码
3 v% R" g6 p% I

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

' \6 T. Y, W- B) F  N) \+ \+ z8 t

  1. /*** e8 C' I4 W, e3 Z/ _9 _; r
  2.   * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2 $ k) j3 c: e$ w  P) d& |
  3.   *         and PCLK1 prescalers. , X! y: P! R4 Y6 L  u- C
  4.   * @note   This function should be used only after reset.
    % O. i- z, \4 e
  5.   * @param  None/ h: i4 a8 D" D6 n: P, n' }, ~
  6.   * @retval None
    3 l6 {' U( n6 C' w& y
  7.   */
    # d& v  w# V8 {7 |1 X& K+ M+ y2 k
  8. static void SetSysClockTo72(void)$ R' y5 X" s' R5 v! x
  9. {
    ' \5 m1 t* |( I9 q! Y) U: [
  10.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    8 p* r$ Q1 j& T9 i5 T; b
  11.   
    0 t, u9 k( d9 z9 Y0 T/ ?
  12.   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/   
    " c7 ?& [, N( N: k  e
  13.   /* Enable HSE */    : O( F! j0 ^' c) x8 E
  14.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
    ) H2 g& x9 n5 p/ c' O7 n
  15. " C: _7 v' T' {6 }0 S5 Y* J
  16.   /* Wait till HSE is ready and if Time out is reached exit */
    3 Q; V% }& Z5 J; c8 z
  17.   do9 l4 Z: ^6 F) j& W; ^: L
  18.   {
    + L8 ^/ l$ A9 O/ D! t% t- C
  19.     HSEStatus = RCC->CR & RCC_CR_HSERDY;6 ~' U& D" K5 t5 K' L" l' `+ H
  20.     StartUpCounter++;  / P) d! ?" p* ^, e
  21.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));/ T$ G; {. ^5 o! M- C, W' [: d& V5 s

  22. . D+ _" j6 B) u8 M
  23.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)- N9 o1 O0 ?$ |
  24.   {
    . C# J! e! F% N: @( D6 v# q' p6 p. b: ~5 R0 z
  25.     HSEStatus = (uint32_t)0x01;
    2 V! s5 s3 L6 d
  26.   }* y1 |) @8 @8 I# D8 d
  27.   else) I8 O% i8 O/ @' V1 B. g" L
  28.   {
    # a+ Y/ }  |* d5 e- w7 P2 W4 t
  29.     HSEStatus = (uint32_t)0x00;
    1 y& j. \2 E9 v- E
  30.   }  / E% D# i) Q. H
  31. ) R: C- g8 j$ l1 p) i& a2 p0 H
  32.   if (HSEStatus == (uint32_t)0x01)
    * c6 t' F2 g9 d, ]& }
  33.   {3 P4 ~* b! _; }. T
  34.     /* Enable Prefetch Buffer */1 O" D9 @. ]4 {+ J% N
  35.     FLASH->ACR |= FLASH_ACR_PRFTBE;
    , {3 i9 |' C" S. w0 e. N
  36. ! c; l1 e) w2 `& J% |
  37.     /* Flash 2 wait state */( ?% |+ o; G0 O* G
  38.     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    ) Z0 n, ?# Z; t3 p" O
  39.     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   
    / z9 c; P' t0 Q4 F# Y6 ]1 h) \
  40. % v. _* w  b( q6 z  m5 |/ @
  41. 6 `! x; `8 `$ {9 w( D
  42.     /* HCLK = SYSCLK */8 V" r0 t, R; m! r6 B# z$ _' k+ y
  43.     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;5 W" o  |; P5 E, ?5 P
  44.       ; e0 N6 q4 a$ k9 S' v1 Y
  45.     /* PCLK2 = HCLK */
    ' X' \2 N  ]# k1 M7 O; P
  46.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;2 l9 ?, d+ N& M9 X
  47.    
    - {# ]/ F% _$ h- G5 S, K: q7 }
  48.     /* PCLK1 = HCLK */1 W8 t$ O3 N" c1 {2 t" ?
  49.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;5 A$ L1 |$ u) x+ S) z
  50. 5 X: b; a9 o8 N8 A/ z9 C
  51. #ifdef STM32F10X_CL
    ' M. T3 m9 q+ B0 l; \$ x9 G+ n
  52.     // ...
    % p  I! k0 Z4 y, X8 S
  53. #else    / K6 V/ ^* h$ u4 y/ g1 a$ `
  54.     /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */3 e4 [- i6 P7 y: o/ w4 U, _  H
  55.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
    0 w2 `0 [- B4 S7 @
  56.                                         RCC_CFGR_PLLMULL));
    - `7 g$ {5 @, P: M
  57.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6); // 12/ ^3 g: h% _5 a- e6 I
  58. #endif /* STM32F10X_CL */
    6 D/ C5 Z" ^5 o3 n3 O
  59. , K( }9 e6 v& v0 y
  60.     /* Enable PLL */6 p0 `/ Y0 C3 b  H
  61.     RCC->CR |= RCC_CR_PLLON;) e0 k( e# b/ ]" K( @: D, O
  62. 7 h8 l8 `9 S: U. i7 _
  63.     /* Wait till PLL is ready */
    3 ?, w6 f, T" i; i9 S* H
  64.     while((RCC->CR & RCC_CR_PLLRDY) == 0)& i  }, T- ?& E7 h) c$ U
  65.     {
    6 q0 F# D  C1 X: H0 S
  66.     }
    % y' }- Y* T! Q' H* K1 U
  67.       m0 ?: a& ~' ^5 E3 x
  68.     /* Select PLL as system clock source */
    1 N: h: {, L+ S
  69.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    ! e9 f, c: W, S6 {
  70.     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    + O; `& |5 f" C( @

  71. " `) V* c6 X* }6 u- E- {: o
  72.     /* Wait till PLL is used as system clock source */* ~: A2 [# C, I, [7 Z0 o
  73.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    0 t' H$ H4 K7 v1 R) f9 H' Q
  74.     {
    . U+ d8 I7 n; s( A5 K
  75.     }
    : H: A7 I: q$ V& X
  76.   }, m+ k% q% w7 n' T5 w3 }2 A
  77.   else8 K9 K! ?# {" H: m
  78.   { /* If HSE fails to start-up, the application will have wrong clock 1 J: z0 b9 f- }
  79.          configuration. User can add here some code to deal with this error */
    / q3 r$ M0 \" O9 B
  80.   }
    8 Y9 }) i0 i$ W8 A2 L
  81. }
复制代码
; d; ^9 ]) r: Y$ z3 F6 K) ^  A
1 {" t$ `4 j7 {
3 . 内部RC作为时钟源
  a2 h+ K# w7 ^# _7 s

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

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

  ?# s9 Q$ D+ O" Y; Z8 a! [

  1. //开启HSI
    2 h" G: @  W! N/ w" N3 u; Q7 T
  2.         RCC->CR |= (uint32_t)0x00000001;
    $ M6 t2 B# T5 k& n
  3.         //选择HSI为PLL的时钟源,HSI必须2分频给PLL# U1 p! R4 \. P2 ?
  4.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLSRC_HSI_Div2;   }# L' o, R* s  x
  5.         // 8/2 *13 = 52 8/2 *9 = 36 8/2 * 12,设置倍频5 Y# @- q+ _0 O2 z" [
  6.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLMULL12;
    5 E) `- y8 r4 ~: C
  7.         //PLL不分频
    1 c9 g7 D2 M4 H& g: r" V  T
  8.         RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      d5 ?$ H3 W% _3 n$ a  [5 f
  9.         // 使能PLL
    1 V) b# ~5 K1 e+ f/ }4 v. q0 j
  10.         RCC->CR |= RCC_CR_PLLON;
    & \3 @0 s) N+ N$ i6 W7 _6 _# G
  11.         // 等待PLL始终就绪
    7 ]/ v6 b3 L( B) q1 `% o
  12.         while((RCC->CR & RCC_CR_PLLRDY) == 0){}2 _) k! ^/ m" @& q
  13.         // 选择PLL为系统时钟源
    . y- P! S5 Y0 H* I2 T6 |: T" b
  14.         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));$ I! ?5 f1 ]; i5 {3 d' u
  15.         RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;7 ?6 p8 l5 A: r: Y
  16.         // 等待PLL成功
    $ @) |' H7 ~# f+ F0 y- B" G
  17.         while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}
复制代码

& a/ ^5 g$ t5 w/ x2 ]/ v1 v+ Y: B( d$ L& Y
4 .Keil MDK中Xtal的作用

7 G. J4 Y9 Z0 J5 X2 e$ R0 U
: }, u; P/ L4 k+ h6 s4 ~
2.png

( w" w+ F, [! l9 D6 \# E: I
3 {4 ~* o% v# e$ q, s/ [

2 r0 R7 ~% M- @) @2 `9 m
: i. s0 Q) S3 y1 y  h6 p
% f% x2 u! D& }
在手动配置主频的过程中,想到Keil工程菜单应该提供了配置主频的选项,于是又看到这个。百度了一下,这个参数只用于软件仿真的,对于硬件仿真或者直接把程序下载到板子里是没有影响的。9 e, ]% e2 @; M0 W
# B8 z; j* Q0 t$ C
  Xtal 后面的数值是晶振频率值,默认值是所选目标 CPU 的最高可用频率值 。该数值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间。正确设置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相同。
, _+ w3 X, q3 J& H, a6 h2 K6 n0 O: Y( K! {  n8 v

, r3 X4 T  r4 v6 A8 L
" m! c* O+ C* S: p7 y7 A9 R

2 Q" s8 }- }1 h8 x
收藏 1 评论0 发布时间:2020-9-14 12:41

举报

0个回答

所属标签

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