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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 21:00
stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法
8 @+ d* L9 E6 L- x. _0 T芯片型号:stm32h743! t( Y* [3 N& F8 v
串口:USART2
- ^4 y- W# x. O' }% s0 U6 f2 ~代码生成:stm32CubeMX
' M; Y  ]! J3 |/ }第一步:使用stm32CubeMX生成代码/ e) Y1 U1 s, d& ?: I1 v
2 E* m  e2 n/ t# M+ s5 c9 C
第二步:添加自己代码
, P0 Q' t4 h4 F
2 T  d! i, F; z& L5 a# `1.发生空闲中断需要reset DMA重新开始接收数据
6 ^8 y7 V5 b! {" m) _$ e; z! T$ I
  1. HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
    # v! |: X! s, v: X. M
  2. {
    / j' T" n" j" W
  3.   /* Stop UART DMA Rx request if ongoing */
    % g! l# c% d. v% [' [. k% t7 Y
  4.   if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&9 k$ v- v! M6 D- N
  5.       (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))- ?& n; L" m0 }+ }! w7 h
  6.   {
    1 G! u$ i/ L: Y* O3 b6 j* z
  7.     CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);' N) h% F2 H- a' y: T3 B

  8. % _8 }# {  ^: ]1 n
  9.     /* Abort the UART DMA Rx channel */
    $ c6 K" |$ ~4 |0 f( R
  10.     if(huart->hdmarx != NULL)- R% \" v. H' X& g$ f. v2 `5 m
  11.     {
    3 Q2 _2 U! K' j8 @2 r' m9 }/ t9 D
  12.       HAL_DMA_Abort(huart->hdmarx);
    % |% a" ~$ a5 D3 B5 P! g
  13.     }4 {- t8 h2 `, K2 {( v
  14. * g$ o/ l: _6 V/ O7 m( @
  15.     //UART_EndRxTransfer(huart);7 H+ N0 f2 X5 E1 U
  16.     /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
    0 n0 \7 J: i. H" l/ o
  17.         CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
    & I/ C0 t" W* g* n
  18.         CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    ( a5 u  ?2 q" X/ _5 x3 Y

  19. ; _- {* V( F6 B+ Z2 n) t
  20.         /* At end of Rx process, restore huart->RxState to Ready */3 @% q" \* Z& o: w) l
  21.         huart->RxState = HAL_UART_STATE_READY;9 T8 I0 A) d  O
  22.   }# ~! M* X+ x6 j

  23. ) p! ]  k+ i, x
  24.   return HAL_OK;2 }: L6 o- a* O3 m
  25. }  b6 `# R8 Z5 M2 j: k' H
复制代码
5 N! v3 n0 q/ R8 P: V
串口空闲中断6 ~. P1 J4 q/ V& C

, U$ n' ~+ ?; r
  1. /**- C1 Q5 @' N# |& h  S) f
  2.   * @brief This function handles UART4 global interrupt., s* {$ v" p2 {) D- n: x
  3.   */& t% X5 w- _9 b0 f
  4. void USART2_IRQHandler(void)
    2 Q2 k, N0 M8 Z4 Z! G/ E. w  P" N; S
  5. {
    % k1 C$ n- e( b% a2 v. _
  6.         uint32_t _len_dmarev;
    4 ]& ^- y3 K& |$ b
  7.         uint32_t isrflags;
    " K5 l0 U0 O( q! A- `! t* U
  8.         uint32_t cr1its;
    : j% b: ~; O8 [
  9.         BaseType_t xHigherPriorityTaskWoken;! [5 r8 M" O3 t4 Y- w4 |+ O2 }

  10. % x5 z) ^: @" H  U3 t
  11.         ( V$ [/ a. A) Q: i7 g
  12.         HAL_UART_IRQHandler(&UART2_Handler);
    # w! j2 Y7 S5 Z; W& J" t/ ?
  13. " c; t3 h; T& r6 x
  14.         isrflags   = READ_REG(UART2_Handler.Instance->ISR);  U2 G; V! b& ?7 h
  15.         cr1its     = READ_REG(UART2_Handler.Instance->CR1);, M. i" ]/ o) y0 X- v- m- R3 w
  16. ) {/ A0 i  M( u" y$ g5 W* v# c
  17.         if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))' w  y8 D; p6 ]! s
  18.         {
    8 a( A3 t% W7 q8 s2 d
  19.                 __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);: J0 u0 ?; [8 d/ \6 R+ \7 n" [5 h

  20. * B* `; c3 `) m  E
  21.                 _len_dmarev = DMA_BUFFER_LENGTH -                                         __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);7 R7 N. [$ j' @$ h$ A; X6 B2 d

  22. 3 H6 K1 Y$ }! L. o! M4 n1 m
  23.                 if(_len_dmarev): b* x! P$ }- O% q) D, Y4 o- s  O
  24.                 {
    % ~7 D9 f: ^. q0 J
  25.                   //停止DMA
    ' x2 w- V9 N; s/ J8 E
  26.                   HAL_UART_DMAStopRx(&UART2_Handler);
    ; g$ c* h9 M3 Y; D! U2 ?+ n2 y
  27.                 //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致
    $ C: i. f* d% t. F
  28.                  SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);& ^# w: B) X; T. ]1 A* K" W
  29.                  + w6 x  Q5 Y. V: X" L, b% h, ^
  30.                  xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);
    + ?' E; B' m3 R. o# {8 w2 [
  31.                  
    " _0 z7 _  A* S' U5 A
  32.                  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    0 j, `6 `! P! l; r7 ], g6 W* ^, a

  33. ' u% m) f- P' I; D
  34.                   HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);
    " A: J1 g, w1 q
  35.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);
    : p, \1 S* L9 \' B* U: O
  36.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);
    ' k, g( v' ?  ]" G! s6 M  V
  37.                 }
    / T4 @5 d6 L9 e
  38.           else
    1 M0 |) {4 G) i( w3 w1 ?
  39.           {+ d: W; E9 |; r/ P7 A1 }0 N. @
  40.                   READ_REG(UART2_Handler.Instance->RDR);
    5 G( p* u4 j  C# \$ Q8 ]5 l
  41.                   __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);) L1 }6 c$ Y. T. ?+ M% T
  42.           }
    # S9 ]- Q& q& h9 s/ s" @: ~

  43. - {3 x6 Z8 p* K
  44.   }
    : j4 a( S% n$ M5 R0 S. S2 x4 D
  45. ; N" d# c3 \! k8 G* v  O- \
  46. }- C2 a- E3 k4 E8 C8 y: q
复制代码

6 [, O2 n- ]) W2 E, w发送函数
. r" @$ R7 s2 Q2 Q+ W  C4 g) V
- v+ V# H8 l+ z. P
  1. unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)( {  V$ E7 ~( _! i/ V; E
  2. {1 A7 p$ i" Z5 p3 I! s
  3. UINT16 i;% R& _5 G2 M/ Z" ^

  4. 2 t( z/ Z6 I9 g6 T" S! K
  5. //拷贝数据到DMA buffer
    : C' I2 m; B+ M
  6. for(i = 0; i < len; i++)
    , n8 Y3 _. S4 G9 G! P& \$ p; B# Z
  7. {1 L5 e2 l3 w' ^: E
  8.         dma_tx_buf<i> =</i> buffer; - m, E$ |+ K! t% |1 q. U! I
  9. }5 j: F, X: i% ^9 j' g1 ^
  10. & C7 H4 I0 O) \# f( `8 z: P+ H
  11. //使发送RAM和cache一致. {0 V9 B: v, H# B' n" |
  12. SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);
    ! _" [0 S9 ~5 x. O7 I0 ]
  13. HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);/ K* u& k) `2 d3 D8 E! W6 g
  14. return 0;
复制代码

, T8 H' x- o; k7 |+ h% b# ?还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域
; l& ?- U1 y" ~" q$ v1 h可使用下面的编译指令:
& d6 R# m: v9 l: h, r9 C8 H5 Q
  1. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;
    4 P0 F: i1 q9 Y* Q
  2. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);* z6 f* b8 y& p+ H& _$ o7 Z3 {
复制代码

; L9 A0 r9 m, L3 ^5 j
收藏 评论0 发布时间:2021-12-27 21:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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