现象复现! x* P$ d+ t3 R6 {/ Y
项目中一个是IAP程序,另一个是APP程序,两个程序都是使用STM32CubeIDE生成,当程序跳转到APP中并且执行到函数SystemClock_Config中的时候,在初始化锁相环调用HAL_RCC_OscConfig函数的时候返回HAL_ERROR或者直接卡死在里面。* j, O& m6 D. F6 C1 z/ M1 ~
9 N1 l Q/ l) n& O( l! R
为什么在IAP中可以初始化通过,但是在APP中却通不过,查阅STM32F4xx参考手册发现这么一段话:& D( n" ?8 t7 K
+ J: ?: e+ p, P0 I& P
3 L' D" T( P* t8 d- C
; c- z, W2 \6 b; u那么出现这个问题的原因也就清楚了,因为在IAP中已经初始化了PLL,在APP中再次初始化就不成功。% L/ f% L4 D1 ^5 n4 ?! a
: H2 g h4 b5 n2 K
解决办法( e! C: T* [6 k+ {0 R0 p; _& q1 h, @4 L
我查找ST官方HAL固件库中对重复配置RCC时钟的时候,发现他是这么做的:
1 M- j; U) e, S8 i9 }$ N1.先将时钟源选择为内部时钟4 y0 g; x; v* k2 W2 B4 n; L6 i
2.初始化锁相环
# e5 Q1 }" ?" w3.将时钟源在切换回外部时钟源) s& G/ r; D9 R
4.禁用内部高速时钟(可选步骤,如果内部高速时钟不用的话,建议禁掉)/ m V/ ], A, `- ]
! c7 t, z: E0 C; D& i8 n5 J( e
官方代码如下:
7 r+ ~0 b% _( q4 S. C$ |; b+ ]
% w5 a3 j' N5 A- ?; n
2 Y3 Y, o: G& g4 h
J4 u3 W+ h+ f# W; j D/ `
以下是我的示例代码:
4 p: M n& `+ O. J
) f2 H. p; d( n3 p* i- void SystemClock_Config(void)1 m {0 E5 ]/ W" ?
- {- G, y$ I! {7 h9 m. b5 _( l1 O) R
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};& l/ {# d' _" X$ D
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};4 b/ t" w$ W5 e+ G( W+ \1 }# {' [8 L
9 x% X( _3 g1 E5 I- }* ]( a- /** Configure the main internal regulator output voltage" J, s+ z7 T1 R% v+ z; `
- */
2 J2 F( @- b1 ~5 D - __HAL_RCC_PWR_CLK_ENABLE();
. K% ]. {9 D2 q - __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
' j4 B+ U0 F; {. b+ }
2 E& j3 q) w* N/ |) c- // 先将时钟源选择为内部时钟5 {+ |9 N2 ?) q7 {1 F/ Y
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;: v7 v3 h( W* W" K s7 T
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
. I2 _5 p7 l+ }! b - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
% w8 s2 y: H. k% v1 m - {5 H" Y6 N1 F2 z' u& [, K
- Error_Handler();
& i. [1 T; R0 y- i% T* Y - }- ?2 Z- N9 N4 `. i+ ]1 h6 O
- + b+ [3 S+ t6 i* q0 v5 R O/ i6 b
- // 初始化锁相环4 A0 G9 g- U0 ] Q1 ~0 x
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
0 h+ o! k% m4 p8 k - RCC_OscInitStruct.HSEState = RCC_HSE_ON;
( ^1 ~) }9 j7 x, u9 ] - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ f: y$ @5 s+ ]! ^/ A% ~4 u - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;0 M0 s; { l4 q7 h) c
- RCC_OscInitStruct.PLL.PLLM = 4;; ~. _4 u. o' \' {9 ~8 n
- RCC_OscInitStruct.PLL.PLLN = 168;9 i4 w1 a+ V) d4 r4 Q' z W
- RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;" s3 W8 {2 Q0 J0 ]! ?
- RCC_OscInitStruct.PLL.PLLQ = 4;: j; c7 A w- k2 u3 j9 p. O
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)# b* b: O/ q' O1 q# N
- {! g. n# f/ G6 j5 a. h
- Error_Handler();
1 u( ?% a$ P8 y - }0 {! U! p! H! k& Q* \8 `' z
4 t v& W; j6 `& ?7 h' H- // 锁相环已经初始化完毕了,将时钟源在切换回外部时钟源
3 y2 c9 G7 o: i/ b U+ \7 S- ^ - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK/ s5 ]$ _- L- @+ V: T
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
) w7 A- V* U4 G. a& q. Z - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;; O7 [* X1 ^4 [1 [, W* ]& n! _+ l
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
% X! D- y3 B* j, m+ L( E - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;+ F2 G6 `# G+ p* X9 n5 h3 ~
- RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;1 v# Z# k1 r$ ~6 u, B+ d
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
3 t. E* R5 u# B) ? - {
X# d0 M2 t9 m: {% e! ` - Error_Handler();
1 M" M2 @) `4 T1 ^* p - }
# e/ Q$ c( r4 f s
3 n* F, o* A0 T- // 禁用内部高速时钟5 U2 Y y$ i' q9 K: `
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
{% s" m7 O( E, n - RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
f$ P3 {% _# t: K' e( Y9 Z" N - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;' ^6 A, V; O: q( C" P, i* p
- if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)4 v. k: O Q( O4 Z `9 s
- {
. b$ V( \# U; o% O - Error_Handler();: H# o# Q }0 J* v$ E
- } D7 p( n- c( o9 j0 {
- }
复制代码 2 A% M0 V5 @+ O
通过以上操作后,问题成功解决!4 _ ]9 r5 u+ Y! _& J' K$ z
! \. q. s0 u( d( u3 Y解决F4系列这个问题之后,我又去看F1系列的参考手册,发现:
- E# a8 d" {$ Z) q
2 E" S) M2 X% D7 O8 {* w/ k1 W: N
+ D( c9 W2 u# P: S1 i6 u. @
8 A/ [2 K) t/ F+ T+ c+ b$ B( a
同样的也是需要在使能PLL之前完成时钟配置,不过在实际中发现,F1系列的IAP跳转到APP中并没有卡死在HAL_RCC_OscConfig函数中。4 b( Q. s; o6 _3 [& Q
7 |$ z; F" ]% u$ g0 J
还有一个更快捷方便的办法,就是在IAP中不使用PLL,直接使用HSE或HSI的8M晶振作为系统时钟,如下图时钟的配置:
* h- k( e! r$ q6 }) W' |
1 {' m" x: F" {' ^8 z% l B0 Q
0 v# k2 l* }6 [9 K- e& }
2 }- M2 |9 `0 f( ?% B
0 Z3 F+ X$ J0 E4 M% k
4 w) V; {/ m3 j' C
|