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
- HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)' I+ V1 A5 W& c
- {
3 E: ]1 K" N% E' {* i- Z - /* Stop UART DMA Rx request if ongoing */
: T% Q2 A+ c; V0 ~+ l' T" H% i - if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&5 B' D; ~! P0 i8 y+ Z/ H* H
- (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))2 r* h7 W0 c& p. E
- {0 [) y# L# d% R, x3 Y
- CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);( K, Q5 p- z0 p: {' a5 P
$ @! _. N* R9 [0 A5 y! c. N- /* Abort the UART DMA Rx channel */5 n+ U, q' q$ J+ r" F
- if(huart->hdmarx != NULL)
5 f) \$ z X% J - {
5 `) b8 }7 L; f5 M6 `; L- @ - HAL_DMA_Abort(huart->hdmarx);/ V8 `, l* M2 M5 |! B$ K
- }+ j( F" z# u! C4 q0 p8 i& \! O
K! k2 b; q9 l9 g6 g9 H3 @, Y& U- //UART_EndRxTransfer(huart);
% d1 Z: ?3 `1 {5 u0 k5 u, m# q7 a - /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts *// C6 F8 N. @) Y7 ?- c( i+ l
- CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
+ o) P* Q$ a9 C& Z- u1 {8 d- | - CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);1 T; ~6 \( O5 j, t5 ^( C+ K
' }% x) ~# Y n- /* At end of Rx process, restore huart->RxState to Ready */# k" Z8 w% X4 w1 w1 C% f7 ~0 p
- huart->RxState = HAL_UART_STATE_READY;/ E7 Q/ _ L& u( X5 y
- }& M: U4 O0 E5 c
- 5 E5 c% W( x+ I8 Q2 Z; E+ _5 L" J
- return HAL_OK;
7 O c# M: X0 q9 X- X - }. A! Z/ j3 U2 D% H3 N
复制代码 - @0 A$ U7 U1 {/ u) I
串口空闲中断* U0 x& g. O+ I$ ?
/ i; N3 V2 A" `. k- /**
9 F! u: W# i8 s5 z - * @brief This function handles UART4 global interrupt.
8 E" @5 s* J$ q/ n3 a - */
5 b$ S0 F' a; ]0 Z& D+ E5 q& X - void USART2_IRQHandler(void)
2 d/ A5 q! E7 t! _- [ - {
! c- W) ?8 }1 ?/ G - uint32_t _len_dmarev;; f; H' L1 H1 F8 V7 ]/ t0 t$ x
- uint32_t isrflags;* F2 Z) i5 W$ Q" Q! d! O/ z6 H
- uint32_t cr1its;
! X: W Z5 p$ c: G' r! d8 t - BaseType_t xHigherPriorityTaskWoken;
8 G2 q. P7 a" ?4 X( F" b$ n: ^ - " l2 `* o2 s7 V- ?
- ; T6 a6 r$ I8 x3 q* D3 N, A( [3 x, [
- HAL_UART_IRQHandler(&UART2_Handler);2 J4 x/ R2 d, g$ x
: X' r* H" W3 x* ]- isrflags = READ_REG(UART2_Handler.Instance->ISR);
4 } O. r' h& |! r5 q - cr1its = READ_REG(UART2_Handler.Instance->CR1);
9 O/ I l' Z+ T9 H1 r9 x
) Q+ I6 E1 M' k3 _1 T! W) \; i: b: D- if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))8 X# C' ]1 h( J
- {8 A2 }! w* M( o# p* ~3 G1 h3 o) S2 F
- __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);
) K7 |9 p0 u0 f' R% f
5 F* X, U( [" P h4 y# e- _len_dmarev = DMA_BUFFER_LENGTH - __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);
+ Y$ k" r# F$ k7 x, d8 z7 l
' o4 _9 P% H6 N* x+ f/ }. i- if(_len_dmarev): i9 f1 s5 o3 l" t( s, K, Y0 a0 i
- {
, E# V2 d: _) k$ N - //停止DMA
) |% N) S9 r# E, S; E. t% ^ - HAL_UART_DMAStopRx(&UART2_Handler);
5 u! Y/ `. m# j5 j3 G9 j - //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致
- p$ S8 ~5 f" h4 p; R - SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);
5 w- \, v' Q' Y -
6 q" r( c3 x5 G& { - xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);
, Z+ D) X- N4 P2 b2 N3 i -
) U' h3 m9 Z0 J! [4 F - portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
% r' q* R9 n; P z9 k# R" A - 0 \1 D/ k7 ]# y( c4 K
- HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);1 O( W' S' l6 ^8 W1 o8 Z
- __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);
1 I: Q, `8 d/ t - __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);
# N3 G* B7 ]5 `6 J7 M+ c# i1 V I% T - }( i3 d7 w+ r- s2 D% Z, W0 V7 _# W
- else+ P5 p2 s0 R$ f1 V
- { H6 i4 g6 h9 P, t* k$ t* z
- READ_REG(UART2_Handler.Instance->RDR);
6 t( c% e/ c* x9 f. |3 E - __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);
$ f7 \, Q/ E; ?* v1 B6 b6 q - }
( O5 |3 A" D6 b5 u& \4 f+ d& Y; @7 _$ @ - 2 e3 x) W" L M: y# x
- }& @% J$ X4 \7 }" c: \% q& ]. S4 s8 ]3 W
- ( s; \( \5 _1 ^4 H
- }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- unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)
- ~6 j; W$ r) I3 ^/ U - {6 M: f/ f3 b0 ^( T
- UINT16 i;
1 [: u, h' ^ i2 e! ~ - 9 r* B/ `7 P4 ~( `! s: K/ I
- //拷贝数据到DMA buffer
( I- k1 k( G* a' {2 r, J - for(i = 0; i < len; i++)6 J2 s4 B" L- e- p
- {4 g2 [7 I' y& c: H6 G
- dma_tx_buf<i> =</i> buffer; " c) q0 r! O e9 {
- }' h+ f3 ~) l8 {. s
) }' M* Z) e9 K \9 Y5 _/ @- //使发送RAM和cache一致
3 y3 }3 [! X7 l' a- `& ] - SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);$ f8 F" u% b9 C) u
- HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);2 Y, h2 Z3 \: q/ o! n
- 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
- ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;
0 P- u x5 U( \/ \& Y - 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 |