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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 21:00
stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法
  P$ {, }4 ]9 j0 r芯片型号:stm32h743
# A1 i# w& {, A5 i/ Q串口:USART2: ?4 z  @. k4 A: j4 N5 {' O
代码生成:stm32CubeMX8 H% z* x0 x) k0 p3 w
第一步:使用stm32CubeMX生成代码$ Q6 O" s9 W# y+ S- Q1 r, I
9 A2 _3 o6 W9 R' ]2 s
第二步:添加自己代码  {; y, _6 |* I* S. F+ {
8 q  N+ Y) h5 w
1.发生空闲中断需要reset DMA重新开始接收数据5 K. z, I, ~7 s

3 r. d& T2 Q( y
  1. HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
    # ^, q- `& I+ V: z+ J+ u9 J) E
  2. {4 k: D% {' y+ G6 U1 k; ]
  3.   /* Stop UART DMA Rx request if ongoing */
      L; P: L1 n& H# b$ _
  4.   if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&. V% ~5 a- O) V$ }
  5.       (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
    - H" ~% U1 S( a% [& g+ `  T
  6.   {" ^: a  J# b! e" W- d
  7.     CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
    % S' I: X) G2 O/ c3 w

  8. : I/ N6 N) h& `/ f  Z# Q
  9.     /* Abort the UART DMA Rx channel */9 \/ C" }3 M3 [( q
  10.     if(huart->hdmarx != NULL)2 z6 Y# g5 w* Q- J
  11.     {
    ' o) A9 }9 V+ a. ^6 [. R! E; G/ M
  12.       HAL_DMA_Abort(huart->hdmarx);% r9 t& V/ _7 k" A  v
  13.     }
    4 x3 Q# K' Y3 G* M: K2 f
  14. % s9 b  S# M, {
  15.     //UART_EndRxTransfer(huart);
    * L1 \2 y5 _5 z
  16.     /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */% K1 ]; d/ G8 S% R8 D
  17.         CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
    2 {7 L. N; y+ z
  18.         CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    9 N6 a* t1 s, ~9 \; s5 t0 J
  19. 7 m0 i& ]/ L8 M# Y
  20.         /* At end of Rx process, restore huart->RxState to Ready */
    * l& J- X8 s8 D& X% [
  21.         huart->RxState = HAL_UART_STATE_READY;" q5 o* _! \: X2 N( _
  22.   }% U7 T9 U. L( g8 ?# j
  23. 5 J$ \/ w+ b1 f# X( J' J
  24.   return HAL_OK;3 J0 s1 S; Y( O. X& ~
  25. }
    ; j0 O% y) k% n% _8 P; Z+ T
复制代码

# x& Z3 ]: Y; m2 Z# \1 K6 X串口空闲中断
8 V1 S* j, D& R
# v+ A. @  ~) y# O
  1. /**+ x0 a& N1 b+ H+ K: {: ]
  2.   * @brief This function handles UART4 global interrupt.4 @) t6 E4 G2 Y% Z
  3.   */
    2 J$ {3 U& ]$ x
  4. void USART2_IRQHandler(void)  p! Z& }7 K5 L& V. l
  5. {
    . c9 F: t/ U+ `2 J5 u( p: A
  6.         uint32_t _len_dmarev;
    % o5 E. L, \, R1 ]+ _  Z  A0 a2 G  |
  7.         uint32_t isrflags;# O! y& ~0 Y/ C0 S! ]
  8.         uint32_t cr1its;! K4 M5 L& T3 F  G  u3 S
  9.         BaseType_t xHigherPriorityTaskWoken;
    , r* L) _: E9 j

  10. / P# m) y1 y& _% e- ]! l' ~1 i
  11.         
    $ I6 K0 I( w! U* @& \$ |
  12.         HAL_UART_IRQHandler(&UART2_Handler);
    + N% R# y1 m( f; i

  13. 8 q+ r, V0 V$ ^8 h3 b" {/ y! r2 k) l; k
  14.         isrflags   = READ_REG(UART2_Handler.Instance->ISR);
    , @: y4 L2 ~" P5 o$ C' u
  15.         cr1its     = READ_REG(UART2_Handler.Instance->CR1);
    / h' t8 _2 g. M2 a' L
  16.   K/ ]0 a, p0 P. y0 ~1 H
  17.         if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))5 T$ [# |2 ?: ]4 ^$ B& M" H
  18.         {
    $ b! X8 A0 H: L
  19.                 __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);- ]2 C0 d4 R+ a

  20. 5 {0 k) i6 s# {2 S8 x( ^! f
  21.                 _len_dmarev = DMA_BUFFER_LENGTH -                                         __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);2 U. L0 a& {% e* Q$ [6 c

  22. - U% O* a0 h% v9 p: Y; s
  23.                 if(_len_dmarev)7 l6 T6 ^4 {) [3 d$ z. t
  24.                 {- A1 b; i) G+ X. A1 R2 u
  25.                   //停止DMA
    ( W% ?7 U4 m. p5 S7 w2 y
  26.                   HAL_UART_DMAStopRx(&UART2_Handler);
    3 e/ A/ L" d( m9 j1 H) b
  27.                 //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致% N* e- C5 y! ?. w( Y/ }$ e" T
  28.                  SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);
    9 E% V0 m( c0 e" t
  29.                  
    8 N, d/ [7 P7 M0 @: I3 o# j' l
  30.                  xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);1 v3 K; o/ y2 ~2 T) S
  31.                  
    . |8 `4 |, N- G/ Y$ n4 ?+ ?$ B9 x
  32.                  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    2 x' U& o1 K: c! E9 @
  33. + n4 e. p% F$ p
  34.                   HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);7 y. P& o% w  `. |. z
  35.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);; Q/ `5 m0 k5 k$ z* r
  36.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);
      F  D, p" J) c( |9 H0 n' S" N7 y2 r
  37.                 }' D+ y% n- Z' Z! [4 k
  38.           else
    ; ]1 l; V: |6 q* Q% W( _* G+ K
  39.           {$ p' I9 M  d5 Y9 ^: M. g" V6 O# Q! @
  40.                   READ_REG(UART2_Handler.Instance->RDR);: y' m1 P6 H1 }
  41.                   __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);! \7 F2 c+ R+ p0 ~1 s0 ]+ R: U% X
  42.           }' T1 i( u3 D- G# Y( F# O

  43. , V. U' [5 _& l1 F( d, [) B7 b
  44.   }
    3 J$ e* s# }- A9 q
  45. ! `, {- q- {0 T% h
  46. }
    * g2 _! ~' N( R+ }
复制代码
% E0 v! r  i' }- {
发送函数
1 B" ~7 L( ^0 P3 H1 h5 i$ W  c$ C
  1. unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)1 G  J3 D0 @) B  r6 ^- G4 r7 [
  2. {4 T% H: d( f, F
  3. UINT16 i;1 V0 \9 r3 e6 l8 N$ \8 d
  4. ( z" e) E! u5 u! Q) O; n. n
  5. //拷贝数据到DMA buffer
    1 s* u$ V9 f" o* y: _. s
  6. for(i = 0; i < len; i++)
    1 s' C. d+ i' e  s, V
  7. {
    - ]! K* z# K# k2 m4 @
  8.         dma_tx_buf<i> =</i> buffer;
    - U- ?! d) p# _$ |7 h0 M3 ~
  9. }
    4 i2 x6 o: \& K8 R5 g* e$ p

  10. * G: n, D# @0 H8 k/ }2 }8 `' M
  11. //使发送RAM和cache一致
    + E" @1 V9 F$ b! C, g
  12. SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);
    1 j6 v% y9 e+ v1 A8 B1 v0 ~3 N) a
  13. HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);
    % Z1 B7 g5 J! {6 f* F2 U
  14. return 0;
复制代码
2 ~6 d& K9 m  }% U1 q* d6 r% p
还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域' m* h+ i' x0 G- q
可使用下面的编译指令:
) j& e( A; o$ V
  1. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;. @9 m( D$ l& H0 {0 F
  2. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
    ( y/ j" C( w. _7 R% ]
复制代码

# a! p( F$ b$ u# E. d
收藏 评论0 发布时间:2021-12-27 21:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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