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

【经验分享】STM32系列单片机在进入main函数前都在干些什么?

[复制链接]
STMCU小助手 发布时间:2022-3-21 13:41
        在刚开始学习单片机的时候,一直以为程序启动后就直接进入到了main函数,但是随着学习的深入才发现,程序在进入main函数前其实还要干好多事情。现在就来分析一下,STM32系列单片机程序在进入main函数前都在干些什么?1 p- m4 i. V% l8 n/ K. m2 ^

3 d6 c1 C" i5 K2 b6 e5 t R}CAY_WL)2P2SXEM{4@MD@K.png 7 J5 y8 i6 T! n$ F. H0 q1 l
, B2 p3 N% S0 z( g; I5 x
       单片机上电后,程序首先跳转到地址0处,此时主堆栈指针MSP的初值也为0。然后单片机产生了复位信号,主堆栈指针加1,由于单片机内核为32位,所以地址增加一位,实际上是增加了32位,也就是增加了4个字节。此时MSP指针就指向了复位向量。而Cortex-M内核处理器的向量表可以重新定位,所以此时程序就会跳转到复位向量重新映射的地址处。
; D$ Z' L7 H* C  N8 o- c: ~1 ~6 J: y9 O3 w, o$ O
_%3]EKZKPMAOD}WXWJBQI.png
9 h. r+ Y" N; Q% O, m JMNH_KOQ~%[TAO`]QQPV9{W.png ; c/ z4 P; k; s
: }+ D: ~6 [& i% z
          通过上面的两个图可以看到,通过复位向量的重映射后,MSP指针就会跳转到复位向量处,在STM32系列单片机中,复位向量的函数通常在启动文件startup_stm32f10x_xx.s中实现。
9 b# R$ ?4 f5 D+ g: l
& m- L' d1 ~7 E& [$ S3 D下来接着看一下复位函数都实现了哪些功能。
, D0 P& l8 ]; a4 D
: T# Z: ]# ~& E8 N& J& a1 D7 q5 v 1]CWCQQKY{~GC$I5_LXV(MR.png 3 o& z0 n6 M; i. ~$ Z: e$ e& H

/ y5 S$ k6 C9 l7 v1 S" e        可以看到复位函数首先获取到了main()函数和系统初始化函数SystemInit()的地址,然后跳转到系统初始化函数中SystemInit()中,接着就会跳转到main函数中。7 n* Z. r; E' ?- d

" s$ Q, z1 C' H2 r( S2 f! P
  1. void SystemInit ( void )
    # b  _% r9 u: H
  2. {9 |' d. X: a/ e) M+ Q& o$ |) y
  3.     /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
    ( [$ d! x* R) e7 K; h0 I) C3 R0 S
  4.     /* Set HSION bit */# N* e3 w# K- ~$ X* v  K) y! y
  5.     RCC->CR |= ( uint32_t )0x00000001;
    # ~0 I! u$ k! @9 H

  6. 5 x: e' `+ X0 p8 \! h2 v
  7.     /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
    ( ?5 }# D" }) a8 e! ]- A: p
  8. #ifndef STM32F10X_CL6 \$ N5 l, q8 k- g; G
  9.     RCC->CFGR &= ( uint32_t )0xF8FF0000;& G- G* m% F2 u0 G4 K" g
  10. #else  G, i4 h# e- l3 T- i% `- H
  11.     RCC->CFGR &= ( uint32_t )0xF0FF0000;
    1 f1 M, v( z. Y: l
  12. #endif /* STM32F10X_CL */- u" Y+ x1 l5 t
  13. ! ~0 y) R5 O# y+ Y4 j; X
  14.     /* Reset HSEON, CSSON and PLLON bits */  K2 d6 C3 t* c  m# t3 h
  15.     RCC->CR &= ( uint32_t )0xFEF6FFFF;. W. R/ S8 h- y4 |$ U6 p) V

  16. ) K' C1 _7 Y* {" ]3 C) ~
  17.     /* Reset HSEBYP bit */
    / i$ i* h/ O4 y4 z, p" U2 c/ S$ ?
  18.     RCC->CR &= ( uint32_t )0xFFFBFFFF;9 v3 k2 H1 Z1 Q7 D$ a
  19. ! }! I* t$ n! m! Q; x( ^( b& o* \+ [
  20.     /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */+ b0 ]* s$ E, e2 V% {3 G
  21.     RCC->CFGR &= ( uint32_t )0xFF80FFFF;+ u& ]+ O; z+ W0 u! h  C4 X
  22. 0 Q" A1 t3 j1 M' I0 w
  23. #ifdef STM32F10X_CL
    + s$ _! M. r- s9 ]3 E. F
  24.     /* Reset PLL2ON and PLL3ON bits */
    - a5 P7 S) i8 A$ a6 h! I
  25.     RCC->CR &= ( uint32_t )0xEBFFFFFF;! F( n: o& @3 k1 t5 p1 w

  26. 0 I; [1 b6 ]9 C! f) _
  27.     /* Disable all interrupts and clear pending bits  */
    6 ?0 f0 v, I& N) D% n- z' P9 {
  28.     RCC->CIR = 0x00FF0000;1 L3 \3 X" @+ g  e8 e
  29. + A$ _7 z) Z9 B* }  w
  30.     /* Reset CFGR2 register */5 A, E" b# u' c+ j6 z" X
  31.     RCC->CFGR2 = 0x00000000;
    4 V- L1 l# ~8 N$ z- A$ U
  32. #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)( H+ h/ }# b  y$ v
  33.     /* Disable all interrupts and clear pending bits  */
    * G$ Y# N3 z8 \6 i
  34.     RCC->CIR = 0x009F0000;6 E5 G$ O: F/ c7 ]1 F4 `/ T

  35. % E0 F4 `; p. a: v
  36.     /* Reset CFGR2 register */4 A) E6 c2 I- U: `4 m, x/ Y
  37.     RCC->CFGR2 = 0x00000000;
    ; v& H8 w* M$ V6 W# n4 Y" Z3 L
  38. #else
    , j$ Q0 Y4 r5 A! i! T
  39.     /* Disable all interrupts and clear pending bits  *// [* |7 l6 O' F$ P% |( A
  40.     RCC->CIR = 0x009F0000;/ P" S: b' c& i+ g) z2 Q8 q
  41. #endif /* STM32F10X_CL */
      R! q$ I9 a7 b$ \
  42. 6 ]; e( [" u9 f  b" r
  43. #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)2 T0 m! S( t: Y  h8 C; F
  44. #ifdef DATA_IN_ExtSRAM
    # A& H6 D. R5 S; Q
  45.     SystemInit_ExtMemCtl();
    # K0 s& u3 o- @4 l, t; x
  46. #endif /* DATA_IN_ExtSRAM */
      A- _% M# i9 _! F8 G8 @
  47. #endif, w# s& H/ F$ ]0 ^$ ~6 `* I

  48. 3 h: z  ]  j2 b* T
  49.     /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */* G' K9 \  _7 y" O0 }9 Y9 k
  50.     /* Configure the Flash Latency cycles and enable prefetch buffer */2 C; @/ v' g) U6 p) d5 K2 K% k, R
  51.     SetSysClock();
    3 b! m2 C  c3 i3 `3 U6 n" H

  52. & l6 e! Z- i! o: q7 N( G$ U8 a
  53. #ifdef VECT_TAB_SRAM
    & ]' [- h  ?/ H
  54.     SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
    5 n" s0 X: Y1 g
  55. #else
    8 m! o  w& f7 P
  56.     SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
    8 K  a9 p" ]& ^+ j) S
  57. #endif9 ^$ x2 N2 n6 U3 w' \. o& }* ?4 {+ w
  58. }
复制代码
" P% b4 j& |( M7 v  D) B
         在系统复位函数SystemInit()中,主要是复位各个寄存器,将寄存器值设置位默认值,最后调用时钟设置函数 SetSysClock()对系统时钟进行设置。
# G+ C9 [+ ~4 a5 _) r, p7 ]& q4 i% Q7 t
  1. static void SetSysClock( void )
    ' d& T" C' {* n7 K  a* u
  2. {0 l6 L- c7 ?' L) Y1 }/ M. {" ~# d1 N
  3. #ifdef SYSCLK_FREQ_HSE1 R# w; K' D9 S0 Z8 l. p! _' k
  4.     SetSysClockToHSE();
    " j: R$ P" I1 h& Z0 k+ U( Q, K
  5. #elif defined SYSCLK_FREQ_24MHz6 u6 a) d7 H. e) j# G
  6.     SetSysClockTo24();  A) w' g6 i1 D7 b
  7. #elif defined SYSCLK_FREQ_36MHz
    5 O' f8 y- |0 l/ I
  8.     SetSysClockTo36();
    ( U" C. V3 O5 z* ?1 I7 p0 d
  9. #elif defined SYSCLK_FREQ_48MHz6 ~9 _/ I; }; P8 t. s: `( I
  10.     SetSysClockTo48();
    7 h4 t* `5 X# ^% X1 e# Y! E( U
  11. #elif defined SYSCLK_FREQ_56MHz
    4 [) `9 S/ ]4 |1 X4 Q
  12.     SetSysClockTo56();
    5 T9 w1 B) a: W+ S! o
  13. #elif defined SYSCLK_FREQ_72MHz
    , n6 k7 q3 U. M+ G! D
  14.     SetSysClockTo72();* J; Y; p. }( k& ~, [/ Y  C0 o" o
  15. #endif
    - {* @" ^) Y2 b( A: j! u* N$ |

  16. 9 q5 _" a0 v: ]3 G9 C+ F% H# S
  17.     /* If none of the define above is enabled, the HSI is used as System clock
    7 J  h5 k2 l7 S- m1 [# T( X
  18.        source (default after reset) */
    - w2 P% w8 n, P) V
  19. }
    ; h0 @1 P" N& m$ o" E4 @; j3 a" J, X
复制代码

( A$ c2 s5 a1 s& L: P系统设置函数,根据不同的晶振和单片机型号,选择相应频率的时钟进行设置。
1 _! ]) t/ E- Z( K/ ?6 i  t1 l7 @' @) [5 E' h% d$ \6 ?
  1. static void SetSysClockTo72( void )6 L" [  T3 V4 ]
  2. {# ^9 S/ A1 w/ ]- H/ V2 n* u
  3.     __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    2 K7 w3 B/ {* _6 ^' p9 L
  4. 7 Z# W+ w  i5 w1 |7 ]* k
  5.     /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
    * M- X- }; X( }+ b. n
  6.     /* Enable HSE */
    ; j0 g- N6 E  a
  7.     RCC->CR |= ( ( uint32_t )RCC_CR_HSEON );
    : K1 |" v, \! o" }) P

  8. * O/ e- {# r! L" F% I1 ~
  9.     /* Wait till HSE is ready and if Time out is reached exit */
    & Z6 F( o! c$ o. _$ S
  10.     do* ~8 ]6 W" {# ~
  11.     {% ^) ^+ Z* e" l9 s3 p6 B
  12.         HSEStatus = RCC->CR & RCC_CR_HSERDY;0 I  H) B( I* w0 `3 U
  13.         StartUpCounter++;  p. q! d3 j- ^+ h( H  ]- f0 c/ n
  14.     }  Z4 @$ b7 a7 h, N" g- q
  15.     while( ( HSEStatus == 0 ) && ( StartUpCounter != HSE_STARTUP_TIMEOUT ) );
    * I* C) z& I! g6 ], p, f( @# e
  16. 8 T) l1 c4 t7 U( J3 P8 U6 p) o
  17.     if ( ( RCC->CR & RCC_CR_HSERDY ) != RESET ). r$ B: `5 N# c
  18.     {+ K1 T! h; r: K9 b, b0 b1 b+ @9 ^
  19.         HSEStatus = ( uint32_t )0x01;
    ; x9 ?$ v- Y+ ~; {
  20.     }
    7 Y3 f; j, Y! l4 ]  e; j' \0 ]
  21.     else9 l( D9 g) R! y1 I7 D
  22.     {
    ; ^4 j' |3 M; l% C4 a& ~
  23.         HSEStatus = ( uint32_t )0x00;
    - y4 Z" }$ O' q& e
  24.     }
    / c9 _% L  j3 {3 i

  25. " [, L7 a5 l* O7 w  q& T  R2 J
  26.     if ( HSEStatus == ( uint32_t )0x01 )
    1 p" G. |* N( I5 j& T7 i& p
  27.     {
    ! i: ?- Q! i3 |& O% g  Q
  28.         /* Enable Prefetch Buffer */" t- m, @- E: L+ K5 E" M6 e0 m/ M
  29.         FLASH->ACR |= FLASH_ACR_PRFTBE;
    : v8 Q: }) L& H6 g

  30. ' K0 S. L  x* v* k9 H
  31.         /* Flash 2 wait state */+ i& L' f. }; d" \; R
  32.         FLASH->ACR &= ( uint32_t )( ( uint32_t )~FLASH_ACR_LATENCY );( `% q- P5 i) O1 a8 j3 r
  33.         FLASH->ACR |= ( uint32_t )FLASH_ACR_LATENCY_2;( n9 M) E4 y, x1 a% d) w

  34. ) \! X- ^+ [* [! l$ a8 z

  35. 7 }: \1 o2 j2 E( B% R; \  Y
  36.         /* HCLK = SYSCLK */4 G  ?; t# U3 h' e1 w
  37.         RCC->CFGR |= ( uint32_t )RCC_CFGR_HPRE_DIV1;
    7 |, E7 N* y! B0 P# _- W# E

  38. 1 U2 T6 U9 L* u8 p* x% s# D& {
  39.         /* PCLK2 = HCLK */, q& o3 V+ e8 @
  40.         RCC->CFGR |= ( uint32_t )RCC_CFGR_PPRE2_DIV1;
    " O, Y# T7 p: ?7 ~% `: d
  41. * P' i+ r$ P% U/ x9 p; e! v
  42.         /* PCLK1 = HCLK */. V* t0 C3 o* |/ K
  43.         RCC->CFGR |= ( uint32_t )RCC_CFGR_PPRE1_DIV2;
    ( G& Q; k2 H1 g/ ^( k. C' u* c
  44. 4 s8 Q5 M* e4 z3 D( I6 E
  45. #ifdef STM32F10X_CL' v: g! n4 _; H$ w
  46.         /* Configure PLLs ------------------------------------------------------*/" n% O  j% d, @& l( U, K& c
  47.         /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    4 L% a7 Z% {$ d! J
  48.         /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */4 O- k4 F: s. v6 j5 b* Z

  49. 5 x# \3 k6 }% Q5 X' b$ v6 I* O
  50.         RCC->CFGR2 &= ( uint32_t )~( RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |& T- h9 P% E4 b! ]2 G# `5 c
  51.                                      RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC );2 t9 [# W6 N0 Q- k/ G7 `
  52.         RCC->CFGR2 |= ( uint32_t )( RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
      K# q3 a9 N9 [& m' j( H
  53.                                     RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5 );
    * L, W: e! N2 W6 N. j% d; h3 }  N

  54. ( S  h# Z  b  k- A
  55.         /* Enable PLL2 */
    , W# x- d$ k, S$ q" h' R# l! q" G7 @
  56.         RCC->CR |= RCC_CR_PLL2ON;( P: p" a* u& T2 w) f
  57.         /* Wait till PLL2 is ready */3 h% Z% f$ r" k
  58.         while( ( RCC->CR & RCC_CR_PLL2RDY ) == 0 )0 J8 }) B/ T% d7 h' S0 y
  59.         {( o; ]- U+ T9 j3 ~
  60.         }4 f0 ~$ v& V5 [) R$ K- l5 n# V3 h  W
  61. . \7 r3 U; Z! ?9 K( \5 D
  62. ( f. W2 X' ^1 p. H' l
  63.         /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */
    & ~4 ?# [" f$ k: Q  w
  64.         RCC->CFGR &= ( uint32_t )~( RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL );$ p* z! E9 Y& E; w# B
  65.         RCC->CFGR |= ( uint32_t )( RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |5 C2 k; R9 e6 j3 o0 m2 ~/ K
  66.                                    RCC_CFGR_PLLMULL9 );) W4 s( h0 _/ L( K5 g8 s
  67. #else
    $ k* k. L3 j3 k$ z7 T3 d
  68.         /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    ' Q0 P  A6 ]' |0 Z. E4 y5 ^  S
  69.         RCC->CFGR &= ( uint32_t )( ( uint32_t )~( RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |7 k5 ?7 v* \. ~+ X% o
  70.                                    RCC_CFGR_PLLMULL ) );
    , G/ p9 f* U* |  U
  71.         RCC->CFGR |= ( uint32_t )( RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9 );9 F0 [: T+ V8 d6 b9 x
  72. #endif /* STM32F10X_CL */
    . p- L# ]! M8 B' H

  73. $ Y) U! y$ `4 {# e
  74.         /* Enable PLL */( [; W" b; z" n6 n. K
  75.         RCC->CR |= RCC_CR_PLLON;+ H! M* t0 U) M8 Q7 N5 L

  76. - @2 \4 g7 `/ \
  77.         /* Wait till PLL is ready */
    / p* U% f8 r5 |0 V4 Z6 v5 i8 M
  78.         while( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
    ; p" n0 I0 {5 g) d4 w3 n- e
  79.         {) c9 r& ?; @& Q6 \
  80.         }$ E7 t% A# z0 m7 I# R4 A
  81. " B5 `! n* m! b  E8 e0 R4 |- N) r
  82.         /* Select PLL as system clock source */
    1 r! z' r8 W6 N
  83.         RCC->CFGR &= ( uint32_t )( ( uint32_t )~( RCC_CFGR_SW ) );+ \; ?1 I( J# H/ \4 c+ L* ?
  84.         RCC->CFGR |= ( uint32_t )RCC_CFGR_SW_PLL;5 o5 n5 R1 Z- t$ [& y

  85. * m: K+ y0 A" U
  86.         /* Wait till PLL is used as system clock source */0 r1 K* \7 h8 k8 Q9 s% O8 K
  87.         while ( ( RCC->CFGR & ( uint32_t )RCC_CFGR_SWS ) != ( uint32_t )0x08 )- Z8 Y* Z/ R: P# b3 l. ?4 u
  88.         {. q- N2 J# K, u6 x9 W$ ]
  89.         }# T9 k# g- R8 l8 M$ [; c. S
  90.     }: Y" _% a% ]- G
  91.     else
    1 d& h. S. z4 d9 }% M% k
  92.     {, v# k3 ?: _% e7 i7 F; q2 H8 L
  93.         /* If HSE fails to start-up, the application will have wrong clock
    + D: s1 U* e7 E/ H; o
  94.              configuration. User can add here some code to deal with this error */2 q4 J6 L# l( y2 c0 i
  95.     }
    , y. J) F4 Z: P/ X
  96. }
      b; l$ o- v3 i# X6 d( |  @- U8 |
  97. #endif
复制代码

. R: \" j: r4 }' a1 Q4 b  v2 d0 G在系统时钟设置函数中,设置锁相环,及各个时钟的频率。
+ l, M& }4 h; s7 S7 |/ \4 k. ~' M& U" \2 R3 H
关于时钟的具体设置,可以参考下面这张图。
) G7 g" K. ^1 w
; Y* O' i! t( Y( q. r. | W9ZU$~E9LX({OMI8O)X0]1Q.png
; \; [& u) Q6 n) m7 s# I
; ?7 y+ s$ \+ P) \/ b: @ 3A}_~OIORAZLV9YV4I[SU(W.png
( {% f, z  M  f2 L# c" S1 n6 {& |$ I4 {5 B
通过上面的分析,可以知道,程序在进入main之前执行流程为
2 [8 h. h4 U) G: D. O' T
2 o" X8 S: o. u 6XRPB5A8`0YI~)S7$RKYD4B.png   ~+ @/ c7 h3 \+ X- V/ @" ^

; \9 j; Q7 V* S/ f, V5 }% b这里大概分析了单片机在进入main函数之前,大概都做了哪些工作,对于具体的启动文件代码没做分析。对于启动文件startup_stm32f10x_hd.s的详细分析,在另一篇文章中进行说明。! w; Z( H  t% M( w) j% H8 G
9 k; M$ v# e1 x" h
9 h' ~4 [* ]+ x" a* ^+ A

6 G5 p! h1 Z. s  N. f: m& S
赞 收藏 评论0 发布时间:2022-3-21 13:41

举报

0个回答

所属标签

相似技术帖

官网相关资源

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