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

【经验分享】STM32H7串口DMA+空闲中断实现接收和发送不定长度数据

[复制链接]
STMCU小助手 发布时间:2021-12-27 21:00
stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法
. w3 \8 V( @+ J/ j4 ~芯片型号:stm32h743/ r, n# `* K3 J. h
串口:USART2/ [5 o, X8 m, B  [( ~# c3 r
代码生成:stm32CubeMX! {& Q/ b% ]& f1 e/ t
第一步:使用stm32CubeMX生成代码( O/ H8 ]; B0 m6 x& L: O
; i  a* @, w& S
第二步:添加自己代码
! k% d) `- \0 |% w( F* G7 c( \. N! r& T9 o* e& t
1.发生空闲中断需要reset DMA重新开始接收数据! a8 P7 ~% I7 Z
3 E, d$ q+ T: C) _9 A. j
  1. HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
    # R) q# [' U; j+ o% O: A
  2. {' [; L" _9 P* y  P! A
  3.   /* Stop UART DMA Rx request if ongoing */
    . b) U4 O; z6 |8 ~' U
  4.   if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&
    5 e# z7 C: {  L/ r& }
  5.       (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))* j* b$ k8 Q3 z3 G* R8 h& G
  6.   {
    ' h9 T- s  B; h( F' G
  7.     CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
      X9 Y2 D" F3 A  d
  8. " ~8 e6 B( u1 E* k4 A% ]  F# Y" K
  9.     /* Abort the UART DMA Rx channel */
    ( p9 [3 X- @* t) P
  10.     if(huart->hdmarx != NULL)  S! E# ~% W, Z7 r9 {4 A
  11.     {: k, `* C' p0 u1 |' D% j  r
  12.       HAL_DMA_Abort(huart->hdmarx);' I9 ~" ^! J8 y+ ^: {/ g  p
  13.     }$ `4 u! L6 O4 ~8 M9 M$ G; s  w1 v! h
  14. ' v" i% o+ T/ z( e$ j
  15.     //UART_EndRxTransfer(huart);$ Q. c. S( F- C9 N& o3 O. [1 Q
  16.     /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
    , U$ n/ B* _5 W+ Q$ p
  17.         CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));7 u& @" r: H* ]8 ?
  18.         CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);" u7 z* [, E8 R  f! m

  19. 3 e+ y3 J& E* W+ H6 C5 _- W' x; F  W% J$ v
  20.         /* At end of Rx process, restore huart->RxState to Ready */
    : l( g; I% P3 w% M  {" n+ [; f
  21.         huart->RxState = HAL_UART_STATE_READY;
    7 U  l9 d" b' D- `) m- Z# p4 H
  22.   }
      i7 ^/ X4 q* U' u5 m
  23. ' R) w5 n8 G) F' \1 q- |
  24.   return HAL_OK;. y8 w) I$ Y5 a) ^
  25. }
    ' C; }. [- |3 j; Z: @, f% @: F
复制代码

( L- b, Q" f& s, r. ]; S串口空闲中断
, ~: P- R2 g0 F4 c, I
- o# b* g8 ?. Y+ J$ @" b7 v
  1. /**% Z9 R  A" P6 M; \3 g2 x
  2.   * @brief This function handles UART4 global interrupt.5 s$ s1 E& Q& D
  3.   */( t7 k8 g* v9 X6 P- t- k
  4. void USART2_IRQHandler(void)
    . x% c0 L8 l. M6 Q
  5. {
    % ?! v" T* k6 M) r5 P
  6.         uint32_t _len_dmarev;
    0 }5 c3 ~$ p% `/ k" K
  7.         uint32_t isrflags;( S7 V" u( v2 q. s+ s# |/ M& J4 C
  8.         uint32_t cr1its;
    ' K: l2 F, e' ?% _' z
  9.         BaseType_t xHigherPriorityTaskWoken;; _, G+ K* \. s* P) h1 C# F6 Q

  10. / s& X/ o. q# J) N- k* c5 |$ U; I
  11.         
    % Z" f& Z7 n( K5 U, I7 l6 ?
  12.         HAL_UART_IRQHandler(&UART2_Handler);
    ( O4 `- W+ g: }
  13. / V& i$ s: J7 [- z7 h. o# q
  14.         isrflags   = READ_REG(UART2_Handler.Instance->ISR);
    4 {( b- b6 _- C- d: g
  15.         cr1its     = READ_REG(UART2_Handler.Instance->CR1);
    6 V6 i+ N8 i) ~* B. e( H/ X0 Y

  16. + o' p+ s2 k6 B; S( \  u5 J
  17.         if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))# o# ^. Y7 \4 A# z  I0 g( R5 i
  18.         {
    ) V% I" Y! y5 n5 \2 U3 s8 l
  19.                 __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);
    6 ^  a+ D0 V. i1 T9 @

  20. , |( S$ m& A9 S, @* @# p  {/ i0 N
  21.                 _len_dmarev = DMA_BUFFER_LENGTH -                                         __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);
    ! }# e7 Y; J0 S9 ?$ O. j
  22. 3 r. A$ @. G& |) V2 v9 v
  23.                 if(_len_dmarev)7 H# a/ m3 N* Y6 Y- E
  24.                 {
    ) W  Q8 s7 N  g8 m6 i. i( K
  25.                   //停止DMA* P" c" T4 h* A  E, Q
  26.                   HAL_UART_DMAStopRx(&UART2_Handler);% w; B" {1 o# G0 `  K# W
  27.                 //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致8 N2 m; p5 o8 r5 x# {' B1 l1 S
  28.                  SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);
    9 H+ m2 _/ v6 F6 Q; q8 X6 t; v/ Y
  29.                  ! G' ^+ o' E# G% D; m: \; L
  30.                  xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);
    6 v, h4 K$ @4 P2 O3 v/ _
  31.                  
    4 }  w, w' R( r% }6 d, p: a: w4 ^
  32.                  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);/ B/ I  s4 a9 D2 G! S. D* U' d+ k0 f

  33. ; u' G; \: {- p" o& m
  34.                   HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);
    6 R1 j$ m) Y0 x% G+ A( H3 X/ P9 L
  35.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);
    ! q* x" r% h+ s' i3 v) O
  36.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);' d' a& V% \6 Z' E  s+ q
  37.                 }
    7 P& _) A/ F! R0 K% E7 F
  38.           else; m3 B8 D* v: @7 I  U
  39.           {; U- e8 V5 ]5 F- m
  40.                   READ_REG(UART2_Handler.Instance->RDR);
    ( T5 P- D3 U- |3 X4 M# {) t- P) p' w
  41.                   __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);
    9 l# \1 z; Z" l) y
  42.           }
    * h; M  D( I' g  I, V% d3 o

  43. ( k# y. p. O9 p9 @5 }
  44.   }, I, f( h  X; D1 Q, m0 J

  45. 1 B$ S. O  q3 c7 o3 w
  46. }
    * A+ `" P; i! F2 ]* Z% D5 s  @
复制代码

0 J" k9 g$ ^/ Q% i$ Z! J! |) l1 p发送函数" a5 K+ W) J  s7 u1 D
5 I  X' u0 V5 U
  1. unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)
    * e  Z0 B7 [( B' G  h, E
  2. {: c$ t- X( r( Q$ D
  3. UINT16 i;
    ( M4 w$ w- k6 v/ @3 N

  4. / _' |5 g3 F, T' ^1 Q) k+ t3 O
  5. //拷贝数据到DMA buffer
    8 h8 {# I, m+ m& p/ D. ]0 O
  6. for(i = 0; i < len; i++)
    6 V. o; r/ ?3 |  t7 V- B' q
  7. {
    7 E! s. s+ O& n) s0 \1 g* B" C
  8.         dma_tx_buf<i> =</i> buffer; % R- ]% b$ f; @7 L5 X; b) S
  9. }
    , S" i2 l: v9 }) K- w  e1 E2 l; h
  10. / D9 \  f. k' j- g5 o2 b
  11. //使发送RAM和cache一致! O1 m7 i" D. E7 E% X
  12. SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);+ p' E: Z  ?, o% \, I' G' T  e
  13. HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);- ^& E- p; X+ P! ^; ^
  14. return 0;
复制代码
8 n) N/ O3 r6 ^
还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域
' u! C7 {- J9 z; c; v1 |* {4 |可使用下面的编译指令:
. G0 n5 O" t9 `4 |  y; x& v7 c' B
  1. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;# {! Z4 O9 B/ ^- v1 C( l
  2. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
    ' W2 H. O1 y$ b1 j  R: B0 z+ G
复制代码
$ E3 \: K+ C9 N5 K( ^6 r
收藏 评论0 发布时间:2021-12-27 21:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版