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- HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
# ^, q- `& I+ V: z+ J+ u9 J) E - {4 k: D% {' y+ G6 U1 k; ]
- /* Stop UART DMA Rx request if ongoing */
L; P: L1 n& H# b$ _ - if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&. V% ~5 a- O) V$ }
- (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
- H" ~% U1 S( a% [& g+ ` T - {" ^: a J# b! e" W- d
- CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
% S' I: X) G2 O/ c3 w
: I/ N6 N) h& `/ f Z# Q- /* Abort the UART DMA Rx channel */9 \/ C" }3 M3 [( q
- if(huart->hdmarx != NULL)2 z6 Y# g5 w* Q- J
- {
' o) A9 }9 V+ a. ^6 [. R! E; G/ M - HAL_DMA_Abort(huart->hdmarx);% r9 t& V/ _7 k" A v
- }
4 x3 Q# K' Y3 G* M: K2 f - % s9 b S# M, {
- //UART_EndRxTransfer(huart);
* L1 \2 y5 _5 z - /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */% K1 ]; d/ G8 S% R8 D
- CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
2 {7 L. N; y+ z - CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
9 N6 a* t1 s, ~9 \; s5 t0 J - 7 m0 i& ]/ L8 M# Y
- /* At end of Rx process, restore huart->RxState to Ready */
* l& J- X8 s8 D& X% [ - huart->RxState = HAL_UART_STATE_READY;" q5 o* _! \: X2 N( _
- }% U7 T9 U. L( g8 ?# j
- 5 J$ \/ w+ b1 f# X( J' J
- return HAL_OK;3 J0 s1 S; Y( O. X& ~
- }
; 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- /**+ x0 a& N1 b+ H+ K: {: ]
- * @brief This function handles UART4 global interrupt.4 @) t6 E4 G2 Y% Z
- */
2 J$ {3 U& ]$ x - void USART2_IRQHandler(void) p! Z& }7 K5 L& V. l
- {
. c9 F: t/ U+ `2 J5 u( p: A - uint32_t _len_dmarev;
% o5 E. L, \, R1 ]+ _ Z A0 a2 G | - uint32_t isrflags;# O! y& ~0 Y/ C0 S! ]
- uint32_t cr1its;! K4 M5 L& T3 F G u3 S
- BaseType_t xHigherPriorityTaskWoken;
, r* L) _: E9 j
/ P# m) y1 y& _% e- ]! l' ~1 i-
$ I6 K0 I( w! U* @& \$ | - HAL_UART_IRQHandler(&UART2_Handler);
+ N% R# y1 m( f; i
8 q+ r, V0 V$ ^8 h3 b" {/ y! r2 k) l; k- isrflags = READ_REG(UART2_Handler.Instance->ISR);
, @: y4 L2 ~" P5 o$ C' u - cr1its = READ_REG(UART2_Handler.Instance->CR1);
/ h' t8 _2 g. M2 a' L - K/ ]0 a, p0 P. y0 ~1 H
- if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))5 T$ [# |2 ?: ]4 ^$ B& M" H
- {
$ b! X8 A0 H: L - __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);- ]2 C0 d4 R+ a
5 {0 k) i6 s# {2 S8 x( ^! f- _len_dmarev = DMA_BUFFER_LENGTH - __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);2 U. L0 a& {% e* Q$ [6 c
- U% O* a0 h% v9 p: Y; s- if(_len_dmarev)7 l6 T6 ^4 {) [3 d$ z. t
- {- A1 b; i) G+ X. A1 R2 u
- //停止DMA
( W% ?7 U4 m. p5 S7 w2 y - HAL_UART_DMAStopRx(&UART2_Handler);
3 e/ A/ L" d( m9 j1 H) b - //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致% N* e- C5 y! ?. w( Y/ }$ e" T
- SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);
9 E% V0 m( c0 e" t -
8 N, d/ [7 P7 M0 @: I3 o# j' l - xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);1 v3 K; o/ y2 ~2 T) S
-
. |8 `4 |, N- G/ Y$ n4 ?+ ?$ B9 x - portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
2 x' U& o1 K: c! E9 @ - + n4 e. p% F$ p
- HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);7 y. P& o% w `. |. z
- __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);; Q/ `5 m0 k5 k$ z* r
- __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);
F D, p" J) c( |9 H0 n' S" N7 y2 r - }' D+ y% n- Z' Z! [4 k
- else
; ]1 l; V: |6 q* Q% W( _* G+ K - {$ p' I9 M d5 Y9 ^: M. g" V6 O# Q! @
- READ_REG(UART2_Handler.Instance->RDR);: y' m1 P6 H1 }
- __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);! \7 F2 c+ R+ p0 ~1 s0 ]+ R: U% X
- }' T1 i( u3 D- G# Y( F# O
, V. U' [5 _& l1 F( d, [) B7 b- }
3 J$ e* s# }- A9 q - ! `, {- q- {0 T% h
- }
* g2 _! ~' N( R+ }
复制代码 % E0 v! r i' }- {
发送函数
1 B" ~7 L( ^0 P3 H1 h5 i$ W c$ C
- unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)1 G J3 D0 @) B r6 ^- G4 r7 [
- {4 T% H: d( f, F
- UINT16 i;1 V0 \9 r3 e6 l8 N$ \8 d
- ( z" e) E! u5 u! Q) O; n. n
- //拷贝数据到DMA buffer
1 s* u$ V9 f" o* y: _. s - for(i = 0; i < len; i++)
1 s' C. d+ i' e s, V - {
- ]! K* z# K# k2 m4 @ - dma_tx_buf<i> =</i> buffer;
- U- ?! d) p# _$ |7 h0 M3 ~ - }
4 i2 x6 o: \& K8 R5 g* e$ p
* G: n, D# @0 H8 k/ }2 }8 `' M- //使发送RAM和cache一致
+ E" @1 V9 F$ b! C, g - SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);
1 j6 v% y9 e+ v1 A8 B1 v0 ~3 N) a - HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);
% Z1 B7 g5 J! {6 f* F2 U - 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- ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;. @9 m( D$ l& H0 {0 F
- 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 |