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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 21:00
stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法- R) Y# y2 J: h) M
芯片型号:stm32h743
1 p3 V8 w/ I' n% w# t# V串口:USART2
* E. N' V/ t2 ~代码生成:stm32CubeMX
' X- r  X8 w5 U第一步:使用stm32CubeMX生成代码
# f2 T! o% B& c8 P; u/ ~% [* k& T) j4 H, a/ [. q
第二步:添加自己代码
; O: `4 I# `4 M6 t: `4 A9 t. _5 T5 u% o8 h, r
1.发生空闲中断需要reset DMA重新开始接收数据
3 K% A6 Y3 W" U' J! a1 D( {$ t& Y! X3 a; f0 M* r6 D1 Y
  1. HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
    5 [8 J/ f$ R) E6 u* ]
  2. {
    " r3 ~! _" g" Q
  3.   /* Stop UART DMA Rx request if ongoing */
    0 H$ B7 E+ W3 q, B. W5 L5 m9 E
  4.   if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&
    $ [" Q  k% X% `
  5.       (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))$ C' ^* r* m) n8 a# X3 |
  6.   {
    ) Z8 L9 Y# d; n) |! g& ~2 E2 P* X
  7.     CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);+ V& s4 y3 k' Z  J' b8 e; G% L
  8. $ x7 h( ]3 E3 ^4 g0 o4 T: b' X
  9.     /* Abort the UART DMA Rx channel *// e/ X, A7 u# C. o
  10.     if(huart->hdmarx != NULL)) C. S6 k) Y* C& t4 V: G9 Y. r
  11.     {' |( J) q* S, r' o0 B
  12.       HAL_DMA_Abort(huart->hdmarx);
    $ p  @0 ]* T6 I1 E. i7 p) A2 S5 Q
  13.     }
    ) |. C: J) R* C0 D7 F2 G7 R

  14. 4 W) r! Q0 Z* N
  15.     //UART_EndRxTransfer(huart);# P+ Y. ^6 L) m: L7 \
  16.     /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */0 x4 ]& D# T( r2 l: M
  17.         CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));- o( |( c# C. k' V, }
  18.         CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);8 N& I3 ]) V. Y
  19. ; ^) j! H9 Y* {6 g
  20.         /* At end of Rx process, restore huart->RxState to Ready */
    8 v" }* N: k4 a0 l/ R( {
  21.         huart->RxState = HAL_UART_STATE_READY;# o" w* G2 g1 u. B
  22.   }
    ' o/ {+ p6 a: d1 ~& C8 v

  23. 2 U3 h  Q2 z9 q* e6 a
  24.   return HAL_OK;
    + d+ i0 l; n$ B6 h
  25. }
    5 Q: ^2 y' p$ Y& k/ R
复制代码
9 t7 h5 ~$ P# @3 i5 S8 B3 }
串口空闲中断
! X: X3 y8 H3 `6 N; p; K- S( s+ W/ C( G  o: h
  1. /*** r' p& O! f4 l: ~: g( C% ?" x" N& V
  2.   * @brief This function handles UART4 global interrupt.% {" O" P+ p% \. c
  3.   */9 [4 Q% a" a: x8 X. n- W' R: h
  4. void USART2_IRQHandler(void)2 f. g" e  p8 W5 t/ J; y; D
  5. {7 q8 ]9 l% D  f- d- j, V% J
  6.         uint32_t _len_dmarev;
    + \$ U* m5 W  C0 j$ q$ Y0 n/ _/ ~
  7.         uint32_t isrflags;9 t: }4 R4 _4 m; W' M
  8.         uint32_t cr1its;
    2 \0 L9 l4 z' m* e( H/ z7 C
  9.         BaseType_t xHigherPriorityTaskWoken;
    ) {" l+ n2 C$ c. E& X$ ?

  10.   a3 g( z2 I* G8 v0 X1 W+ ~
  11.         : J5 K( N& z- Z+ x0 K5 ~, l" ?+ y
  12.         HAL_UART_IRQHandler(&UART2_Handler);- D' L' C3 ~4 N! e6 P
  13. " |$ I0 \4 p4 l3 p& g+ }$ x* v' G
  14.         isrflags   = READ_REG(UART2_Handler.Instance->ISR);: p  b! O: e- }4 p- f+ T1 z5 F- m  I
  15.         cr1its     = READ_REG(UART2_Handler.Instance->CR1);
    $ |2 ?& t3 R! U
  16. ! c' N- ~, c4 E1 Q+ R# ?" p" O
  17.         if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))
    % w8 \% S0 g% d* X% F
  18.         {
    0 k/ D' ^5 I+ Q; d: w4 i
  19.                 __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);: j2 ]9 O  F( N0 m

  20. " u6 V4 t$ ^2 D3 [. }
  21.                 _len_dmarev = DMA_BUFFER_LENGTH -                                         __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);" T/ v. G8 `+ C# K1 _  A

  22. ; D9 t) c# x' y$ t3 |/ t
  23.                 if(_len_dmarev)% _2 k/ U* s- ]' H3 f
  24.                 {; R& [3 H* p9 c) a
  25.                   //停止DMA' F0 y4 w3 _. b4 M
  26.                   HAL_UART_DMAStopRx(&UART2_Handler);! y, G; b, s& q4 f! Z$ M/ T
  27.                 //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致! S1 K8 ~' e5 h6 E7 Q+ n
  28.                  SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);
    ; v8 s' S* d8 U, z
  29.                  % f" E3 }  g4 Z* U& V3 |8 ^
  30.                  xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);2 e. m) @$ y7 Z! Q! o" d8 x) L
  31.                  
    / l6 q1 ^. @2 p5 {
  32.                  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    * [# o4 x- W4 D: @. c: N% _
  33. 7 f% j2 I6 \) P" ?$ Y+ y7 @3 C- R
  34.                   HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);
    1 R! H% T0 W  s0 P/ R% r
  35.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);
    $ p- w/ j4 B) p
  36.                   __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);$ j- m# b9 H9 z" o( D
  37.                 }
    $ @* I: ]3 Z$ a) R3 }5 X
  38.           else6 D( r1 X7 m$ \' c2 D
  39.           {
    $ w+ B, S9 {' D
  40.                   READ_REG(UART2_Handler.Instance->RDR);
    8 k7 ^# K9 f( K& ]- q( I
  41.                   __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);6 H( v+ x7 p9 s# T  R7 \
  42.           }% }( S: o2 ~. p8 X
  43. & @% E2 ^* R* o& t, L5 R
  44.   }
    + t/ z5 y. n' x( d
  45. % f3 P& l, {9 y& o! _/ Q5 J- U+ b
  46. }
    0 Q; \- a0 W' w1 o* [! {
复制代码
& Y! O, j: b( R# @6 U6 G
发送函数0 Q" O& O$ J2 M/ p

( b6 g7 n: w; a% U4 L. {& H
  1. unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)
    + b' B3 k; {, X" k+ U: T3 o, n3 z0 f
  2. {
    & u# L2 B0 }( m5 w( J6 Q( G0 M
  3. UINT16 i;! F7 Z% \6 Q  `) n5 M2 F1 ?8 @, y
  4. $ k5 g& R  g: h/ Y* m
  5. //拷贝数据到DMA buffer
    3 l" K6 s3 P8 t
  6. for(i = 0; i < len; i++)3 D/ ?6 F+ _- }  ^; d) W  t
  7. {. W( {* T7 j# u: g9 n
  8.         dma_tx_buf<i> =</i> buffer; / i' {- G% M) i
  9. }
    5 S2 B) a. A1 L0 u6 U
  10. , `6 i* L+ k2 C' F( `- \! s. a
  11. //使发送RAM和cache一致
    / Y7 _, x/ [  d3 M
  12. SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);
    & N) F5 O* l' {6 E8 T: m1 s
  13. HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);
    * [, s9 O+ u& e# \. z
  14. return 0;
复制代码
% ?* N; `! K& ]9 L( V# x) j5 `
还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域
5 Y3 g* ~: W. k* W3 H可使用下面的编译指令:* \1 D- [) K6 M3 c, {
  1. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;
    - [! R* b7 L2 l1 c/ L
  2. ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
    * O0 @( w. _/ ?' D1 W" w( U
复制代码

5 K- Y9 f" G: y2 @' t
收藏 评论0 发布时间:2021-12-27 21:00

举报

0个回答

所属标签

相似分享

官网相关资源

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