现象复现
- {. Z9 H9 t0 J+ r2 [; Q项目中一个是IAP程序,另一个是APP程序,两个程序都是使用STM32CubeIDE生成,当程序跳转到APP中并且执行到函数SystemClock_Config中的时候,在初始化锁相环调用HAL_RCC_OscConfig函数的时候返回HAL_ERROR或者直接卡死在里面。
$ }" p1 x/ ~7 } f3 v( J! j+ z- x
为什么在IAP中可以初始化通过,但是在APP中却通不过,查阅STM32F4xx参考手册发现这么一段话:
; O3 K$ y, O+ q8 c1 @5 v) F; H+ v4 q. R# I1 I& Q
! V8 S x5 u1 q% K: e
- f2 ]: u$ N! r5 ]! H6 t那么出现这个问题的原因也就清楚了,因为在IAP中已经初始化了PLL,在APP中再次初始化就不成功。
* |' h8 v- n/ `2 r7 O
E/ A! }/ f- }/ j/ Y* h8 E解决办法( ]5 l4 [9 i/ D! Y
我查找ST官方HAL固件库中对重复配置RCC时钟的时候,发现他是这么做的:3 \/ u; D3 d6 k: Q
1.先将时钟源选择为内部时钟
) }" E7 f# N t- B: Y& u7 C2.初始化锁相环7 B- n4 [( W8 P& l7 [9 q/ h; `
3.将时钟源在切换回外部时钟源
) g, Z% s5 I5 Z( N4.禁用内部高速时钟(可选步骤,如果内部高速时钟不用的话,建议禁掉)
$ ~$ }! u; P) p: X( ~9 |* Y* ]9 ?* W. Y" Y; e; ? K7 x" G/ G
官方代码如下:$ _7 ^4 j) i+ k: @* V+ N) r4 T% p
- h6 i) {) E7 C {3 d# {- x. A& H
( O/ S4 a2 {- V9 Q3 W$ t( q: u3 K e6 J1 @ y4 e/ w7 `
以下是我的示例代码:
+ P j0 ~2 r1 b) @' I" b2 ^4 w) L. |9 u1 f a( T
- void SystemClock_Config(void) h4 _$ ]9 } G9 n
- {
0 o2 N2 _! g( s Q - RCC_OscInitTypeDef RCC_OscInitStruct = {0};; } S. a' p. B+ ` S
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};: U$ u, l0 `: W# E; j/ F6 n
- 0 Q7 f# `$ `2 r% E) N B4 b9 l
- /** Configure the main internal regulator output voltage
. E$ x2 f! J+ h% \3 F: j - */
9 [( `/ L+ G: G W) Z/ b9 o1 { - __HAL_RCC_PWR_CLK_ENABLE();
' L' e1 l/ q9 n% | - __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
; _1 ~8 K7 ]: @" z
) |7 M: M; R$ g) m5 i& h; I8 a- // 先将时钟源选择为内部时钟" F1 E# a# C% a1 c1 q2 ~* v
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
, D* h, w7 x8 G; ?4 C! o - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;) o/ f9 t0 P. l$ ~, l, Q
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
9 s1 L# ^9 h f, E# \, x - {
% u2 A9 }; t! U! b) m8 W - Error_Handler();
5 _% C) C* M9 S* Y. [1 B* f+ a - }
w+ E* M0 w: L, F+ a7 X9 u( | - % v5 h* y9 J3 L) j
- // 初始化锁相环+ g/ a( a9 a- F+ g" R5 x4 ~
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;* s7 F$ H! i+ ^
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;& p: V; p: [* ~5 m9 U$ a
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
# `0 k0 S8 }5 o0 G - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
& A/ g0 C0 y; g% Z) J - RCC_OscInitStruct.PLL.PLLM = 4;
- [, _, Y# D0 Q# p0 ^) M/ a* A - RCC_OscInitStruct.PLL.PLLN = 168;- ~6 s: B+ `8 a2 R8 H
- RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
' ]" N; D# a2 P# j1 a! y - RCC_OscInitStruct.PLL.PLLQ = 4;
/ `! H" V, F$ V; T* d+ [: _ - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)0 s- k: f& N( ^6 K' O) x
- {
8 \; B' o; ]4 w9 D9 r - Error_Handler();
* O% a4 m. ?3 g5 r. z% ` - }7 g) d* I& L3 k$ D ~4 F8 [
8 d% n, l* D8 }& F8 f' ]- // 锁相环已经初始化完毕了,将时钟源在切换回外部时钟源
6 i, ^( d6 f0 j9 ~8 Y$ ~0 ~ - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK0 @- z7 Z4 }( k0 t* E
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
4 F, m. | L% `. N+ t - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;: T# T" r' q4 g! e/ P* o, k0 W
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
7 G) X- T( I1 L - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
3 f5 a& Y2 i! g - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
7 d, k! i/ r8 J9 E) D- @ - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)8 Y! p5 Y) ?/ k7 g4 f% x
- {
, N* M7 l+ [, D \5 A% w" v - Error_Handler();
; c: h! [' g' X: u! Z5 l - }5 x+ Y$ H7 y* J _ B' J! `7 L
^: Z2 d; u3 w7 }- // 禁用内部高速时钟
3 b& r+ l% V z4 r" J* b - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;0 s8 Q4 y& E8 F, E$ u
- RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
4 \0 ?! b( ], k/ B \ - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;9 }& j! W$ f8 p( V' T
- if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
7 t- u/ d7 O& V6 v# [ - {
: ]. c; u7 D% s, q - Error_Handler();
+ |# N6 p% F# w; } - }
1 g% t/ {% Y; [* N' A - }
复制代码
( u# }7 i# y! P- z通过以上操作后,问题成功解决!
* I8 o( g# O$ I8 [: _+ y
! j8 E" I1 q6 C" {3 ^( a解决F4系列这个问题之后,我又去看F1系列的参考手册,发现:: ?% a% ^" R* k& W+ K5 y
0 l# @3 r# E7 @& J& R. n+ N
" j7 }( l, [; @* O9 p% }) x! Z, w# q9 q! I' ^% a" M
同样的也是需要在使能PLL之前完成时钟配置,不过在实际中发现,F1系列的IAP跳转到APP中并没有卡死在HAL_RCC_OscConfig函数中。
. {9 q0 m% W0 C' R. J0 c0 J
3 z, k) L' m9 d* K还有一个更快捷方便的办法,就是在IAP中不使用PLL,直接使用HSE或HSI的8M晶振作为系统时钟,如下图时钟的配置:
: B+ h T R8 l" ^7 a9 [- }% A6 o7 y' G
! z; B. f( t& | u. ]1 B
$ V# Y* M" i4 R( a
& x! ^; y' f! X+ j5 l7 ]
m2 L; ?) ?9 R3 r6 J' H, @ |