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

HAL串口库的分析于修改

[复制链接]
tanic 发布时间:2019-1-17 17:00
本帖最后由 tanic 于 2019-1-17 17:02 编辑
& I! v+ F/ Z" l0 W
, q2 e- h* |+ d- |8 x8 A: b, x之前做一个项目,串口收发频繁就老卡死,后来用了保守法度过去,近来有空详细分析,发现了问题,并解决,这里分享一下。! S( V: p; C" _! `

8 I6 [( }$ Y) K4 m这里不对基本操作分析,仅仅讨论一种方式,能让我们稳定的用串口,本文会对HAL库进行些微的修改。. U" a- e* i" ]! b9 @3 @" M  A4 R
HAL库的串口大致可以分解为2个部分,一个是寄存器控制部分,一个是数据传输部分。我接下来的只修改寄存器控制部分一点点内容,数据传输部分不变,任然采用其回调函数形式,下面具体说明。
$ }0 E0 n2 E' [一般来说最常用的是发送数据HAL_UART_Transmit,中断接收数据HAL_UART_Transmit_IT。串口其余,如DMA什么的不做分析。4 x4 B7 P  i9 b; s  k4 w. ?
研究一下会发现,HAL库中强制对串口进行了半双工限制,其实STM32的串口是全双工的,很多时候卡死,是因为我们做了全双工操作导致的卡死(不是HAL_UART_STATE_READY状态)。. n# L5 N0 v, q5 v! O8 z* |( q
HAL_UART_Transmit修改后如下
' _$ B+ G6 d: U6 e% f7 z
  1. HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
    , x. ?  E6 h9 G% |, Y% U/ u
  2. {
    ! o& X; K  L6 Y' N
  3.   uint16_t* tmp;
    0 s* |, U, L5 M  F9 v
  4.   uint32_t tickstart = 0U;
    1 P+ P3 O' w$ |% k& L! J

  5. ( B3 {9 D5 \- k! \/ ?2 s
  6.   /* Check that a Tx process is not already ongoing */
    : m6 \- s8 R1 m: c- e& o: A, u
  7. //  if(huart->gState == HAL_UART_STATE_READY): [( E0 _# S% C" M' M0 a
  8.   {
    8 a4 E- {8 `& y; H8 R5 \) m" I
  9.     if((pData == NULL ) || (Size == 0U))3 I5 m: h6 o6 F2 e6 A
  10.     {$ R# x$ Q$ x9 J, C
  11.       return  HAL_ERROR;3 Y* G4 c* T4 \
  12.     }$ S' t3 s& l( r$ |1 A+ x
  13. ; @7 H7 V$ Z( u; p7 B* O5 K9 t, B
  14.     /* Process Locked */* N8 F8 w8 o4 f8 {! ^) n
  15.    // __HAL_LOCK(huart);% i4 p( r/ M1 x3 K
  16. ! e6 s* b; q" H. D% S
  17.     huart->ErrorCode = HAL_UART_ERROR_NONE;
    + u+ {; s" n, v4 d8 T- P0 y
  18.     huart->gState = HAL_UART_STATE_BUSY_TX;
    % z, V4 A/ e: ~
  19. ( t0 u, j" S  H9 p  y
  20.     /* Init tickstart for timeout managment*/& `( v" L' w8 |! w$ J3 q( {5 N
  21.     tickstart = HAL_GetTick();
      _) g' i* R' C
  22. . P3 A  {9 D0 b8 Y& ~. b
  23.     huart->TxXferSize = Size;" g0 M% u& @2 Y5 B5 w% G
  24.     huart->TxXferCount = Size;
    . B* F+ D; O$ a) K+ h# v
  25.     while(huart->TxXferCount > 0U)* @8 t9 D  A. e9 m: q
  26.     {
    3 `; N5 d. G# S5 p
  27.       huart->TxXferCount--;
    & J  k9 k* |  z' M$ |, o$ G! i
  28.       if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
    , t4 u# l+ [/ w* Y4 n  }
  29.       {
    " l- y# m: r: {) k) K% L) D; R3 |4 s3 c
  30.         return HAL_TIMEOUT;
    $ [3 h( ~; v4 G2 {- @% n! I3 W
  31.       }! k7 u$ P4 ?  q, u" y/ _
  32.       if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    ; K$ m/ g9 U% Q$ p5 H% l) P* g7 _
  33.       {
    / P1 [1 a5 U& n! K
  34.         tmp = (uint16_t*) pData;
    - t0 \$ F. p. P* y4 F
  35.         huart->Instance->TDR = (*tmp & (uint16_t)0x01FFU);
    0 c* U4 R- P7 r2 k* |1 a
  36.         pData += 2;
    $ F3 {% z/ T: z" a0 @: p2 `* D4 i
  37.       }
    4 j' ]& A  I" @/ H6 d
  38.       else- u, g) ^% b" ?8 \& F2 o
  39.       {7 ~0 X% ?2 O7 a6 B2 n
  40.         huart->Instance->TDR = (*pData++ & (uint8_t)0xFFU);% ?9 c% }7 X) _# ~. g
  41.       }( \2 r9 v$ m3 m1 J- i
  42.     }! ~& d' f) f7 ]# k% e7 u8 Q
  43.     if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
    1 R) r9 m$ J: x* s9 D0 y
  44.     {/ @: ]# N; c) w3 b; H
  45.       return HAL_TIMEOUT;
    & m: R, X; r/ c7 `- J( p! Q
  46.     }$ O5 G* X% ?3 l* s. E- X
  47. # d9 c1 {2 q5 i" Y
  48.     /* At end of Tx process, restore huart->gState to Ready */
    8 S! S" A) r, f; y! b( v. s5 r& C
  49.     huart->gState = HAL_UART_STATE_READY;
    & \: j1 J' d: B+ }/ r3 c

  50. 7 X  B" Z6 c! K
  51.     /* Process Unlocked */
    8 |, l" }8 v7 ~7 C5 c9 C
  52.    // __HAL_UNLOCK(huart);
    0 Q# q: K- q# J% T" H
  53. 7 F$ J0 X( a8 Z* {" e( B6 O
  54.     return HAL_OK;+ J, y9 ~7 c3 {3 H  J& }! ^
  55.   }+ E! M% X7 o+ r9 l5 N2 F! \6 L; V8 T: k4 |
  56. //  else2 d4 N& u, X/ g6 L& }* F
  57. //  {
    ! U  ]% p/ @) p
  58. //    return HAL_BUSY;; t4 O  n1 x( Q' b: G
  59. //  }; G+ l; M0 J9 A5 D# ^# k
  60. }
复制代码

& X% Z( i+ C* a1 Y+ S3 M! KHAL_UART_Transmit_IT修改如下,除了祛除限制,还屏蔽了中断使能,这个后面再说原因
7 M5 D5 e( _  p1 A2 Q
  1. HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
    4 W. o- Y# z3 _4 s! @* J) J! ^2 S
  2. {
    / v6 i! }! A& v2 T
  3.   /* Check that a Rx process is not already ongoing */" g5 h$ [# Y9 j$ @. I% D; J
  4. // if(huart->RxState == HAL_UART_STATE_READY). f0 }  ]" n- {% E% r6 d
  5.   {8 {7 u5 L% w2 Z. L( T
  6.     if((pData == NULL ) || (Size == 0U))" W  V+ I5 y0 Z( S3 ]- X4 m  O) v  S
  7.     {! @/ I- R: R$ H# u% \
  8.       return HAL_ERROR;
    $ ?# O1 l% ]- V$ D; M& Q0 t8 L
  9.     }( p! t+ g; o6 u8 ^; @
  10. 8 {  }6 ]* o+ s1 I* S# x# E
  11.     /* Process Locked */0 n. A4 |7 `/ w
  12.    // __HAL_LOCK(huart);/ Q6 |/ A0 u& s& |1 h4 N- T

  13. + v6 _) x5 ~( F2 T, }7 E
  14.     huart->pRxBuffPtr = pData;3 [" a1 U: N9 E0 j) ~( w" R8 \
  15.     huart->RxXferSize = Size;
    . j) `$ M2 s/ G
  16.     huart->RxXferCount = Size;6 B: M( E' v2 S/ @. N

  17. 3 H9 \* M/ z2 }
  18.     /* Computation of UART mask to apply to RDR register */
    ; R5 {6 f1 q3 F8 R4 h
  19.     UART_MASK_COMPUTATION(huart);2 \8 U: {  V3 m$ V$ C

  20. 2 ?  q, A2 x- Y* W; L: F
  21.     huart->ErrorCode = HAL_UART_ERROR_NONE;
    " O. E# D3 V& l  i( y: `& v( ?
  22.     huart->RxState = HAL_UART_STATE_BUSY_RX;- w$ |2 X' R* c+ \
  23. ! m4 P! V. k4 U2 Q1 E
  24.     /* Process Unlocked */5 r. {9 M" p( ^/ h$ o. |
  25.   //  __HAL_UNLOCK(huart);/ ^: n( z, p/ g1 k, }
  26. ( b9 V: g! G8 Q$ i
  27.     /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */5 k; L  u+ _  z$ q+ }# m4 Y
  28.    // SET_BIT(huart->Instance->CR3, USART_CR3_EIE);
    : L2 M* a4 \+ r4 _; P% G

  29. : N7 M4 q2 q/ Q, Y7 |! Y* ^9 w
  30.     /* Enable the UART Parity Error and Data Register not empty Interrupts */
    % I8 G) j) o: s2 f/ m6 u
  31.   //  SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);; S8 m4 {% ^# q! W% _* @( V

  32. , D3 ]* A' d- v; S# y9 K1 C
  33.     return HAL_OK;
    ) S9 g6 `- @7 M9 B; v9 b+ p
  34.   }; w$ y/ o. j( R: I
  35. //  else
    + \7 G, y2 F/ }7 B
  36. //  {" \4 z( k5 X4 l
  37. //    return HAL_BUSY;
    " |" p. n8 @- K9 U) H- ?) G! u
  38. //  }0 v0 m& ^4 E7 i2 {. K0 W
  39. }
复制代码
0 F* @- z/ q6 X3 ]
接收中断,屏蔽了清除中断的两行,中断开启后就不再停止了
- o) u/ H$ B& ~- _9 ~8 b& m
  1. static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)7 l. t$ I, w: Z- b" ^* k
  2. {! T5 D$ y9 u. }4 j9 U; K
  3.   uint16_t* tmp;$ K' c& {8 t5 g5 c  k4 B; X
  4.   uint16_t uhMask = huart->Mask;
    ' ~- M  V7 v5 G

  5. - P, S- W0 u( s* c# V% b
  6.   /* Check that a Rx process is ongoing */- d* u  }) d, i2 u/ A8 W  e6 J1 \
  7.   if(huart->RxState == HAL_UART_STATE_BUSY_RX)5 r; t4 G7 V+ o- \0 L* l2 q
  8.   {; _; p. V. K1 T* C9 }2 `$ h. d
  9. 8 \5 f9 w! Q/ `. n
  10.     if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    / v6 U- }3 c0 o% E
  11.     {
    + h3 m+ s. t8 \7 D& F1 R1 o1 k
  12.       tmp = (uint16_t*) huart->pRxBuffPtr ;
    : C- h. @. X( u/ s) y6 P8 j
  13.       *tmp = (uint16_t)(huart->Instance->RDR & uhMask);
    0 U. n5 z# F6 X( i/ y
  14.       huart->pRxBuffPtr +=2;
    # Q: B9 J$ h; D8 Q9 |
  15.     }- q4 Y$ r: _1 f2 @( Y
  16.     else4 \# I0 ~. U8 ~) }2 L: |' z* E
  17.     {
    # b! z9 _# i6 }0 F" z+ F0 G0 z
  18.       *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);" l+ V( r$ U" j7 T( f4 [
  19.     }
    8 ~! q, q. I, G+ ~9 _
  20. ! a5 R+ i9 p4 N( @& f
  21.     if(--huart->RxXferCount == 0)
    6 Y  c$ y' g* T% P
  22.     {
    ; ?' {! [" N' Y2 w0 Y7 O3 {
  23.       /* Disable the UART Parity Error Interrupt and RXNE interrupt*/
    % F  y1 ?9 l) |' i
  24.    //   CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));7 L2 m% ]5 X! p5 r' f2 Y
  25.   F& t% [3 @" f  h' k
  26.       /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    4 K1 D4 p# c0 ^: ]
  27.    //   CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    : E5 K6 r6 e. U" E( o  m1 z# M
  28. 3 D$ E) W+ Q) Z/ G8 l% X
  29.       /* Rx process is completed, restore huart->RxState to Ready */- r) A  _* }( ^/ u' p
  30.       huart->RxState = HAL_UART_STATE_READY;; ~! N- q/ ?! |% v/ X" H: S# [

  31. + l6 \" \" ~( G
  32.       HAL_UART_RxCpltCallback(huart);- h; Y- T8 Q3 D5 Q2 v; I( K/ x
  33. % C( q% `+ \# Y' b( f9 G5 f7 x
  34.       return HAL_OK;6 F/ \* R! B+ S* |
  35.     }; p( X! k, M% }7 r5 \  c1 n

  36. ( y) I0 k' b$ ^. @: G$ W) c
  37.     return HAL_OK;
    . ^/ h" l" O5 R; Q* u( m( s
  38.   }
    ' z. L% y& p! h7 S' V
  39.   else' T. N3 Q, J4 Y. {! C; e
  40.   {5 L. j0 X9 _0 X
  41.     /* Clear RXNE interrupt flag */6 ?  i. B& X. h' s% J
  42.     __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);4 m6 V2 {2 [& {* |' g

  43. ' L* w3 \$ u6 Q5 ~* m
  44.     return HAL_BUSY;4 c. ]6 }4 i9 N4 r5 j
  45.   }- p! m$ H2 d% l# L' U
  46. }
复制代码
  g6 G5 s1 g* G5 Y0 @; O
在usart.c添加如下代码,
# i. E$ ?9 C+ l2 p3 N( A. I3 X( w1 ^StartUART_Rx:开启中断,同时开启HAL数据流。本来调用HAL_UART_Receive_IT会重新开启中断,不过前面我把它屏蔽了,这样,这里初始化开一次就行了,上面代码中关中断部分已经屏蔽了! y: g, o, ^2 k6 P, M. }7 \
HAL_UART_RxCpltCallback:接收中断回调函数: X, v/ c$ E7 U# f$ f  T" C: E
HAL_UART_ErrorCallback:错误中断回调函数/ F0 {2 }1 c5 R  E/ H) N! d
" H# _/ p1 m& r  ~
  1. /* USER CODE BEGIN 1 */& }( j' W8 J# W! U) L0 |5 v
  2. uint8_t a=0;0 T' @' f3 M. A+ c. H
  3. void (*UART3_Callback)(uint8_t)=NULL;
    ; P9 T/ X) k  A( _
  4. void StartUART_Rx(UART_HandleTypeDef *uartHandle)0 W& B+ i" h* F
  5. {
    6 N! q7 i8 A) y% t
  6.         if(uartHandle->Instance==USART3)9 q. a" ?. g7 I: y
  7.         {+ D. V4 t- u1 V4 q
  8.                 if(HAL_OK!=HAL_UART_Receive_IT(uartHandle,&a,1))
    + b  t! M! {4 N& E
  9.                 {
    3 \6 r) U6 z$ R, w2 J5 C
  10.                         assert("HAL_UART_Receive_IT",__FILE__,__LINE__);- ]/ K$ G: g: q; m. `3 y
  11.                 }        
    ( `! t* M) b; o6 W, V
  12.                 SET_BIT(uartHandle->Instance->CR3, USART_CR3_EIE);        6 W4 T4 L. [  a, s6 k' ^
  13.                 SET_BIT(uartHandle->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);                1 K6 ?2 Q0 P# c9 T  W. M" F( q
  14.         }
    ! N! b& z7 W* j( a4 r
  15. }
    4 L" t8 |5 F( v% q2 M0 Q

  16. 2 q/ B4 h* ~9 c8 u
  17. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle)
    . e; J% b# @3 k% B. u
  18. {
    0 N: a5 N, _0 c- g
  19.         if(uartHandle->Instance==USART3)
    , f6 A' v" Q5 V) ?/ l' K
  20.         {
    - ^4 c; q9 D6 C* z6 t
  21.                 if(UART3_Callback!=NULL)
    6 m/ o6 z7 K7 G$ c8 \. x  o+ v
  22.                 {5 W  [; K/ J) Z2 u4 ?2 {/ T
  23.                         UART3_Callback(a);
    / O5 P3 u# P- O3 h( k
  24.                 }
    6 Y; O6 y  o- ~+ g
  25.                 if(HAL_OK!=HAL_UART_Receive_IT(uartHandle,&a,1))
    4 d1 b  y7 X% S0 m6 X2 A
  26.                 {6 a  t2 p: ~5 l) w& ^  }' a4 Y0 U% M
  27.                         assert("HAL_UART_Receive_IT",__FILE__,__LINE__);: c5 v% h0 M& `( U9 E5 ^
  28.                 }                          R9 \, t  ~* K4 I
  29.         }9 Z0 d  H2 X& e1 Q4 M2 e' }
  30. }
    ( N/ g; Z  G$ ]. a' @4 n
  31. void HAL_UART_ErrorCallback(UART_HandleTypeDef *uartHandle)
    ; ?$ B/ T! ~- [3 q) A- x
  32. {
    3 a2 F: K# i. v$ C- D% @2 T
  33.         uartHandle->RxState = HAL_UART_STATE_READY;
    4 [' Q) x2 S, H; f
  34.         if(uartHandle->Instance==USART3)
    $ G  ?6 [+ ~2 }$ Q( B
  35.         {: r- f  r+ i6 f5 ]
  36.                 if(HAL_OK!=HAL_UART_Receive_IT(uartHandle,&a,1))
    1 F# w' {) E2 Z6 ^
  37.                 {
    # B" \  d' c# [. T
  38.                         assert("HAL_UART_Receive_IT",__FILE__,__LINE__);8 I  `  Y4 c* B0 B9 ~( K% [
  39.                 }
    9 U1 h8 M$ ^/ X; g+ A0 _. a
  40.         }
    9 w5 m) M* l6 _* d
  41. }
    # \5 Q  t0 N4 _

  42. * o* y) {& g1 R* |; o2 M. k

  43. 2 g, N) l4 ~6 `" }& L! Q
  44. + z. r$ z8 U7 @6 u
  45. /* USER CODE END 1 */
复制代码

/ N. ?8 {# n& q/ ^: F/ }
7 P3 h) b7 ^7 e# A# i

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

6 s( F) g6 J3 }* W# N

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

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

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

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

+ n" m0 p  }1 f* h

$ H. ^' u' ]. c- k% |& p+ K5 r% }7 M1 x0 E7 P

/ T1 ^; X/ x2 b- |0 k% D! x

评分

参与人数 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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版