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

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

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

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

; \/ m: U  c4 u- e

  • HSI内部8MHz的RC振荡器的误差在1%左右,内部RC振荡器的精度通常比用HSE(外部晶振)要差上十倍以上。
  • 内部RC频率受温度影响比较大,如果省电Sleep模式下内部RC会停止工作。4 \1 y) X7 ~% L) U

    5 G! s) b* d2 Y9 Q' ^( W6 b
9 I. H3 R: d9 U5 m8 v5 z$ K

' k+ ^: ]1 m; w  K, {- q1 . 时钟系统
7 X( K! p; e* ^. i

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

: u4 F# D$ z3 _4 G9 M

  • HSI是高速内部时钟,RC振荡器,频率为8MHz。
  • HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
  • LSI是低速内部时钟,RC振荡器,频率为40kHz。
  • LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
  • PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。( d: \& H% E- f' V6 u0 M$ Q

0 ?8 r+ n: k7 u
1.png
; i% N6 w3 G) j
1 O! N0 ]! d0 z9 ]

; M7 d* u. v+ r. w! O# o

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


5 N; n) m9 z) ?- i" L8 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)。
    ( Z+ `' e3 s4 N5 \! l7 e  E

    ; J* r% _% Y( C& k+ f3 x. E
; T3 Y5 U6 @* h; n! I2 {
2 . 外部晶振作为时钟源
* U4 H* E, e  O2 y* u4 F0 E

接下来,解决使用12M外部晶振时,如何配置作为系统时钟源。
5 J5 t1 o6 X, o* M4 X3 u! ~- {3 r第一步,修改stm32f10x.h中的HSE_VALUE为12000000


: h4 R: ~2 F) p  h, h. W. O$ }0 {, E

  1. /**
    4 C$ x4 a0 l2 K  w9 C
  2. * @brief In the following line adjust the value of External High Speed oscillator (HSE)% V$ \4 @+ R! A9 J6 }! c, f9 H4 M
  3.    used in your application
    8 m7 o8 U  b  \
  4.    
    1 i1 |( n% t2 ^# L& g6 R. O! D) ?
  5.    Tip: To avoid modifying this file each time you need to use different HSE, you
    ! Q8 A! |, @. a4 j
  6.         can define the HSE value in your toolchain compiler preprocessor.
    , ^1 Y5 T- O  ~9 R$ d
  7.   */           8 G. c' g( I9 A% H% d
  8. #if !defined  HSE_VALUE
    & W* J4 {. {* _/ Z) P& H$ S
  9. #ifdef STM32F10X_CL   0 d' m: G4 L/ R( O/ b9 M
  10.   #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
    0 ^& p# J5 G+ s" l" W5 H: b! D5 u( g- J
  11. #else
    , _( G6 h2 r0 K" u: E8 C) m6 y$ g# [
  12.   #define HSE_VALUE    ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */5 _8 C; l, W  @* i( c
  13. #endif /* STM32F10X_CL */
      k8 I# g0 o$ r# D
  14. #endif /* HSE_VALUE */
复制代码

- ~, ]) d- v/ Q" j

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

) ~: C- U4 v/ S8 H+ w

  1. /**
    4 M- |5 T/ f2 |4 z  _# G+ F6 Z: {
  2.   * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2
    " i2 g/ l) H# U8 A( A  d1 V6 X) x
  3.   *         and PCLK1 prescalers.
    * w$ \- ]9 @4 `6 b$ k/ h0 }; }0 ?: I
  4.   * @note   This function should be used only after reset.* f# D# |* v: H+ Z5 ~
  5.   * @param  None5 ?' Z! t* h: e
  6.   * @retval None# |( p2 X- R( O0 @0 C
  7.   *// {" @# O. N& o8 {
  8. static void SetSysClockTo72(void)5 v* @( x  r% I6 f: [1 M2 \
  9. {
    4 D% g$ z. G7 h! \- K
  10.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    7 ^+ T1 G* W  t
  11.   
    ( \. }% s6 j' F. {( ]& Q) Q
  12.   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    ( W5 i5 x) Q  z& A
  13.   /* Enable HSE */   
    : e+ A4 a* i0 ^' X
  14.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);/ U; W  T, g5 k7 a8 }0 u, u
  15. # @6 E' e, s5 C8 C6 O
  16.   /* Wait till HSE is ready and if Time out is reached exit */- Y8 [7 n* f( G5 A1 o
  17.   do* {0 J( `8 {! `: Q
  18.   {
    # U4 P- ~. Q/ {- L: V1 @
  19.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
    / X' e; G: p& ~* S7 E% S
  20.     StartUpCounter++;  # N+ p/ T) t3 q. d5 S5 ^4 r
  21.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    1 r$ a$ ]5 N2 B  _

  22. $ T" j) x0 T* `6 K% J5 A
  23.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)$ z' C" T" E% P* D$ k
  24.   {
    $ [. T/ \! \! @- R" R; G# M" d. F8 ~
  25.     HSEStatus = (uint32_t)0x01;) }! q  R! Q1 w; d
  26.   }
    9 K0 K+ g# ?9 q5 B) Z! }0 M
  27.   else
    0 |" p3 A( f/ w* B$ J$ J, j
  28.   {% K$ k8 k; h7 T% V9 g* w
  29.     HSEStatus = (uint32_t)0x00;& ?' R+ m% M" v. w+ _
  30.   }  
    2 s+ D& [- ~! o* ^0 q( x9 p

  31. ' M) \% y+ C+ b0 ^9 _$ {
  32.   if (HSEStatus == (uint32_t)0x01)
    + C# _0 a* {$ ~/ X7 f$ a- n
  33.   {
    : P7 `" ~. I- M& M* @6 v( A( O' h
  34.     /* Enable Prefetch Buffer */) d" m4 i" \+ k% A6 r
  35.     FLASH->ACR |= FLASH_ACR_PRFTBE;$ @4 S: [1 Q. [8 X& P& {

  36. ) t4 D, I3 b0 B. j9 d
  37.     /* Flash 2 wait state */
    4 h! O3 g0 J2 k6 k7 T4 K- U9 E7 R0 _
  38.     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);, n: _/ a) N0 X; S" l
  39.     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    : {3 N9 f" z: j# N

  40. " l" e/ R  d- S
  41. 8 g' s2 h# N' D% M$ J5 I0 u( b
  42.     /* HCLK = SYSCLK */. x& o5 B3 h0 B' a; _& S! @! f
  43.     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    - R( D; h0 H1 Y6 |4 z/ H
  44.       
    - N  m9 n5 F* P6 T
  45.     /* PCLK2 = HCLK */9 h. `" O7 o  _% T
  46.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;8 ^+ }" s1 O$ P) r6 T
  47.    
    + O& E2 U+ c/ P0 C4 O, s. c# R! a3 J
  48.     /* PCLK1 = HCLK */
    % }8 ]0 T$ a, ]: N8 z* }
  49.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
    : q9 J1 n$ A  U3 J$ ?' @# _
  50. ; ~0 [) h; ^  X8 ]: U9 k' H
  51. #ifdef STM32F10X_CL5 B6 w& i0 h- D7 I( x. \- l
  52.     // ...) w  ^7 P1 p( P, e0 \, r
  53. #else   
    8 O9 ?  a% g! I7 Y8 a$ l: u0 j& S; U1 N
  54.     /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    6 g+ U7 e1 g9 \( V' L7 Y& T
  55.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
    " _3 V6 ?7 M/ E# b* u1 R) N! K
  56.                                         RCC_CFGR_PLLMULL));9 I# a; l* X" G6 H0 S$ J; i; Z% b6 I
  57.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6); // 12
    : w& s5 O+ k- z7 g4 f: D; R
  58. #endif /* STM32F10X_CL */
    & s  [' t" G1 T8 \
  59. # P* I7 c0 l  |* y7 h! V. ~$ Y
  60.     /* Enable PLL */
    : |- w. Q1 E, U* j+ F8 l
  61.     RCC->CR |= RCC_CR_PLLON;
    : E) U7 \! V- |" C' T& G3 i+ J! R
  62. / k8 ?5 Y. g0 O/ L3 Y7 |
  63.     /* Wait till PLL is ready */8 N- L/ J% A2 ^' S* Q9 r& y* Z
  64.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    ' ~  W8 M% o6 m& s: `
  65.     {" r- ?8 r# c& F& c% d8 y6 M
  66.     }' b# F( f- c$ P) f* t2 u
  67.     & Q3 i) e* e  \1 b& q9 M
  68.     /* Select PLL as system clock source */
    1 ~, _$ ^: i1 `) R9 L) H
  69.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    7 M0 ]2 o2 T" s) X4 ~2 X4 X
  70.     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   
    + T! @5 T8 Y3 m# \0 a9 }
  71. 5 z* e6 C' X) w. C) C5 H, k! V
  72.     /* Wait till PLL is used as system clock source */; w) n8 i7 H& |/ H
  73.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)8 d& r; X; W8 A+ a  r1 \: |
  74.     {
    2 t0 s9 W+ d6 s8 ]7 ^& N% S
  75.     }
    ' ?# P. p+ ]; R% W
  76.   }* m0 m% Z. X' ^. f! N
  77.   else, D5 W4 u! U- {
  78.   { /* If HSE fails to start-up, the application will have wrong clock
    ; H+ }4 C; G5 {, y$ f3 m
  79.          configuration. User can add here some code to deal with this error */: [9 Y' G% \: X( W
  80.   }
    # k" r8 g4 _; x6 v! d
  81. }
复制代码

% D$ m: f) w1 B) a* `5 M9 f8 w
4 x* ]/ h. o# _! e& z: @$ X3 . 内部RC作为时钟源

: {8 ^6 r, {* E3 `  {

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

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

+ J' K# P+ a( N% I. ~

  1. //开启HSI
    ' G0 Y; z8 W, y* p
  2.         RCC->CR |= (uint32_t)0x00000001; + E' U$ n2 p2 O
  3.         //选择HSI为PLL的时钟源,HSI必须2分频给PLL2 W! }/ v: P8 j. G) u
  4.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLSRC_HSI_Div2;
    " W0 b2 F1 M: {, H" J
  5.         // 8/2 *13 = 52 8/2 *9 = 36 8/2 * 12,设置倍频% o( o! D7 M' H3 }
  6.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLMULL12;
    2 T/ k# _9 B, B
  7.         //PLL不分频+ _9 E& A* K2 y1 ]
  8.         RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    6 v% s: G, O  O4 x0 L4 d
  9.         // 使能PLL; b7 O( c/ K: }5 u- q
  10.         RCC->CR |= RCC_CR_PLLON;
    $ M8 J5 ]; |0 a9 _: c
  11.         // 等待PLL始终就绪3 b$ [- V# B* P. U' Y5 @) ~3 C
  12.         while((RCC->CR & RCC_CR_PLLRDY) == 0){}
    7 r) e4 z+ B  Z- _, k
  13.         // 选择PLL为系统时钟源
    % j( r+ k  J7 O" X' ^7 Z0 w- @# c
  14.         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));8 E, H# B3 J: G! O1 H+ S6 t2 B
  15.         RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;" A- D$ s$ }2 ?3 O
  16.         // 等待PLL成功  z+ i/ ~% x3 G3 z6 {  Z$ _9 N
  17.         while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}
复制代码

1 e8 s5 B5 x) K- O$ b3 g
# F4 E. _2 T4 @4 .Keil MDK中Xtal的作用

3 n5 e$ j8 R$ E
9 G9 E- y. T6 R: U' \' m
2.png

  ?4 G6 l/ J) W5 L# E( Z" u( |/ I0 x1 A: F( g4 w1 V# ~; O3 z' W; z* S
$ j7 A; d/ H) T9 H5 r( W- e

- l! c" h6 k& f5 a+ P- @
- k7 h! A, ^3 `! c, v% B
在手动配置主频的过程中,想到Keil工程菜单应该提供了配置主频的选项,于是又看到这个。百度了一下,这个参数只用于软件仿真的,对于硬件仿真或者直接把程序下载到板子里是没有影响的。; L! T, e9 ]2 j) p# I

; G4 H6 o& b. z5 a7 V$ B
  Xtal 后面的数值是晶振频率值,默认值是所选目标 CPU 的最高可用频率值 。该数值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间。正确设置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相同。, |+ k& j9 n% ^5 i/ ~

5 H" f  g9 f6 L/ b& a- x" u$ P/ l6 k3 p9 R7 H1 S: g

1 j7 ]- B5 `6 E) \5 v, I; c" ^# F; [! g5 z0 o
收藏 1 评论0 发布时间:2020-9-14 12:41

举报

0个回答

所属标签

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