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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 21:00
stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法6 h; o( y5 Y1 k+ a* A+ U
芯片型号:stm32h7432 U5 C- \3 L) w  D0 t( O6 W
串口:USART2* j* u! G0 u8 O, |& Z, U
代码生成:stm32CubeMX. C+ C/ w! j  }2 \% U8 b: W5 Y7 C7 f' x
第一步:使用stm32CubeMX生成代码0 e. I8 q; g" o1 I! I) T$ E5 n: W
8 P  B9 m! o; D+ o
第二步:添加自己代码% u" O% A; C* T2 P, H; S7 Z
5 i% n; G+ @5 ]5 X/ W+ P
1.发生空闲中断需要reset DMA重新开始接收数据
3 v' \, y; O9 T2 j: O2 J
" d7 O- |3 n4 S5 O7 Z# }
  1. HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
    2 O& u. b) T& M- V4 o
  2. {. b; [$ I' B9 ]) G  @
  3.   /* Stop UART DMA Rx request if ongoing */6 J5 n# @2 f! R0 o6 ?6 q0 x4 g- d& c
  4.   if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&
    & H$ c4 H* s3 P" x/ u
  5.       (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
    * u* C- ]( F* c2 p, Q
  6.   {
    ( \* t- d( ^; ^7 j" a( g4 U" A$ `
  7.     CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);8 C6 t, c& e- o

  8. 2 Q6 Z) f6 Z' ]4 v, L3 _# ]6 y
  9.     /* Abort the UART DMA Rx channel */
    7 _+ P8 i! g- J0 m* j3 v% |( i& T/ H
  10.     if(huart->hdmarx != NULL)
    5 p" s& T0 f0 H4 x2 R
  11.     {" J8 J4 _- O0 j2 g6 X
  12.       HAL_DMA_Abort(huart->hdmarx);& W4 k* y' F. M1 P$ V1 S+ z  T
  13.     }( ]4 o5 X7 F) B! m8 h. S7 b
  14. ' r0 \5 }4 h0 ?7 o; k
  15.     //UART_EndRxTransfer(huart);
    . G% w# @6 i- p& e% u/ z
  16.     /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
    : E% D7 _2 n0 d3 A: V) Z% G& R) O
  17.         CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));  i% U( O3 v% Z" o! O: B
  18.         CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    ; b7 T+ ~0 H! M% ]8 v: h" D" b

  19. 9 m0 E) k" L* U3 j
  20.         /* At end of Rx process, restore huart->RxState to Ready */5 V1 n! ~0 \- y$ \
  21.         huart->RxState = HAL_UART_STATE_READY;
    ( k: n5 H* M: l
  22.   }6 t3 I0 S6 ?. ?& D

  23. 6 F) V5 T# N; |5 P
  24.   return HAL_OK;. B/ x9 O. E: h
  25. }
    $ j0 ?+ H5 T! b8 o
复制代码
' k8 _6 y) H4 a% t. G! D% K$ p
串口空闲中断% M0 K# Y) f* D) b% A3 q

/ c# _2 w, m1 d$ j9 E% |6 f* k7 [
  1. /**8 R; F* \" B* d: r
  2.   * @brief This function handles UART4 global interrupt.! G8 b" Y9 O) \. L' T" Q
  3.   */
    7 c9 K/ u6 D& ~+ @+ r
  4. void USART2_IRQHandler(void); a  i% o# ?' W! B* C
  5. {$ n" l+ V$ Y& O3 k3 @
  6.         uint32_t _len_dmarev;. C8 e4 ?% [% n, q
  7.         uint32_t isrflags;
    : V. K8 e! G4 l& `! f4 q
  8.         uint32_t cr1its;( H0 q8 N' z. m0 I/ Z1 \) m
  9.         BaseType_t xHigherPriorityTaskWoken;
    1 d' z( Z0 D& G% U0 G2 k' i8 R
  10. * \$ d" \; K% I$ ~9 U! M- _
  11.         
    & L. g* b) a- \. A
  12.         HAL_UART_IRQHandler(&UART2_Handler);1 T, c) i" a5 i" k* c9 D
  13. * y  w  u$ I0 E6 @' t) s8 c
  14.         isrflags   = READ_REG(UART2_Handler.Instance->ISR);
    $ a6 T# {$ K+ `# ~; t) W' G
  15.         cr1its     = READ_REG(UART2_Handler.Instance->CR1);( D4 t8 N; R3 p) y" r
  16. ) ~$ k" _+ ~; T& D
  17.         if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))
    7 [7 Y9 [+ i- q
  18.         {. I) C+ I- i2 z% U8 T: x6 W
  19.                 __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);
    . A* n2 A! z' Z7 N
  20. ! r4 P# K, E: y
  21.                 _len_dmarev = DMA_BUFFER_LENGTH -                                         __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);
    $ `2 z- C5 B( F% H0 S- x# T
  22. ' C7 T- b/ H6 q: e
  23.                 if(_len_dmarev)
    * p6 E+ h% Q- I8 k5 ^
  24.                 {$ W; G8 x( j. g9 q
  25.                   //停止DMA
    / q/ t$ q/ W* A- J& O
  26.                   HAL_UART_DMAStopRx(&UART2_Handler);
    9 I, B# U$ C/ K  i3 A" S
  27.                 //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致
    2 y2 ?7 y; t: L' U5 Y5 [
  28.                  SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);, P  a' ]3 f" |7 @, C- g
  29.                  3 w0 x+ G7 h0 a$ g5 _
  30.                  xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);3 C5 x2 N: ?" G( ~8 p
  31.                  
    / o: o* G0 ?( o3 t( H
  32.                  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    8 b& y* p9 [& A( b0 A; X

  33. 3 l# L0 W) O8 k: d! ^' w+ }0 W5 a
  34.                   HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);
    8 [2 {, w0 f4 E/ |. A8 `
  35.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);& I9 t3 U9 y' x+ l* n7 f  f2 b
  36.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);- [* Z& K" M! L2 c; }& T( Y9 T
  37.                 }1 @9 K( {+ m' {; s( g, W: R# z
  38.           else; e# _/ ^  F, T5 ~7 e8 j1 g8 \& E
  39.           {
    * g1 k, k9 E0 ^' e
  40.                   READ_REG(UART2_Handler.Instance->RDR);
    ' k) Z  U- z% E9 `: w
  41.                   __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);+ L4 A8 N: M9 {, X9 e
  42.           }! i+ f9 b' u6 X5 t# K1 w/ T
  43. 3 @6 m( l  l1 h
  44.   }
    ) W6 P" _" l/ T- ?5 O9 x  Z( x

  45. 1 c3 e/ ]) J8 r5 a
  46. }
    3 J: X% Z6 P& M
复制代码
0 `8 g" D) r( |
发送函数
0 P0 W! n! P" N- G$ f! Y' L! W  G+ [' F9 B
  1. unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len); [, T$ s. Q3 Z7 I7 S4 M
  2. {
    / V. ^4 Y  T* y1 Z9 y  }8 M  k
  3. UINT16 i;
    2 S! d. q& u  u3 X5 S. ?! C- E! ]
  4. 0 G8 V( u  n* x/ F0 W3 P, s. J% n
  5. //拷贝数据到DMA buffer) j! Y# @0 W1 h0 u4 t
  6. for(i = 0; i < len; i++)
    ! V2 b- y0 B+ m+ U/ D9 h+ V
  7. {
      S% Q4 J3 y9 C
  8.         dma_tx_buf<i> =</i> buffer; 8 j( Q4 n9 J: Y! ~
  9. }
    : O7 c4 c) w# }/ k( q% e* }$ O
  10. ; w- O0 P8 m5 y+ ^1 P& d
  11. //使发送RAM和cache一致4 U5 n- s# S! L# g
  12. SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);
    5 ]8 B7 O4 c6 a7 _
  13. HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);
    4 r1 F% H! c6 T& O6 N3 }
  14. return 0;
复制代码

7 G$ w( r! }  b- j/ d% a还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域
* V8 q4 k: o: E, ^7 {! b2 O" Z8 v可使用下面的编译指令:/ S5 ]; @4 {& Q& b, Y
  1. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;4 R0 ?4 u8 i5 `  ~! t
  2. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
    ! z& O! n) ^1 {* ?& H! M/ h
复制代码

8 Y' L2 c& m- X& k8 D
收藏 评论0 发布时间:2021-12-27 21:00

举报

0个回答

所属标签

相似分享

官网相关资源

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