问题:
* T! L3 {0 ^5 L: H" ]此问题由客户提出,客户在使用 STM32F411 开发产品的时候,采用的是 HIS 作为主时钟,同时使用了UART 与其他 MCU 进行异步通信.
8 p0 o2 m8 [6 B9 R+ s) r, g* h客户发现部分产品 UART 不能正常通信.9 ]+ w; g2 j# k8 ` r1 \
% T% T9 w9 K7 O; N1 ^0 K" \1 M2 Z0 _2 {" M& F9 V, C* P! M- Q
调研:6 Z# k9 m* J6 z
1. 通过使用示波器来测量 UART 的 TX 的波特率,发现误差较大,查看原理图和代码发现他们使用HIS 作为主时钟,且没有使用 PLL 来倍频.* v) d8 f' J* A6 ^. m8 S7 T$ X
2. 由于 UART 直接用 HIS 作为时钟源,所以考虑通过使用 LSE 校准 STM32F411 的 HIS 值来使得UART 波特率准确.: @$ ^+ R5 `0 D- ?
3. 我们 STM32 官方提供了基于 STM32F0 的 HIS 校准方法 AN4067(基于 STM32Cube).其基本原理如
8 V0 v' e0 t- q 下写的很清楚:& U6 [: j$ @5 N8 V
. n; s3 N5 w3 e
6 v7 F7 ]; T1 P9 N8 D$ Y
8 O& L9 }6 Y! h' ?$ C1 Y {. s5 g
# L5 Z, H# ?+ ?6 y4 d1 U* S
; @5 N, n4 a! j5 ^6 i4. 所以我们将其移植到 STM32F4 上:) Z; p% V, L, C3 ?1 w; x
a. 替换 STM32F0HAL 为 STM32F4HAL, [0 }' i G! }+ x/ a
b. 修改工程器件相关的配置.
! T6 X! V( p0 f* f; r c. 去掉与 STM32F4 HIS 校准无关的文件,只保留 his.c/h
3 A- Q9 u( @ E. r# I d. 修改 main.c 的主程序,初始化校准前频率测试校准后频率测试.! ?% t/ F. B( E7 Y) y' M
HSIFrequencyBeforeCalib 为校准前的频率值,可以在 IAR 的 Watch 窗口查看.+ Z. M% V% q9 W5 d
HSIFrequencyAfterCalib 为校准后的频率值,可以在 IAR 的 Watch 窗口查看.0 ?5 T/ e0 A6 w* @0 O; h' [
e. 定义使用 USE_REFERENCE_LSE 和__HSI2LSECALIBRATE_TEST__,使能使用LSE 校准 HIS 功能函数.$ |( F+ T: Y% t+ U
- /* Private typedef -----------------------------------------------------------*/ B1 F# ?6 Q5 G, v
- /* Private define ------------------------------------------------------------*/3 U, {7 ]5 I( H/ b$ o2 `
- #ifdef USE_REFERENCE_LSE K8 M& ^ u% _8 U/ s; K$ h
- #define HSI_TIMx_COUNTER_PRESCALER ((uint32_t)0), J' @& f) \; s- `; m" z9 l
- /* The signal in input capture is divided by 8 */! j$ s8 M, c( V2 Y( |2 A
- #define HSI_TIMx_IC_DIVIDER TIM_ICPSC_DIV8& O) t f4 Z. @+ ?8 N* N, X
- /* The LSE is divided by 8 => LSE/8 = 32768/8 = 4096 */0 l* y# \: y4 @$ e1 s5 w
- #define REFERENCE_FREQUENCY ((uint32_t) 4096) /* The reference frequency
$ U3 A6 P/ D3 |. P* c - value in Hz */3 y+ |2 n) J6 f
- /* Number of measurements in the loop */" z } t- c# C% @! ~+ v
- #define HSI_NUMBER_OF_LOOPS ((uint32_t)50)( g7 F; y1 X" |/ O% C' ^" J- e5 ]
- /* Connect LSE clock (through MCO) to TIMx Input Capture 1 */
) i/ w6 q5 D& o& w( Z - #ifdef __HSI2LSECALIBRATE_TEST__' J- c( x' T- v/ R
- #define HSI_Timer_ConnectInput() do { ; D! `! @ e) X" }% y! o" ]
- HAL_TIMEx_RemapConfig(&TimHandle, TIM_TIM5_LSE);+ a0 N* G. c4 F' b- a. V. x: d
- } while(0)
% S9 J- g( Z0 j! H* U! g' u0 ? - #else
% ~8 ]" l7 H, v. @/ D - #define HSI_Timer_ConnectInput() do {
& o6 ~% L5 u5 _
' L9 I. E% g/ G- k" ?4 i$ D
0 S% k4 ^9 U9 J1 N# l: e- HAL_RCC_MCOConfig(RCC_MCO, RCC_MCOSOURCE_LSE, RCC_MCO_DIV1); ; N" n9 H: |8 W/ m& v; ~, h6 n
- HAL_TIMEx_RemapConfig(&TimHandle, TIM_TIMx_MCO);
4 x/ A6 k' {( }2 i; |& y, y4 d - } while(0)
" W6 m! M- I- W. l - #endif
复制代码 2 w, g5 F- A9 S0 t
d.详细代码参考附件源码例程.5 d# j* _7 B/ u9 g3 C# m& H6 @( [! E
3 X. j) y4 d1 F1 r* i结论:
4 Y8 j: W. H# m/ m. T" I* w1. STM32 MCU 内部高速时钟是可以通过外部提供的精确时钟源进行校准的.- l+ G! l+ l2 V5 O8 w' @# \
2. 我们提供一篇应用笔记和参考代码给客户演示如何校准 HIS,基于 STM32Cube 的良好的可移植行,很方便的从 STM32F0 移植到其他 STM32 产品上面.
# }1 L3 v b3 }5 D4 f, z! T0 R. B3. 如果客户在使用异步通信且没有使用 PLL 作为时钟源,建议在系统启动的时候增加校准代码来增强系统的容错能力.
! \: e; v: V" F5 `3 N0 @
/ F4 p# `* N9 D4 R% m$ f
: s4 i8 i1 X# H. V7 Y- w& L |