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

HAL串口库的分析于修改

[复制链接]
tanic 发布时间:2019-1-17 17:00
本帖最后由 tanic 于 2019-1-17 17:02 编辑
! D9 S" b" l; R# h9 _; p! v- h* _% i3 q$ Z
之前做一个项目,串口收发频繁就老卡死,后来用了保守法度过去,近来有空详细分析,发现了问题,并解决,这里分享一下。
6 V1 P5 x; R4 H+ ]  G$ k) Y0 \& N% s! m
这里不对基本操作分析,仅仅讨论一种方式,能让我们稳定的用串口,本文会对HAL库进行些微的修改。. U% b+ X+ ^+ H  V7 z$ o! q6 w
HAL库的串口大致可以分解为2个部分,一个是寄存器控制部分,一个是数据传输部分。我接下来的只修改寄存器控制部分一点点内容,数据传输部分不变,任然采用其回调函数形式,下面具体说明。
# y4 }( n0 a4 Q( r( C一般来说最常用的是发送数据HAL_UART_Transmit,中断接收数据HAL_UART_Transmit_IT。串口其余,如DMA什么的不做分析。
6 l& @! B, ~( q* J$ h' `0 H, B0 z研究一下会发现,HAL库中强制对串口进行了半双工限制,其实STM32的串口是全双工的,很多时候卡死,是因为我们做了全双工操作导致的卡死(不是HAL_UART_STATE_READY状态)。
( J* J. U! e& hHAL_UART_Transmit修改后如下
: Y3 M: P, T5 J. s
  1. HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
    4 W9 O) g- ^4 p
  2. {
    2 H+ Z; _" s  ?- h, X5 J
  3.   uint16_t* tmp;: B' ^- d7 I' V9 x6 z
  4.   uint32_t tickstart = 0U;
    1 U" a" ^2 ~; v. B& J7 Y/ _
  5. 8 y1 R& Z" M& s* K" W  P* b0 F; L
  6.   /* Check that a Tx process is not already ongoing */  y' B+ w1 m6 E( m' c8 n3 O
  7. //  if(huart->gState == HAL_UART_STATE_READY)
    $ M- W$ o: E& I" ]
  8.   {
      N) \6 b* k% N4 i0 c# ?
  9.     if((pData == NULL ) || (Size == 0U))
      M( ]' E( N2 A& {& i* r1 E7 e
  10.     {
    $ H4 q+ c- L! Q  K5 d
  11.       return  HAL_ERROR;
    ' W; ^3 \, [* S( P, }: F
  12.     }
    + L, K3 N' H& [4 f; v7 I

  13. 5 v+ }0 |) u" s. u% h
  14.     /* Process Locked */
    ; Z6 E; K: \- q9 n
  15.    // __HAL_LOCK(huart);. v- I8 {0 u0 s0 F! r8 m, a1 y

  16. ) V9 N6 ~4 N' Y# ^' h
  17.     huart->ErrorCode = HAL_UART_ERROR_NONE;3 l) q0 Z& ?) m; r( H! i
  18.     huart->gState = HAL_UART_STATE_BUSY_TX;+ a  t5 J, E0 b9 w& x  m1 B

  19. 3 C* J( |3 g2 B" U% e+ ]: e
  20.     /* Init tickstart for timeout managment*/: O' X' @' Z1 {/ z+ ~5 o" y! \
  21.     tickstart = HAL_GetTick();
    / H8 F+ H$ B% m7 ]

  22. 8 K  U, B- ], p, Y; p# S5 B
  23.     huart->TxXferSize = Size;; B/ g* i2 o+ j0 m, v' ~1 L1 [* x. J5 }
  24.     huart->TxXferCount = Size;
    : E" i- w6 M2 e( l
  25.     while(huart->TxXferCount > 0U)$ Z/ d; t; B1 N4 M5 M# G4 F7 N
  26.     {4 L% `/ _& V) g  i1 d0 {
  27.       huart->TxXferCount--;
    $ L+ N; W. T8 k9 z- n
  28.       if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)6 i# ^. j& J# r  G0 \4 Z
  29.       {
    . J0 `/ [& v' w9 L
  30.         return HAL_TIMEOUT;
    6 H1 e9 A+ t7 h5 e- N* Y# j% Q6 h$ k
  31.       }7 j* d  d/ A7 h+ f: X; t
  32.       if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    % v' p  @6 m& H( H. ?
  33.       {
    1 P2 Y4 W( ]1 ]- i% T
  34.         tmp = (uint16_t*) pData;
    9 h4 V7 e* \/ N( _# `
  35.         huart->Instance->TDR = (*tmp & (uint16_t)0x01FFU);
      R9 T2 S: d4 k( r) c
  36.         pData += 2;; `5 K: A3 R7 u, ?" T3 O# N0 J8 q
  37.       }4 K4 _: ]3 w$ X0 p
  38.       else8 ^9 s' }( G% V; _" B3 A
  39.       {
    . j5 z/ E. w4 M3 v
  40.         huart->Instance->TDR = (*pData++ & (uint8_t)0xFFU);% F8 o. j" y0 m! [) o
  41.       }6 z/ B  A* X5 ^( g8 n8 P/ Y. ^
  42.     }' C, {% x5 B7 ^3 N* u7 z% Z
  43.     if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)1 f/ T* X7 L  ~
  44.     {
    9 `" t) y! Z( \+ Q
  45.       return HAL_TIMEOUT;7 Q. l( m2 x9 v' p1 r: \0 q+ y
  46.     }9 ^2 U+ F" W7 l8 A

  47. % ?5 Z2 F3 i" m" I$ B
  48.     /* At end of Tx process, restore huart->gState to Ready */( e8 N7 V. ^4 F& c# G. `' J
  49.     huart->gState = HAL_UART_STATE_READY;" V! X4 k! e% F% u& _1 J+ f3 P* B

  50. * c0 \/ \( o7 T" S: M
  51.     /* Process Unlocked */, F: }2 N# w% ^. v1 Z6 y( x* v
  52.    // __HAL_UNLOCK(huart);
    8 J; M$ a5 ~  O. B$ X5 r& f: R

  53. ' ]5 |6 W% |1 ?' i. X/ {1 z) r
  54.     return HAL_OK;
    1 K4 D: \# c0 a& p  e
  55.   }! F0 u+ ]' a& w
  56. //  else
    , z& P5 y8 {8 _7 U3 [1 Y
  57. //  {
      r+ j/ \5 p2 w% k# S* w2 n4 I
  58. //    return HAL_BUSY;
    3 v0 T2 x0 i7 u( {& ?$ y) A
  59. //  }4 O. {5 L2 t! T! w9 I) M% b
  60. }
复制代码

% U" o  A" {: ?8 e* _9 cHAL_UART_Transmit_IT修改如下,除了祛除限制,还屏蔽了中断使能,这个后面再说原因
+ O$ g9 @1 U5 P0 p& C
  1. HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
    ! F8 F4 x+ m" e# c$ o
  2. {: k0 g' M1 @; t4 [5 x
  3.   /* Check that a Rx process is not already ongoing */
    # u' `9 M7 k1 n& \
  4. // if(huart->RxState == HAL_UART_STATE_READY); _0 p' U2 Q. q9 j/ t( ?9 _
  5.   {
    ) }" f1 a# c, S. N1 \0 u
  6.     if((pData == NULL ) || (Size == 0U))
    5 V( @* b+ h. |) v
  7.     {+ l5 ]2 s9 u, s) i. x, r
  8.       return HAL_ERROR;
    # \6 r) I5 G6 n! [, Y$ L0 u
  9.     }$ b8 e3 z; B% j0 w3 u
  10. : u3 p- i! c0 v" S5 u$ A
  11.     /* Process Locked */
    # A+ r+ T4 Z3 o8 t( p+ K
  12.    // __HAL_LOCK(huart);- h/ k% P# w5 Q4 w

  13. ) T) O9 _# y& q1 K( y# {* d
  14.     huart->pRxBuffPtr = pData;
    0 d6 z9 ?- {. T/ B7 q
  15.     huart->RxXferSize = Size;
    : d& T4 X8 C' I1 ~0 e  _
  16.     huart->RxXferCount = Size;
    7 M( a  f  S9 r  r
  17. , a$ P# W. |6 A: H; q9 u2 |  V
  18.     /* Computation of UART mask to apply to RDR register */, A& h: H" n& O. O  l0 u* S
  19.     UART_MASK_COMPUTATION(huart);
    , n2 H' f! B* H* Z. R+ g% T

  20. 7 I, D# c# }: q( t" a( R
  21.     huart->ErrorCode = HAL_UART_ERROR_NONE;
    . h9 B/ S+ U; y. n$ u' @/ t. a
  22.     huart->RxState = HAL_UART_STATE_BUSY_RX;5 K1 F. m5 H0 c! I
  23. ' Q& E' _9 O: s- Y) h9 o
  24.     /* Process Unlocked */7 I0 D5 b8 r# F1 M3 J
  25.   //  __HAL_UNLOCK(huart);2 J% G5 e4 }8 d' ?, z& K

  26. % M  Z/ y6 g1 U9 ?7 D+ P& _4 ^
  27.     /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    6 g$ L' r* J7 b+ c( U
  28.    // SET_BIT(huart->Instance->CR3, USART_CR3_EIE);: p/ w. U9 P0 h; ^# i
  29. # @3 d; S& [+ V- n. k, Z# E
  30.     /* Enable the UART Parity Error and Data Register not empty Interrupts */$ D: S9 \( T$ h
  31.   //  SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);6 z9 j/ Q- Q+ v# i, m7 i& Y; _
  32. % G8 F7 l9 w, S" ~* K5 g
  33.     return HAL_OK;2 W" L, C  }8 m% x( T: V
  34.   }8 m$ K8 V# ^1 R5 d1 m" S
  35. //  else
    , r3 G6 q$ f- }- E. z$ {
  36. //  {+ ^: i, k) R: P$ P: R" g! v6 h
  37. //    return HAL_BUSY;" g5 q- M% Z7 {1 g. L
  38. //  }3 \- ^3 Z* D) C; C0 W& z
  39. }
复制代码

- n  B" G6 v& U% Y( e: i9 t3 j. v* W7 ?接收中断,屏蔽了清除中断的两行,中断开启后就不再停止了
( D2 {1 N2 ~  i
  1. static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)( ]$ k! V* x- @# ~8 h% f% K! O; q
  2. {
    ) c) u$ ?* V2 B5 _5 L: r8 ~% k& N
  3.   uint16_t* tmp;5 W3 c8 b3 R% q6 A5 R
  4.   uint16_t uhMask = huart->Mask;
    / _! }; o& B- |9 S

  5. , q) z' T: Q; `) C$ O/ u( L
  6.   /* Check that a Rx process is ongoing */
    - _7 ], t+ A& v) F# l/ `- s; N
  7.   if(huart->RxState == HAL_UART_STATE_BUSY_RX)
    9 a  a$ b4 L9 ^8 A  N
  8.   {
    7 j$ v5 y) I- i9 L4 f; P
  9. 4 M5 `, d; D& t0 X) F9 X# k
  10.     if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))/ p, s) C: c9 D0 T
  11.     {
    4 O! o0 \6 w) {  _! O+ `% b; Z
  12.       tmp = (uint16_t*) huart->pRxBuffPtr ;
    ( i/ H8 x2 ?% Z5 X6 m
  13.       *tmp = (uint16_t)(huart->Instance->RDR & uhMask);! @7 D5 h( k% h$ {
  14.       huart->pRxBuffPtr +=2;' I7 W. r1 C* L  w- j
  15.     }+ y, a0 R: ]; f
  16.     else
    7 L8 p  n3 ]8 L' v0 W4 B
  17.     {2 L  R" _& p0 Q- d& ?9 X
  18.       *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);
    . V! M. c2 D' u) d
  19.     }
    / N- a' L- k! G. d) P  A( a  l; w

  20. 1 k$ O/ W3 S6 F' |9 z
  21.     if(--huart->RxXferCount == 0)
    ( e( ^' O# ^0 o4 g2 q* Y* G
  22.     {
    $ i9 ?6 m9 `6 o- q8 L
  23.       /* Disable the UART Parity Error Interrupt and RXNE interrupt*/
    $ Y, z: K' u% M! d
  24.    //   CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
    8 v! d  Q( l& `; \" {- i

  25. 3 _% `$ L8 U0 @! e3 F+ n3 e
  26.       /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */& [3 H0 z: U& t3 v$ g$ E
  27.    //   CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    2 f( k1 V' ?3 d& J
  28. ) u" U: {) U+ j4 d: M
  29.       /* Rx process is completed, restore huart->RxState to Ready */; a/ q& e% ~! b8 z+ [: }$ `5 c
  30.       huart->RxState = HAL_UART_STATE_READY;
    1 \* W( C3 W7 c# i: g5 z+ i, s+ Z2 _
  31. : g. c; M0 t) v. I: K3 o
  32.       HAL_UART_RxCpltCallback(huart);
    , D* j) Q% S2 F9 D  h4 _( J
  33. 2 S0 {+ {' ?0 ]
  34.       return HAL_OK;
      s6 k2 T0 Y# n: O0 {
  35.     }( i: I% ]2 `9 ?" {6 R

  36. % F5 b9 E* S- n$ {2 H
  37.     return HAL_OK;
    $ [; t4 ^9 |8 `, J% W
  38.   }9 d8 W" O2 i9 j) n3 ]
  39.   else
    / t. P! @7 U; _& A+ j
  40.   {0 ~7 J9 a, m( ~/ f' U
  41.     /* Clear RXNE interrupt flag */
    ( ?  s. U6 J+ B! }5 b  `2 z3 d
  42.     __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
    : X2 b7 {  }9 A- \2 J+ [

  43. 4 A& Y- k+ U# D, b' E1 p
  44.     return HAL_BUSY;
    / J$ Z  R. V' T; ]
  45.   }1 V8 r% {. O$ m  N1 r: c
  46. }
复制代码

0 I! m( l& z2 a在usart.c添加如下代码,
/ c4 R0 x$ V! N6 H2 h7 ^StartUART_Rx:开启中断,同时开启HAL数据流。本来调用HAL_UART_Receive_IT会重新开启中断,不过前面我把它屏蔽了,这样,这里初始化开一次就行了,上面代码中关中断部分已经屏蔽了
: V8 C& E+ X0 b7 ^6 |8 C! f0 hHAL_UART_RxCpltCallback:接收中断回调函数
8 k: M5 H4 C" [! \HAL_UART_ErrorCallback:错误中断回调函数
9 a5 ?( s% \8 y, y! V/ m8 ?( O
: j) v0 I' y$ u5 ^( ?0 [8 w
  1. /* USER CODE BEGIN 1 */0 n1 |+ h. P3 U0 y' b0 J- k( q2 p! U
  2. uint8_t a=0;. {3 f. U' u4 S* ]8 T, `
  3. void (*UART3_Callback)(uint8_t)=NULL;
    , k) Q/ ]/ ?- Y; h8 v
  4. void StartUART_Rx(UART_HandleTypeDef *uartHandle): T2 d: K* k( y1 h
  5. {2 n2 [7 f0 |! d' J- M
  6.         if(uartHandle->Instance==USART3)
    ) e" A" ~  u8 f/ @; ^: t
  7.         {
    % v8 R( M* O4 q- i! r$ K
  8.                 if(HAL_OK!=HAL_UART_Receive_IT(uartHandle,&a,1))
    $ S5 Q$ m: w. y  Y
  9.                 {
    ; o1 _, v% c& _7 E5 J
  10.                         assert("HAL_UART_Receive_IT",__FILE__,__LINE__);  y5 q# H- u0 R0 N" |9 [) k
  11.                 }        ; K( e' i7 X; L; N, S
  12.                 SET_BIT(uartHandle->Instance->CR3, USART_CR3_EIE);        1 }0 d% e) h8 N) Q
  13.                 SET_BIT(uartHandle->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);                . s7 }2 T  J' c
  14.         }' ^: |" B! ?4 o- n3 B# `- o6 ?
  15. }
    2 C) ~( t3 q8 E9 Y9 J5 l

  16. " x! o9 H0 t/ f  j2 K( ?% [
  17. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle)
    6 R$ t5 b8 L* x6 Z& C
  18. {
    & @' E8 ~- ^" _
  19.         if(uartHandle->Instance==USART3)7 {' k& n6 i/ `
  20.         {
    7 c$ a3 v( b4 j7 l% M
  21.                 if(UART3_Callback!=NULL)
    9 ~/ ?5 H: s' q2 q
  22.                 {
    1 g5 _  P+ ^+ s# d  {& X
  23.                         UART3_Callback(a);
    ) R( j( C6 _9 \+ d( s& `
  24.                 }- K% \' P" I1 p/ H9 r
  25.                 if(HAL_OK!=HAL_UART_Receive_IT(uartHandle,&a,1))
    , I) l& o1 q0 J8 [4 _4 S: v
  26.                 {
    6 I% I) _. z; d4 \
  27.                         assert("HAL_UART_Receive_IT",__FILE__,__LINE__);# G2 d- R- a* }* s
  28.                 }                        
    4 E; ?! ~9 c% M* F4 W
  29.         }
    ( [' M( z9 t$ h( j/ y5 g
  30. }3 }5 y, B+ a, K- K  i, f1 t$ J
  31. void HAL_UART_ErrorCallback(UART_HandleTypeDef *uartHandle)7 H6 f. [- S4 o- K3 b- a. V0 P' I
  32. {& ?" r; `2 {: M2 H& \- ^
  33.         uartHandle->RxState = HAL_UART_STATE_READY;
    % U8 p) m( \, k5 r& q4 ~4 Y" p
  34.         if(uartHandle->Instance==USART3)% l  q/ v/ b5 k/ {, c0 V
  35.         {
    ! x1 d4 O" y1 u& I* y7 R4 A
  36.                 if(HAL_OK!=HAL_UART_Receive_IT(uartHandle,&a,1))
    - O% d' j5 I+ W; e% h3 n
  37.                 {
    * }, p* [& k6 A. a; J$ z
  38.                         assert("HAL_UART_Receive_IT",__FILE__,__LINE__);
    ! y; c/ {7 W$ I! y+ |
  39.                 }
    / P/ Q) L) e4 z. d
  40.         }$ ]3 |# j) F2 s) F. V9 T; y" H8 V
  41. }
    # t1 f, I6 D+ ^. K8 c# a' \; w

  42. 6 j% w1 d" b! m- P) z

  43. % W6 X1 t% Q8 R7 A

  44. # T3 N% R0 R3 {) Y4 z
  45. /* USER CODE END 1 */
复制代码

0 j" _3 a/ D+ b/ l
/ y: Q2 [( @/ P3 f( q! Q  z

基本这样改就能应付大部分应用了,


, t! e& J, R  X  l1 u+ \6 Y( W

当然有另外一种方式,就是开一个检测任务,定期检测串口状态,如果发现串口卡死,则重新初始化即可。

亦有人用了DMA+空闲中断的方法,不过感觉是不太稳定的。

估计HAL库其他驱动亦有类似的情况,自己把自己卡死。

改库有风险,跟风需谨慎!


" R! B: E! `2 ?, L. C. j( K+ g* Z0 P- \1 ^. q+ j: W
5 Y  K. ^4 U. d
) i" k" q% D- S. g

评分

参与人数 2 ST金币 +6 收起 理由
小鄭QQ + 5
linuxdaxia + 1 很给力!

查看全部评分

收藏 2 评论3 发布时间:2019-1-17 17:00

举报

3个回答
chenbourne 回答时间:2019-1-18 10:06:21
感谢分享        
STMCU-管管 回答时间:2019-1-22 13:29:42
感谢分享
孤僻菠 回答时间:2019-7-29 18:34:52
完美解决,必须要赞

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版