现象复现
3 A' P1 }1 G' A! R( Q7 W. e项目中一个是IAP程序,另一个是APP程序,两个程序都是使用STM32CubeIDE生成,当程序跳转到APP中并且执行到函数SystemClock_Config中的时候,在初始化锁相环调用HAL_RCC_OscConfig函数的时候返回HAL_ERROR或者直接卡死在里面。
8 A: o' [( L9 {) G0 o
7 t& [& S( H$ ]; V5 b为什么在IAP中可以初始化通过,但是在APP中却通不过,查阅STM32F4xx参考手册发现这么一段话:
: k& H& q+ E' S: L" m
3 ? M% V7 I8 G0 x1 F- X
& l$ a# o3 \# f; k
8 ^( K* U) O* r+ G# g那么出现这个问题的原因也就清楚了,因为在IAP中已经初始化了PLL,在APP中再次初始化就不成功。% _! A. t# k: f8 k
1 s$ S9 t' B3 [0 `( V2 x+ j
解决办法9 O& p; J$ [! p& x7 O8 b1 O C- z
我查找ST官方HAL固件库中对重复配置RCC时钟的时候,发现他是这么做的:
5 j7 N d L% |! l z5 y1.先将时钟源选择为内部时钟
8 s* h. ~ w) D6 d6 v8 i' m ?1 ~2.初始化锁相环) Y! L1 ~0 x7 p1 Y) m' w5 q" j
3.将时钟源在切换回外部时钟源
* C! H* I% Q- {7 C j4.禁用内部高速时钟(可选步骤,如果内部高速时钟不用的话,建议禁掉)
8 s0 ^' r. x$ W5 R% }1 X2 P4 a9 s$ z; J
官方代码如下:- {' Q/ |% v7 [% a# b/ L6 T- G3 `
$ {& c0 d0 {: J
- Z% w, C2 q6 v1 N
' A8 B; s! y ?1 o以下是我的示例代码:
, l% [: i; h8 Z; J3 ]( j M2 F$ I' b9 m" U$ _
- void SystemClock_Config(void)
3 y2 \9 f9 R0 l% `' B - {
$ _. A" u' l' r- Z0 k - RCC_OscInitTypeDef RCC_OscInitStruct = {0};
( K/ X% f9 R5 z4 l: y- J - RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};7 t: k2 x1 O2 W
- 3 f8 S2 x: K: P
- /** Configure the main internal regulator output voltage" o/ U9 t0 v" a" S# ^0 t
- */) ^0 z; i1 }/ k( m
- __HAL_RCC_PWR_CLK_ENABLE();
9 ^0 u& g$ R1 Z - __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); {* `3 ^- } j! E
3 {" l! L% }( A* i% Z; V* V# T. l- // 先将时钟源选择为内部时钟1 }4 U( c0 I% e4 r, D# r9 D
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;4 k: a. H' W( z. g, t1 Z5 p2 |
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
2 g8 K- T( A4 @/ @8 G# d8 T - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
6 r3 ]) s5 x: Z& U0 |9 o - {4 M/ s: S: E& d g+ a% m: v9 L
- Error_Handler();
6 d/ E( @) |& w K: R" } - }9 |( x/ s& q# {& i: [8 ~
+ \: d! C1 A, r! V; s/ b- // 初始化锁相环! P r+ j+ S* ]: \% a2 j% w
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
7 }7 f+ [2 Q6 h - RCC_OscInitStruct.HSEState = RCC_HSE_ON;
7 b6 I7 w9 o% a& m! E - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;, R; B1 S7 Z/ }2 K
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; ?2 t9 B7 l, j }
- RCC_OscInitStruct.PLL.PLLM = 4;
* j3 g4 t3 {" v3 P$ R# o0 h5 E - RCC_OscInitStruct.PLL.PLLN = 168;
8 J* q( {. Q: x2 Z# x. _8 W/ k - RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; v) ^7 q% n- C$ h1 m- U( y7 E
- RCC_OscInitStruct.PLL.PLLQ = 4;- G/ |; f/ E/ R* a5 K+ `% O7 V% y
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)8 Z; a+ @1 _. h- |) L
- {
" d) `8 |/ }5 T! J' r/ W) B - Error_Handler();
1 c$ N/ A6 o$ F8 ? - }
! s1 H h) C5 v$ _& ^$ Z
) T* D. L* x$ c/ r* W- X) N- // 锁相环已经初始化完毕了,将时钟源在切换回外部时钟源
7 z/ C$ v" N$ @# A - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK: w* _( m T0 g0 E. w% x
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;! f' d9 r% |* {' I7 Y( g' t
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+ ]3 Y+ {. D" u0 ~( { - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
4 R+ q% ?# k! l - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
7 f0 _1 R( p8 ?6 B2 z - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;$ D ~5 J% z* V+ e( d# d7 }7 C$ p2 G
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)/ [8 W' k+ @8 b
- {* O8 t1 x- Y O3 ~1 a/ }
- Error_Handler();
; c0 t6 |; U5 D8 c' H - }% C6 g, q$ i: R+ T# C9 Q1 [ W
1 d* p$ [! n7 @, t! K. u, c5 A- // 禁用内部高速时钟
f& m2 k4 i D# r7 Y) o - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;. T# s; r& Z8 y5 ?' d
- RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
]9 N' C$ i4 \; P - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;# N. W1 B+ _: l1 Q0 Y# d5 T
- if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
5 Q. `. ^/ G, C+ Q3 a- V' R - {' w% G9 u4 t( Y# u
- Error_Handler();
* x5 F9 X5 R" d - }
, u: X' C# B/ p% k: ` - }
复制代码 . Y3 _7 |9 i* J5 k: L) \
通过以上操作后,问题成功解决!
: |- B- G) |/ o( H9 A! y" W# n9 X7 \
解决F4系列这个问题之后,我又去看F1系列的参考手册,发现:' a3 b* I) s& U$ a; h
6 S6 E9 _' S. s+ }+ r$ T
$ n0 b7 M, ~4 y, Y# t/ A
/ B/ ?1 S7 {7 W) J同样的也是需要在使能PLL之前完成时钟配置,不过在实际中发现,F1系列的IAP跳转到APP中并没有卡死在HAL_RCC_OscConfig函数中。
' }6 b# G3 ]3 B2 p* Q
; I4 {/ v; I3 G' ^还有一个更快捷方便的办法,就是在IAP中不使用PLL,直接使用HSE或HSI的8M晶振作为系统时钟,如下图时钟的配置:3 D/ \; l' ]. ~1 u1 D( |6 L
o" J- u' D. J) F2 G/ v" [" h
$ n7 O- G/ t& I5 D, O0 ^; Q' q" C4 \" D
1 n2 U* m, e5 [, g: R, E
9 f. T: `4 P/ q' |6 i$ H |