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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 21:00
stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法# V5 r( E9 D) a% z3 ~
芯片型号:stm32h7435 Z* y/ j) ~; t5 b3 _  }! t
串口:USART2' C) f/ D- E8 m* j+ A, A  z6 P
代码生成:stm32CubeMX3 }; e+ c, ~3 P3 ]- ^, G
第一步:使用stm32CubeMX生成代码, _1 ^# u4 H9 n' Z8 l/ G

' j  c0 p+ @8 x  W第二步:添加自己代码# A3 J5 [8 c2 R; q& a
( q2 m* @6 T1 N7 r; N) P  n
1.发生空闲中断需要reset DMA重新开始接收数据3 \' N4 \0 Z# n
' O5 T" |% P2 N( z+ i
  1. HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)' I+ V1 A5 W& c
  2. {
    3 E: ]1 K" N% E' {* i- Z
  3.   /* Stop UART DMA Rx request if ongoing */
    : T% Q2 A+ c; V0 ~+ l' T" H% i
  4.   if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&5 B' D; ~! P0 i8 y+ Z/ H* H
  5.       (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))2 r* h7 W0 c& p. E
  6.   {0 [) y# L# d% R, x3 Y
  7.     CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);( K, Q5 p- z0 p: {' a5 P

  8. $ @! _. N* R9 [0 A5 y! c. N
  9.     /* Abort the UART DMA Rx channel */5 n+ U, q' q$ J+ r" F
  10.     if(huart->hdmarx != NULL)
    5 f) \$ z  X% J
  11.     {
    5 `) b8 }7 L; f5 M6 `; L- @
  12.       HAL_DMA_Abort(huart->hdmarx);/ V8 `, l* M2 M5 |! B$ K
  13.     }+ j( F" z# u! C4 q0 p8 i& \! O

  14.   K! k2 b; q9 l9 g6 g9 H3 @, Y& U
  15.     //UART_EndRxTransfer(huart);
    % d1 Z: ?3 `1 {5 u0 k5 u, m# q7 a
  16.     /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts *// C6 F8 N. @) Y7 ?- c( i+ l
  17.         CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
    + o) P* Q$ a9 C& Z- u1 {8 d- |
  18.         CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);1 T; ~6 \( O5 j, t5 ^( C+ K

  19. ' }% x) ~# Y  n
  20.         /* At end of Rx process, restore huart->RxState to Ready */# k" Z8 w% X4 w1 w1 C% f7 ~0 p
  21.         huart->RxState = HAL_UART_STATE_READY;/ E7 Q/ _  L& u( X5 y
  22.   }& M: U4 O0 E5 c
  23. 5 E5 c% W( x+ I8 Q2 Z; E+ _5 L" J
  24.   return HAL_OK;
    7 O  c# M: X0 q9 X- X
  25. }. A! Z/ j3 U2 D% H3 N
复制代码
- @0 A$ U7 U1 {/ u) I
串口空闲中断* U0 x& g. O+ I$ ?

/ i; N3 V2 A" `. k
  1. /**
    9 F! u: W# i8 s5 z
  2.   * @brief This function handles UART4 global interrupt.
    8 E" @5 s* J$ q/ n3 a
  3.   */
    5 b$ S0 F' a; ]0 Z& D+ E5 q& X
  4. void USART2_IRQHandler(void)
    2 d/ A5 q! E7 t! _- [
  5. {
    ! c- W) ?8 }1 ?/ G
  6.         uint32_t _len_dmarev;; f; H' L1 H1 F8 V7 ]/ t0 t$ x
  7.         uint32_t isrflags;* F2 Z) i5 W$ Q" Q! d! O/ z6 H
  8.         uint32_t cr1its;
    ! X: W  Z5 p$ c: G' r! d8 t
  9.         BaseType_t xHigherPriorityTaskWoken;
    8 G2 q. P7 a" ?4 X( F" b$ n: ^
  10. " l2 `* o2 s7 V- ?
  11.         ; T6 a6 r$ I8 x3 q* D3 N, A( [3 x, [
  12.         HAL_UART_IRQHandler(&UART2_Handler);2 J4 x/ R2 d, g$ x

  13. : X' r* H" W3 x* ]
  14.         isrflags   = READ_REG(UART2_Handler.Instance->ISR);
    4 }  O. r' h& |! r5 q
  15.         cr1its     = READ_REG(UART2_Handler.Instance->CR1);
    9 O/ I  l' Z+ T9 H1 r9 x

  16. ) Q+ I6 E1 M' k3 _1 T! W) \; i: b: D
  17.         if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))8 X# C' ]1 h( J
  18.         {8 A2 }! w* M( o# p* ~3 G1 h3 o) S2 F
  19.                 __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);
    ) K7 |9 p0 u0 f' R% f

  20. 5 F* X, U( [" P  h4 y# e
  21.                 _len_dmarev = DMA_BUFFER_LENGTH -                                         __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);
    + Y$ k" r# F$ k7 x, d8 z7 l

  22. ' o4 _9 P% H6 N* x+ f/ }. i
  23.                 if(_len_dmarev): i9 f1 s5 o3 l" t( s, K, Y0 a0 i
  24.                 {
    , E# V2 d: _) k$ N
  25.                   //停止DMA
    ) |% N) S9 r# E, S; E. t% ^
  26.                   HAL_UART_DMAStopRx(&UART2_Handler);
    5 u! Y/ `. m# j5 j3 G9 j
  27.                 //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致
    - p$ S8 ~5 f" h4 p; R
  28.                  SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);
    5 w- \, v' Q' Y
  29.                  
    6 q" r( c3 x5 G& {
  30.                  xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);
    , Z+ D) X- N4 P2 b2 N3 i
  31.                  
    ) U' h3 m9 Z0 J! [4 F
  32.                  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    % r' q* R9 n; P  z9 k# R" A
  33. 0 \1 D/ k7 ]# y( c4 K
  34.                   HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);1 O( W' S' l6 ^8 W1 o8 Z
  35.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);
    1 I: Q, `8 d/ t
  36.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);
    # N3 G* B7 ]5 `6 J7 M+ c# i1 V  I% T
  37.                 }( i3 d7 w+ r- s2 D% Z, W0 V7 _# W
  38.           else+ P5 p2 s0 R$ f1 V
  39.           {  H6 i4 g6 h9 P, t* k$ t* z
  40.                   READ_REG(UART2_Handler.Instance->RDR);
    6 t( c% e/ c* x9 f. |3 E
  41.                   __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);
    $ f7 \, Q/ E; ?* v1 B6 b6 q
  42.           }
    ( O5 |3 A" D6 b5 u& \4 f+ d& Y; @7 _$ @
  43. 2 e3 x) W" L  M: y# x
  44.   }& @% J$ X4 \7 }" c: \% q& ]. S4 s8 ]3 W
  45. ( s; \( \5 _1 ^4 H
  46. }3 m* ?; C3 `# f( M4 W6 }- w
复制代码
: E( o, I- w; O: [9 i
发送函数; F$ [( k/ Q4 r3 t% {# W- N2 j

5 s+ W  B8 j7 S, J, v' g
  1. unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)
    - ~6 j; W$ r) I3 ^/ U
  2. {6 M: f/ f3 b0 ^( T
  3. UINT16 i;
    1 [: u, h' ^  i2 e! ~
  4. 9 r* B/ `7 P4 ~( `! s: K/ I
  5. //拷贝数据到DMA buffer
    ( I- k1 k( G* a' {2 r, J
  6. for(i = 0; i < len; i++)6 J2 s4 B" L- e- p
  7. {4 g2 [7 I' y& c: H6 G
  8.         dma_tx_buf<i> =</i> buffer; " c) q0 r! O  e9 {
  9. }' h+ f3 ~) l8 {. s

  10. ) }' M* Z) e9 K  \9 Y5 _/ @
  11. //使发送RAM和cache一致
    3 y3 }3 [! X7 l' a- `& ]
  12. SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);$ f8 F" u% b9 C) u
  13. HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);2 Y, h2 Z3 \: q/ o! n
  14. return 0;
复制代码

% M( t$ w' S+ c$ s$ D% @还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域# b; I* ^* t* h6 a0 B/ C
可使用下面的编译指令:; z; e  ?' C6 N: v: ^/ a
  1. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;
    0 P- u  x5 U( \/ \& Y
  2. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
    . t5 c9 B0 u3 Z& b' T4 ]/ d
复制代码

2 N. u5 c! T- W
收藏 评论0 发布时间:2021-12-27 21:00

举报

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