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

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

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

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

/ Z: r4 b# G: @0 {8 i

  • HSI内部8MHz的RC振荡器的误差在1%左右,内部RC振荡器的精度通常比用HSE(外部晶振)要差上十倍以上。
  • 内部RC频率受温度影响比较大,如果省电Sleep模式下内部RC会停止工作。
    6 C2 s) N; x& d: l0 n- U6 L
    5 n9 S3 q1 w' N6 t- N. l3 K$ g3 _$ `
4 x9 ]% [; H- Y8 u( l

6 U: j8 q3 Y4 O2 u* b5 M1 . 时钟系统
2 x. A3 L8 _- Y% y; z% j. o

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


9 y' U0 D; H. T5 x) w/ Y

  • HSI是高速内部时钟,RC振荡器,频率为8MHz。
  • HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
  • LSI是低速内部时钟,RC振荡器,频率为40kHz。
  • LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
  • PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
    8 {% Y) I5 h- o( |( M1 R

% ?4 I& s9 P( `0 E% G2 a
1.png

, _. [" c% _+ T$ O# O
: j/ R. q$ ^' G( F: Z' A
- X8 v. a; E/ a# Y; A( {

 用户可通过多个预分频器配置AHB总线、高速APB2总线和低速APB1总线的频率。AHB和APB2域的最大频率是72MHZ。APB1域的最大允许频率是36MHZ。SDIO接口的时钟频率固定为HCLK/2。/ `1 _  x; l5 s0 M0 x  O
  40kHz的LSI供独立看门狗IWDG使用,另外它还可以被选择为实时时钟RTC的时钟源。另外,实时时钟RTC的时钟源还可以选择LSE,或者是HSE的128分频。RTC的时钟源通过RTCSEL[1:0]来选择。
$ Q1 t7 E* I2 }" e) ~- @  STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz。6 r, B' F3 h6 f9 r6 {: X
  另外,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大模块使用:

  Q, o/ k3 B" P; c

  • 送给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 J5 q3 a' G7 m5 ?0 G7 _
    & E# Z; M9 ~& H) ?

: G' s9 b8 J9 G. N2 . 外部晶振作为时钟源
2 F1 E' l+ x4 B8 r; S

接下来,解决使用12M外部晶振时,如何配置作为系统时钟源。
7 ?/ i6 H+ Q& Z' W4 g, ?第一步,修改stm32f10x.h中的HSE_VALUE为12000000


: Z8 z6 c; E% t0 ^

  1. /**% i8 ~- w' ]7 h$ `/ G7 d1 W
  2. * @brief In the following line adjust the value of External High Speed oscillator (HSE)) b/ L5 u# R. l
  3.    used in your application 8 c/ g+ i$ y/ u0 {
  4.    ) `- R1 _0 s; m. q8 r( t7 w
  5.    Tip: To avoid modifying this file each time you need to use different HSE, you$ I. r0 X: Y0 I. k" ]& q
  6.         can define the HSE value in your toolchain compiler preprocessor.  F9 ^1 r/ K! U, ]* A  |* z8 d/ h& V  q
  7.   */           
    6 R/ U/ `' K& s
  8. #if !defined  HSE_VALUE3 k6 [9 r; p4 b% V- F1 ~
  9. #ifdef STM32F10X_CL   
    ! b9 Z) B; _5 n; g% H3 `
  10.   #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */) k) c3 R$ I/ O( u
  11. #else + s7 U: C0 E5 D; q! S: s: q
  12.   #define HSE_VALUE    ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */
    8 w; \% B( {5 w4 l: k9 E; z6 Z- q
  13. #endif /* STM32F10X_CL */9 }9 b/ ^0 U2 L3 D- v) o+ R6 l
  14. #endif /* HSE_VALUE */
复制代码
$ {# z1 y4 G" ]* t

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

' _7 m" C% }8 p( n+ `

  1. /**$ \( }) M' A5 @6 L5 F6 e% f
  2.   * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2
    2 L' G  _% |: O* a
  3.   *         and PCLK1 prescalers. $ e9 t: f9 ?/ T- Y# I
  4.   * @note   This function should be used only after reset., Z8 f, b) c2 q- w
  5.   * @param  None, f5 U8 a5 P* l9 O* d* O6 _0 C  {
  6.   * @retval None
    , O: J; {( \( D0 k4 e! }
  7.   */1 K* n. ^" |- M5 q/ a4 l
  8. static void SetSysClockTo72(void)
    7 _; r" F4 d6 I9 h
  9. {  Z8 M( }( K: V! }1 c
  10.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    # T# H5 Q, o+ f& r& j
  11.   
    $ v2 ?" V: ^$ k
  12.   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/   
    ; Z) r# y+ U# E  H' u- g
  13.   /* Enable HSE */   
    " ~# ^# n# e! n1 ^7 K0 i& h
  14.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
    0 Z1 H7 }0 z$ }$ p) r. A+ j+ \$ d
  15.   n) l* g3 v2 i
  16.   /* Wait till HSE is ready and if Time out is reached exit */
    3 h. G6 f# B6 l+ Q
  17.   do$ J/ S+ O: s8 {
  18.   {3 \$ ^- O/ Y% E
  19.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
    2 g4 a- K4 C' ^
  20.     StartUpCounter++;    Q2 _5 P  m1 W1 ~+ A6 y9 s
  21.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));# e  A2 i8 _7 F" X' ~2 y. d
  22. % ]3 ?$ R5 u# f# e. v2 Z/ Q; C1 T
  23.   if ((RCC->CR & RCC_CR_HSERDY) != RESET); e$ U- T6 J3 I  R& K8 T; [
  24.   {
    + _8 A, T& Q0 K) X3 N' S" d
  25.     HSEStatus = (uint32_t)0x01;; E* r$ B+ m2 A2 J* {9 ]
  26.   }
    + z/ W- r+ ]# Y( P
  27.   else
    ; l3 F7 F, }8 O' [) K7 J# Y
  28.   {
    4 b* O* w8 \7 x$ M! L8 w
  29.     HSEStatus = (uint32_t)0x00;0 [! z0 i5 c5 p! I3 {5 y9 {
  30.   }  
    0 Y2 C9 A7 ~+ [# Q+ e/ G1 F
  31. - K3 i/ ~" M. Y2 T0 c! {* d
  32.   if (HSEStatus == (uint32_t)0x01)8 J( F! `8 A4 ^# B4 }: G+ @3 G+ i9 ]
  33.   {& F/ q8 W8 H  ?- e" b9 E1 f3 W
  34.     /* Enable Prefetch Buffer */) V  B& y) ^4 ~* c4 x: J' I( R
  35.     FLASH->ACR |= FLASH_ACR_PRFTBE;
    2 E* m3 H7 H/ y" }+ u/ j
  36. 5 d  Z) m+ |* x- x& @, A
  37.     /* Flash 2 wait state */( l! j+ L" }. t0 d2 E0 w
  38.     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    ! m+ N; w" Q- J3 O. K$ I, ]' R- h% |
  39.     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   
    , ~* J3 d: E8 g: e- f- d, f
  40. # U$ W# J2 _/ v! N1 s+ V

  41. 0 ~& a4 {8 t1 i: n: j' H* R
  42.     /* HCLK = SYSCLK */
    ) D2 g& W: r+ m- B0 D1 S
  43.     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    / W# U) o; V" j
  44.       
    - V3 [5 m4 `- ^1 h
  45.     /* PCLK2 = HCLK */2 J& F) C+ Y1 R8 p5 c/ z% G: {) w
  46.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;& p. j9 t9 B0 f4 X% }& ?* l( _
  47.     ' ]7 g: Y: V1 G3 G
  48.     /* PCLK1 = HCLK */
    * _) o: p* ]- o
  49.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;. G8 [: q: l( G. e- j% C

  50. 7 B# c" U9 m$ r6 I0 A
  51. #ifdef STM32F10X_CL
    / y0 n2 P: k2 S  ]
  52.     // ...
    * l5 E4 W4 {& W' W
  53. #else    5 ]" r: }$ g0 z# d1 k; B  D# |
  54.     /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    3 o! S4 N2 U$ u1 j( i* l7 O
  55.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
    2 z9 e1 \* t' B2 ^2 a2 H3 e' d3 Y
  56.                                         RCC_CFGR_PLLMULL));$ V1 P! p# Z3 F# e
  57.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6); // 12
    ; g; v' O! b& v/ b& s
  58. #endif /* STM32F10X_CL */, f0 A& ^- a+ Q9 z' X
  59. 0 u4 Y0 o. x- j  T% u
  60.     /* Enable PLL */
    9 |; q* A, M) I4 \" n  f1 H( f
  61.     RCC->CR |= RCC_CR_PLLON;- ]) b  ?* r3 ]* I! X/ Y& i. r

  62. 4 \: w: V$ Q9 C
  63.     /* Wait till PLL is ready */
    ) z# k) p0 L0 q5 N9 n
  64.     while((RCC->CR & RCC_CR_PLLRDY) == 0)9 A- \$ \4 V- y8 W/ o
  65.     {
    1 y7 ^' @% C( A1 }+ }8 T; `5 V' d
  66.     }
    3 U# M( j' R/ D$ M
  67.    
    9 t+ L8 v- v) v* u: n4 H
  68.     /* Select PLL as system clock source */: h. |* N6 C  \: O3 h4 ?; P
  69.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));& {( s* r* h( f; b( m( j3 m& j
  70.     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   
    . _4 r: t: v, O8 {1 `! j  _; \- M$ x

  71. 9 Q8 f) N  y# m( d1 l( B( Z: e: b! Z
  72.     /* Wait till PLL is used as system clock source */
    ) N" G( s2 {8 E! I
  73.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)% r9 R% L' k% R
  74.     {: o, i0 o" S( B) O; N$ P& J
  75.     }
    : K* E; k8 P1 s/ J3 o/ i
  76.   }
    - W7 `& L2 \. t+ ?- q
  77.   else; W1 [' R% ]+ U& G
  78.   { /* If HSE fails to start-up, the application will have wrong clock
    5 I' A! r8 C" y+ U& V
  79.          configuration. User can add here some code to deal with this error */
    8 d9 D- B" E! ]" S/ I' A( }- y
  80.   }
    ; {, T% K2 F& U8 Z& k8 `
  81. }
复制代码
. X; P2 T7 W8 @9 Z3 K2 c' n: m9 E

% Y& [& f1 t# o# R& h; ~- i. d3 . 内部RC作为时钟源
. J; l1 G5 c# \! Z. R

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

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


% A4 v- a' U4 h& ~* K, c: U

  1. //开启HSI! P  Y* l9 E3 x/ k+ E* d
  2.         RCC->CR |= (uint32_t)0x00000001;
      }4 k8 [; W$ F+ [0 }( u. t
  3.         //选择HSI为PLL的时钟源,HSI必须2分频给PLL. h! f3 A1 N( d9 M' V
  4.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLSRC_HSI_Div2; 9 }% V: f1 R8 |6 h9 `+ `  q
  5.         // 8/2 *13 = 52 8/2 *9 = 36 8/2 * 12,设置倍频
    . }% p/ Y8 a2 |0 `; ]
  6.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLMULL12;+ H, ?. t( ^( \! U% l, N
  7.         //PLL不分频: t3 z) O8 X: \3 _5 s& T, S
  8.         RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;' l/ ]5 Y: U6 D. W, f
  9.         // 使能PLL
    & w9 k) }, @$ @( G- k7 S; h" H' X
  10.         RCC->CR |= RCC_CR_PLLON;
    7 W9 {; C3 i' F* N  X7 m/ e" G  x
  11.         // 等待PLL始终就绪
    & v/ X  F; g1 z. {' |# c6 j
  12.         while((RCC->CR & RCC_CR_PLLRDY) == 0){}8 y' P& K+ h" @7 W+ Y
  13.         // 选择PLL为系统时钟源1 A/ A/ l+ m2 T# e# B+ L  p* P2 N
  14.         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));" V2 p; N7 h. k- f0 ~$ J
  15.         RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
    * o) \9 |/ e3 T" _
  16.         // 等待PLL成功( h! i4 Q' u  k# }9 s2 f/ J
  17.         while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}
复制代码

1 G2 m1 C3 Y2 v% D+ ?4 _6 d
1 Z' G. \5 S  S3 h4 C) E4 .Keil MDK中Xtal的作用

  W& N6 @& `: H/ J4 B% Z  f1 z% S1 Y5 ]0 f7 t' t$ q1 b. L% ?
2.png

9 d1 Q, W( N# c% [6 n6 B* W# Q! A# c

' a. Q( _7 `% Z( S$ p6 V/ v3 G" t
/ ]" `8 I4 p/ L9 f

: f$ {7 B, Z5 y* i, w& P在手动配置主频的过程中,想到Keil工程菜单应该提供了配置主频的选项,于是又看到这个。百度了一下,这个参数只用于软件仿真的,对于硬件仿真或者直接把程序下载到板子里是没有影响的。
$ i9 p6 L4 Y- o; Z7 F4 z) L8 K5 |
  Xtal 后面的数值是晶振频率值,默认值是所选目标 CPU 的最高可用频率值 。该数值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间。正确设置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相同。7 x. M6 I; m1 X5 Y# r2 K

$ a0 O  a# |  U% ^- d
, S6 B. X/ Z! W) [
. Z3 K( E$ |- e/ O6 e) \% i+ u
/ V( Y: Y5 ^- d; Q4 m; d, z4 C
收藏 1 评论0 发布时间:2020-9-14 12:41

举报

0个回答

所属标签

相似分享

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