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

HAL串口库的分析于修改

[复制链接]
tanic 发布时间:2019-1-17 17:00
本帖最后由 tanic 于 2019-1-17 17:02 编辑
# g. V/ ?* _# X# U, c8 m+ G) W; z! d, l$ A/ ~* Y
之前做一个项目,串口收发频繁就老卡死,后来用了保守法度过去,近来有空详细分析,发现了问题,并解决,这里分享一下。( A" u: y* Z. t0 C- \
+ t# m/ w- F3 K7 Y: h+ J
这里不对基本操作分析,仅仅讨论一种方式,能让我们稳定的用串口,本文会对HAL库进行些微的修改。0 k& l' r4 `- w3 m+ S0 k3 k
HAL库的串口大致可以分解为2个部分,一个是寄存器控制部分,一个是数据传输部分。我接下来的只修改寄存器控制部分一点点内容,数据传输部分不变,任然采用其回调函数形式,下面具体说明。
" `; z$ }1 M' o( k7 g一般来说最常用的是发送数据HAL_UART_Transmit,中断接收数据HAL_UART_Transmit_IT。串口其余,如DMA什么的不做分析。) \- f: I4 a7 e) Z# d; Z2 }! H
研究一下会发现,HAL库中强制对串口进行了半双工限制,其实STM32的串口是全双工的,很多时候卡死,是因为我们做了全双工操作导致的卡死(不是HAL_UART_STATE_READY状态)。* T+ w/ m5 b  M6 S
HAL_UART_Transmit修改后如下$ E% |# m% K/ P3 G3 |
  1. HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
    ' z: s5 M% D- Q6 J' y
  2. {
    , I: n8 G* b' D, |
  3.   uint16_t* tmp;4 T# n# |, \, H
  4.   uint32_t tickstart = 0U;% {1 r8 ?/ b1 t2 A9 W: J

  5. + }1 R  U, A, R# l: d# X" c
  6.   /* Check that a Tx process is not already ongoing */
    1 X$ D/ ?$ C1 E) M
  7. //  if(huart->gState == HAL_UART_STATE_READY)
    + @9 s* Y3 k. q* h( ~  N6 V5 d
  8.   {1 x# z. D- S, r, j' V' r
  9.     if((pData == NULL ) || (Size == 0U))
    ( c. e5 o5 P, l# x: G% k! p
  10.     {
    5 M$ S* q* u) `8 p8 }  u
  11.       return  HAL_ERROR;4 O) Y! g8 T7 v% `: Z2 k
  12.     }2 q" g; i  \' Q9 v

  13. " \; [5 A- @- t# p& j/ t
  14.     /* Process Locked */
    # h5 O  w& j: ^/ q6 S! P/ W) H; x
  15.    // __HAL_LOCK(huart);' Y* `0 Y# Q- i0 Q0 p9 S9 K* c
  16. 8 E6 g1 b! |+ [2 R8 M6 j
  17.     huart->ErrorCode = HAL_UART_ERROR_NONE;
    0 C2 E* G& P( N) }2 ]
  18.     huart->gState = HAL_UART_STATE_BUSY_TX;) l) H) `/ p4 k" o6 M$ l5 _

  19. " Y2 j/ v/ ~& j5 v* k6 G6 U
  20.     /* Init tickstart for timeout managment*/7 y6 v" l$ o* l) Z0 J
  21.     tickstart = HAL_GetTick();
    ; a! d$ l. N1 b8 V

  22. * m8 c) |8 \% I( _% `& A7 g: \
  23.     huart->TxXferSize = Size;
    9 v: i) a5 G* h9 k* K) ]' x( ^; G
  24.     huart->TxXferCount = Size;
    % s7 Q) H  E+ j
  25.     while(huart->TxXferCount > 0U)
    + y+ u; s/ D8 ~: |. X2 s
  26.     {- w" R! F5 ^, v5 B7 h, S- x, h) ^4 T
  27.       huart->TxXferCount--;* K5 A* Y$ P# r0 z! O& }5 h
  28.       if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)7 z$ E; G( k7 r; u% f. B
  29.       {% M& m! P' `+ K; J# p5 s
  30.         return HAL_TIMEOUT;
    * X% q3 n, w( g6 a7 x7 Q
  31.       }
    ( W$ O$ d* k) p4 N! U
  32.       if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))( r9 u7 X% W& q% \& g
  33.       {
    . Y6 z; K# n! G
  34.         tmp = (uint16_t*) pData;4 S0 |9 @* I  o
  35.         huart->Instance->TDR = (*tmp & (uint16_t)0x01FFU);0 ]: F: q' o3 a  {  h. @
  36.         pData += 2;( a: f& G7 y- d, r& ~& c
  37.       }
    ( [, T" b) L! l) S" n: p- E
  38.       else5 I$ q- ~* [/ A' e, i: C* J! x% J7 C
  39.       {! {/ U, V% A& B( Q% x
  40.         huart->Instance->TDR = (*pData++ & (uint8_t)0xFFU);
    * o0 _: e' p/ T) d2 P% S& k
  41.       }2 I0 x2 l5 f; o' E, w7 u8 F
  42.     }4 s. i: o! @- G8 r
  43.     if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)1 D; x4 I, z9 _  ]8 o# a. u% D* A
  44.     {6 [& X$ @5 a; |! l% f, n7 n
  45.       return HAL_TIMEOUT;: b1 M; W/ W! C, P
  46.     }, u" D2 s5 }1 Y" k$ o6 ]
  47. 3 t3 q& e+ f, K* {8 \
  48.     /* At end of Tx process, restore huart->gState to Ready */
    9 U3 \8 Z3 z( t
  49.     huart->gState = HAL_UART_STATE_READY;
    ( O, n/ g4 B: E& `# Z3 w: b

  50. & o9 C- u& i! |) D  X
  51.     /* Process Unlocked */
    * \% o6 O" W9 E. x" o. |0 c+ d, `
  52.    // __HAL_UNLOCK(huart);; @. v1 ]: C. r

  53. + C4 R% y7 k6 P+ |* V
  54.     return HAL_OK;4 Y7 {1 i' Z  A( C
  55.   }
    - w7 `* g2 @- }& H' t% b- }) P
  56. //  else
    8 F0 T) {& X+ J+ n% Q3 U% }
  57. //  {
    7 C0 g; p. y, U
  58. //    return HAL_BUSY;5 e# s: b- W5 ^) D- Y) t4 g, S
  59. //  }
    8 e% }, K2 M! t4 G+ _- h7 q4 ~
  60. }
复制代码
. I2 a" t* b9 m0 @1 V3 u
HAL_UART_Transmit_IT修改如下,除了祛除限制,还屏蔽了中断使能,这个后面再说原因
- m  u& V! G- ?; o# t7 F5 x$ [0 a
  1. HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)$ C5 c' Y* ]& Q! P* F8 W
  2. {+ ]1 y9 A, ?* M7 o/ ?4 S
  3.   /* Check that a Rx process is not already ongoing */' H3 n0 k$ c+ v# o. ]7 g
  4. // if(huart->RxState == HAL_UART_STATE_READY)0 j* |4 G7 y, m2 `# \7 B+ T
  5.   {) y% k  l( N) e
  6.     if((pData == NULL ) || (Size == 0U))  A$ y5 w% R, h/ i+ o
  7.     {" D* X! ~5 ?/ D1 B; w
  8.       return HAL_ERROR;' f) a* E$ k1 Y, ^0 G0 t
  9.     }
    # p# n3 Q9 q) a- T& n4 k

  10. - \, `6 p) X9 s% `
  11.     /* Process Locked */
      i  I! V! H- B" ~! c& i
  12.    // __HAL_LOCK(huart);2 ~# ]* n4 @4 d2 |8 s3 B

  13. ( T8 @& f0 v$ ~" ]% @# [
  14.     huart->pRxBuffPtr = pData;! q7 `* O, ~% H- o: R# j
  15.     huart->RxXferSize = Size;
    8 S1 _% b) Y- C+ n# n
  16.     huart->RxXferCount = Size;7 |$ \$ H9 l1 T0 k' A8 Q
  17. $ l0 c4 F2 @, j
  18.     /* Computation of UART mask to apply to RDR register */% ^& ], n- o2 w$ ]4 e1 ]. F
  19.     UART_MASK_COMPUTATION(huart);) H2 V' ^+ a7 O1 z' ~# I
  20. 8 H5 ~8 `9 r! L$ G7 |: B& h
  21.     huart->ErrorCode = HAL_UART_ERROR_NONE;+ ~6 W4 U4 }1 ~1 c- v8 w( m3 V2 U
  22.     huart->RxState = HAL_UART_STATE_BUSY_RX;
    2 z2 b( d2 _8 m  v4 H

  23. , c( M7 `9 |8 d; L$ ]+ [
  24.     /* Process Unlocked */$ _6 ^, Q3 O) D% z$ `
  25.   //  __HAL_UNLOCK(huart);* ]& w' l- S) q0 K. F+ m7 V

  26. 4 X2 m/ F* y. R  G# g' c; Y( b
  27.     /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */& _6 g; G" A5 p# @
  28.    // SET_BIT(huart->Instance->CR3, USART_CR3_EIE);! S& t8 `: C& g- \' z+ ?4 F
  29. 3 \( T8 a0 P- _6 }) C
  30.     /* Enable the UART Parity Error and Data Register not empty Interrupts */
    : ~7 m) Z% J8 u2 I
  31.   //  SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
    . ?5 ~+ k' w; X1 H1 i
  32. 6 Y% f3 G5 x6 f" o7 _% W% W2 r5 r5 C
  33.     return HAL_OK;/ B" ~" h" F* `: {/ f6 L, j
  34.   }
    ' g- U' D: C, {4 y- ]/ g$ J) m
  35. //  else
    - w7 r5 N0 J0 w
  36. //  {
    ; y7 Z4 k' |  C, e7 y+ j* W! j: O
  37. //    return HAL_BUSY;
    & Z& g5 A& M" Z2 D: j- Z, o2 |, z
  38. //  }
    6 r. h. r/ c# P+ d5 `* {
  39. }
复制代码
( B% z/ @: Z( n0 T
接收中断,屏蔽了清除中断的两行,中断开启后就不再停止了: ~( J/ k0 B: h& i! j/ q( [
  1. static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)0 {6 E5 L0 ?, r" k/ f' v: o$ O
  2. {0 }' B, P  ~' Q$ ?0 Y4 L
  3.   uint16_t* tmp;" O: `' c" Q2 b, w1 y, d- a
  4.   uint16_t uhMask = huart->Mask;
    3 [% P* }* r3 A  O

  5. + {( w! m# D1 x  i0 W0 L! B! j$ l
  6.   /* Check that a Rx process is ongoing */
    + M: B, Z& M* c
  7.   if(huart->RxState == HAL_UART_STATE_BUSY_RX), e" }/ f7 `2 V; T$ C6 h' X
  8.   {
    * F/ e- }: h* Z6 G

  9. 4 K2 J1 c  [$ t( P' n; H2 I: K' [
  10.     if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))9 Y" N4 }4 E# \, @2 n$ a! b
  11.     {3 g4 g/ z9 j5 H
  12.       tmp = (uint16_t*) huart->pRxBuffPtr ;
    / v* w; J: T  k7 y  t) b6 V
  13.       *tmp = (uint16_t)(huart->Instance->RDR & uhMask);8 ?! [1 I5 v' r' t8 _
  14.       huart->pRxBuffPtr +=2;( k6 C$ g. t/ m% _! e0 B
  15.     }6 P6 [* m, k. L- R: `% S
  16.     else. d+ ]% O0 D8 Q/ Q$ u
  17.     {
    . [( s# V7 V  Q) I9 }' |: B
  18.       *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);" K. y2 r) g5 @3 X
  19.     }! L/ N8 D' z' m% |$ Q* O
  20. . J% g- I# B/ K) }4 v7 ]
  21.     if(--huart->RxXferCount == 0)
    8 e% C: m: C  \, L1 B/ h
  22.     {
    5 \6 J. J. _  @& K. O
  23.       /* Disable the UART Parity Error Interrupt and RXNE interrupt*/  V6 H1 H) `0 Y
  24.    //   CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
      m- t7 p  a, h0 i/ b3 ?2 b

  25. 6 @6 D9 M; Z. Z" j7 v9 r
  26.       /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */' h/ M5 e% V* ~$ Q' b
  27.    //   CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    5 O- U+ @" g& q8 |) {# k
  28. 3 w7 B( g1 ?  Z  b% A
  29.       /* Rx process is completed, restore huart->RxState to Ready */
    1 `3 W4 J  X  H% T; r" S
  30.       huart->RxState = HAL_UART_STATE_READY;
    3 t: q6 q( r7 X2 X: C
  31. * q- y% s/ w% c0 b5 E2 J/ S
  32.       HAL_UART_RxCpltCallback(huart);
    ! h4 A5 W1 W/ c6 u- N9 v; n
  33. % n( I' t* M. H
  34.       return HAL_OK;
    - |2 E. z+ d3 E2 k! \
  35.     }; \) x% i9 h3 X* I  ], R
  36. + J: W  D+ o; K. m2 t& J0 }- [
  37.     return HAL_OK;, ?7 @' p. x  ^4 v: K8 ~: y9 \6 r
  38.   }0 t" t3 d3 {' u9 |% [5 C. O2 a( S3 h
  39.   else
    - Q6 p$ ^2 `5 k, I4 j* V
  40.   {
    ! C& s& P* l7 b4 o
  41.     /* Clear RXNE interrupt flag */, n* u, R0 d  W  u
  42.     __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);3 G5 ]$ Y0 e* n" _; P

  43. ; Q' q+ t$ \6 g
  44.     return HAL_BUSY;
    6 u! B- Q# Y4 f+ o0 v
  45.   }0 i+ k+ d# s3 i  Z1 m, w4 m' p
  46. }
复制代码
( }/ d$ E- B$ Z
在usart.c添加如下代码,
4 l+ V7 _% A, ^4 FStartUART_Rx:开启中断,同时开启HAL数据流。本来调用HAL_UART_Receive_IT会重新开启中断,不过前面我把它屏蔽了,这样,这里初始化开一次就行了,上面代码中关中断部分已经屏蔽了; }/ B5 d4 E" i! d' g( G
HAL_UART_RxCpltCallback:接收中断回调函数
, u8 x8 O% s, C) C$ M( `/ L# w, D3 pHAL_UART_ErrorCallback:错误中断回调函数5 K/ @5 a+ b0 [( G8 T( Z

) V* C# N# k* N
  1. /* USER CODE BEGIN 1 */
    : D* l" j& U; M5 W. N& ?! Y+ q5 O
  2. uint8_t a=0;4 L- e9 ~( v# T& e7 k
  3. void (*UART3_Callback)(uint8_t)=NULL;4 o5 n# N1 [8 c; K. q
  4. void StartUART_Rx(UART_HandleTypeDef *uartHandle)
    * q  N( N) w* S( [: A
  5. {5 ~# f4 u: q4 b1 X# a1 u3 o# r
  6.         if(uartHandle->Instance==USART3)+ U% F0 U; \1 T) ^  d! |3 R8 {$ n. J
  7.         {
    ! |$ O, e* X6 d. ~
  8.                 if(HAL_OK!=HAL_UART_Receive_IT(uartHandle,&a,1))
    6 o8 a- [/ Z# n- E+ u$ Z* P+ `! t# H7 W
  9.                 {
    ! j% N7 w- e" X  L4 {0 I/ b- g1 ^
  10.                         assert("HAL_UART_Receive_IT",__FILE__,__LINE__);
    # w1 u. p4 A+ J3 K" u: z; J
  11.                 }        - f2 q' g7 A- n0 ]$ U
  12.                 SET_BIT(uartHandle->Instance->CR3, USART_CR3_EIE);        0 Z4 }; l% e' x$ C: t
  13.                 SET_BIT(uartHandle->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);                4 {. s* O5 r8 E- x7 i+ A4 e6 ~
  14.         }
    2 J* a* z3 R& v
  15. }
    6 T3 L- c: G) q& ?& w. e
  16. 0 r0 v; C1 i/ p+ r
  17. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle); \9 q) S. i) z, a! e4 |: a' V; O8 N
  18. {
    9 C# C, o& w1 i, g- I
  19.         if(uartHandle->Instance==USART3), ?: g- I6 W$ k
  20.         {! A* M9 x+ }9 m, Z7 F) F( \6 S
  21.                 if(UART3_Callback!=NULL)7 U! n- Q1 m" z6 J
  22.                 {
    , B; G+ u2 j# F# o1 Y1 a6 |
  23.                         UART3_Callback(a);
    / ~$ ^8 l1 \5 I1 @
  24.                 }
    ! N( w* W3 ~" i. x
  25.                 if(HAL_OK!=HAL_UART_Receive_IT(uartHandle,&a,1))
      |* a/ A: a& i; i+ }* W3 D
  26.                 {
    2 e) N) O( s+ N9 j" ^1 O' L
  27.                         assert("HAL_UART_Receive_IT",__FILE__,__LINE__);
    ' c7 \5 ^( c6 P- F' a7 D
  28.                 }                        ( K9 v# _+ E" \9 }" ^
  29.         }
    " W3 |( u& [; `9 _2 E
  30. }
    8 C, Y) s; q, t- t( X$ y8 R8 B
  31. void HAL_UART_ErrorCallback(UART_HandleTypeDef *uartHandle)* ~7 I( r0 i4 F
  32. {
    8 V7 M+ v( e! j& s, n+ r, W6 f
  33.         uartHandle->RxState = HAL_UART_STATE_READY;+ F; R' Z/ m/ n& [0 j/ R
  34.         if(uartHandle->Instance==USART3)- H" d# N; F7 w' A3 d1 I
  35.         {: g  \6 y4 J. D$ I7 F# p, U
  36.                 if(HAL_OK!=HAL_UART_Receive_IT(uartHandle,&a,1))
    0 R4 }6 K" i7 ~. ?
  37.                 {
    ; G+ E$ l% k$ u" Z5 X" Z
  38.                         assert("HAL_UART_Receive_IT",__FILE__,__LINE__);
    8 ~9 W# \  V% `/ p
  39.                 }
    % }( \7 K/ w, x& A. O! \
  40.         }
    + m( c# N! ]! w& k8 A9 r/ I8 u
  41. }" v2 E  i' S2 t; M

  42. ; @3 w. R) o1 ~% J& j" J& B7 \
  43. 4 E) [9 D, c+ p  l! O, v
  44. 4 W. Z5 c( Y9 J
  45. /* USER CODE END 1 */
复制代码

# \; i" Z! r3 F0 W' m4 d
% y2 F8 ~  [$ R, |

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


2 N% g7 A  G4 z* o, V, A/ g

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

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

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

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

4 F. C  N6 @# X" r  s
+ O- K3 b5 C3 P4 F# z$ X0 y! i* P

- h" B9 q+ `2 x2 y, G
, V; S5 J( }" k

评分

参与人数 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管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版