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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 21:00
stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法
4 n$ ]  h2 j+ F4 \& `) [0 O! o芯片型号:stm32h7430 W6 A- J& [+ P3 w- k
串口:USART2/ Q+ H9 M3 f3 r/ A& M
代码生成:stm32CubeMX. H9 G# I0 W+ {; N7 t9 A' q0 ~
第一步:使用stm32CubeMX生成代码
2 \' w. q1 i5 t1 R$ b* P2 ~/ l
& t1 ]: J8 c+ z: T第二步:添加自己代码! P1 @) v+ C; W  H

+ D+ G( r4 n- W% Q1.发生空闲中断需要reset DMA重新开始接收数据/ K: q/ H! `# ]

3 A! n3 d; n1 @0 U8 D  A
  1. HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)) c7 m0 F' ?7 v9 [4 S
  2. {
    / L7 i  x0 a- }4 I7 I
  3.   /* Stop UART DMA Rx request if ongoing */
    ! E$ o& w3 d+ b. q
  4.   if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&9 \; J  O* [- s8 k" L
  5.       (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
    ) u# ~. _% y) A% L
  6.   {: F$ s# C) c6 s" Q; |
  7.     CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
    . e8 v8 w% P, b: |/ `
  8. " M7 Z4 m4 O8 D: e( Q% b
  9.     /* Abort the UART DMA Rx channel */
    & y/ Y8 h3 N0 e$ R4 ]4 b3 k
  10.     if(huart->hdmarx != NULL)
    . L- Q! o+ k5 i
  11.     {, d3 Y' Z9 S. X8 I
  12.       HAL_DMA_Abort(huart->hdmarx);
    , ^6 _% w7 B: M; Y# A
  13.     }- f9 O; V0 q9 Y' e
  14. " K# `& ^# |- z3 ^1 X. J, N8 H
  15.     //UART_EndRxTransfer(huart);
    # C# @0 ?' [- F7 E* I6 Q/ J2 C6 Y
  16.     /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */* ]: e9 J2 h8 {4 g, ]
  17.         CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));  E) o5 @+ ]# Z5 _
  18.         CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    / N: Y* k9 a! P+ Q! Y- y
  19. 9 H- T. \3 {- j# |
  20.         /* At end of Rx process, restore huart->RxState to Ready */$ w- E# q8 S3 l6 x, c% f& w
  21.         huart->RxState = HAL_UART_STATE_READY;4 {1 T7 v$ B9 M* q  n1 u
  22.   }: D% U5 ^; b9 n. t
  23. & S+ l( S6 W- `
  24.   return HAL_OK;
    2 z/ ]: J3 [' I7 ^: H0 b. D8 q
  25. }
    6 E. O( B; M5 L9 Q# P: A
复制代码
. H& P+ w- C! |6 P2 X
串口空闲中断9 X  q% H6 k+ w% D) d9 |
" [/ h9 m8 F5 s) S  `; O" {& P
  1. /**3 [9 ]% w3 a; N% o- u; g4 |0 {
  2.   * @brief This function handles UART4 global interrupt.* D3 I8 Y; G% z! G3 A
  3.   */
    ' n( T9 t' g6 O& O5 u% L
  4. void USART2_IRQHandler(void)
    ! ~# F; L; ?+ `4 r
  5. {( r  J" ^* w1 r' l
  6.         uint32_t _len_dmarev;
    9 B. i: U+ H: {2 H+ I
  7.         uint32_t isrflags;
    0 ?$ ^! w4 ]8 @3 z2 {: \
  8.         uint32_t cr1its;
    2 _( ?, w; I( [) |
  9.         BaseType_t xHigherPriorityTaskWoken;
    * {% [' j& ?. G5 i8 F8 `( x! J
  10. . }3 x6 [: j( m- h9 Y8 j0 f* W+ _
  11.         % s) s0 \) f/ A$ c% g* A" [
  12.         HAL_UART_IRQHandler(&UART2_Handler);
    ! o5 I( N7 Q* e" M* t; J& Y% ^

  13. - `  g. V, d4 Z5 K* s
  14.         isrflags   = READ_REG(UART2_Handler.Instance->ISR);
    5 Y: Q  H3 s3 j+ G! b$ e
  15.         cr1its     = READ_REG(UART2_Handler.Instance->CR1);
    3 v) ?" l" F3 _. w
  16. : n0 _+ H, E5 s7 o) T8 R1 E6 H
  17.         if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))) t5 V- [4 Z/ ]; L
  18.         {# E; B- i- y3 L2 v3 N5 z
  19.                 __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);
    / T  c  h8 n2 F
  20. $ N9 }+ a& m; C2 c/ P  P/ R* J& J
  21.                 _len_dmarev = DMA_BUFFER_LENGTH -                                         __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);
    " R) k$ i9 W$ J  Q6 D  Q7 V
  22. 4 l& ~2 i( S2 |) y8 s
  23.                 if(_len_dmarev). j9 d! p8 ?# Z1 y7 C
  24.                 {/ p- Z- W5 F  `  ]/ S2 g- R+ H
  25.                   //停止DMA
    : ^# a! i! N, q- a
  26.                   HAL_UART_DMAStopRx(&UART2_Handler);
    2 p) X# K# w4 H* E5 R
  27.                 //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致! o1 a/ G( Q! a* u3 c
  28.                  SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);+ B$ m$ a2 }& o7 M
  29.                  , i) C4 R0 k% E, h0 d7 S
  30.                  xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);9 l6 d; p9 J9 }
  31.                  
    + P7 l: f& \- Y% ~
  32.                  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);* j& H2 f8 p: {9 B, Y  X

  33. ; }5 o/ V0 g  B6 d+ Y9 [( B" o9 J* C
  34.                   HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);& d: J; J; ]- }/ R2 u/ s7 k8 p
  35.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);* ^) V8 m9 [) L8 l% v$ e
  36.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);
    % ^$ Q. e  M8 l4 M
  37.                 }; h) W1 a' Q0 F3 z/ o$ Z
  38.           else& `5 V2 M8 I( M) `8 X7 l3 `, M$ ^
  39.           {
    ' p& h5 y" ^* w) [1 A  W' @3 m
  40.                   READ_REG(UART2_Handler.Instance->RDR);
    ! s, s' @, ^' K2 m
  41.                   __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);4 o( R' ~9 W6 ]& N" h: b
  42.           }6 H* A) A- L  ]  G* [0 f; O2 q

  43. 1 U& g9 ?8 s: F( o- H1 o
  44.   }
    ) a+ G3 O  t6 J/ Q' a) ?# j
  45. " Q% e0 _& `* S1 i' G: P
  46. }
    ' S1 @0 ~5 V, `
复制代码

0 ?; T0 b: A5 e  K发送函数6 z7 s' }) p' {: U9 C

& {8 T3 {8 w5 ~1 b
  1. unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)+ X- I6 `+ f8 ?4 u& @
  2. {
    2 h  `5 @. v! W( m: ?
  3. UINT16 i;) n# s" y0 k2 h4 F- J' B

  4. 6 t/ _4 \/ J  l* x  l) b; W
  5. //拷贝数据到DMA buffer
    6 T6 }2 {# o; Z% j2 t, @
  6. for(i = 0; i < len; i++)
    , u* l% m4 T% V" F+ L- ]( n
  7. {
    2 N# e: k/ m! C7 B8 n2 O3 o" U
  8.         dma_tx_buf<i> =</i> buffer;
    & `  b) t3 E3 t- `) K
  9. }: I" }2 Y+ U- e% Z- h7 v
  10. : J8 f' e. l1 G7 E5 U2 j7 C
  11. //使发送RAM和cache一致5 c' H( j5 Z& a# U
  12. SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);% E2 S. U* i2 X) c2 n% S
  13. HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);
    ( T( X5 I, E2 s7 z! X
  14. return 0;
复制代码

, ~) q9 H  U! C- m% T还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域& X2 V2 ]) D5 X' x+ E
可使用下面的编译指令:
: C1 d6 a% d. N: G9 b$ O% l# T$ T
  1. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;
    + J0 C2 s: O  i2 b" d$ u; a
  2. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
    * o$ G! C1 q0 K4 A9 S% H1 ^( a
复制代码

& Y& d$ A/ {7 _0 m
收藏 评论0 发布时间:2021-12-27 21:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版