stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法
, k$ t" a) x5 U4 O; }芯片型号:stm32h7432 _. P8 Z9 S: O- Z
串口:USART29 |( K" R' m Y
代码生成:stm32CubeMX
1 V: V7 I9 J8 @' |: `第一步:使用stm32CubeMX生成代码4 ^3 @: k7 o# Z! ?2 `- k0 i+ i
: F9 v% b' M3 M) ^第二步:添加自己代码6 W8 }' e& s; L2 Z* U
) k y Y9 x+ p \& ]4 S1.发生空闲中断需要reset DMA重新开始接收数据
3 d1 B( \0 j: S( x4 B5 r
) J; }" P0 r6 k$ @0 Y( j- HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
" G: h$ i+ d% L" d% ^6 k0 A+ i5 i - {
4 H: Q2 f/ a0 m( u. t8 | - /* Stop UART DMA Rx request if ongoing */4 K7 z9 |# \6 g5 D5 Y( j f
- if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&5 m" I5 \( @& a7 b7 ]6 C: F" n
- (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))3 T$ o. I# c2 z; d. l* _6 z# c9 B
- {
) n7 R; b% C' f5 x" n* T" a - CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
( B, Y; Z! n! W- J' m# n
( P. n2 X4 H7 J) ~4 ^4 y# P" @7 B- |- /* Abort the UART DMA Rx channel */
( J4 X1 ?4 {' ]; _* q" r4 ? - if(huart->hdmarx != NULL)
; z0 Q9 r, M. x d2 p) ] - {% u! F) w0 v) U% M1 K& }; B: C% ?
- HAL_DMA_Abort(huart->hdmarx);
# U, `. B/ P* ~, i1 ^. m, G - }
* D. w" Y% l7 M& y3 H: }) K - - _7 @/ } K% r8 o; i
- //UART_EndRxTransfer(huart);( E& x1 g ~2 h
- /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
3 V" s9 P4 A& q' O$ a - CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
/ Z6 {7 @& R0 g8 O; ~, U, h8 y - CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
; |. {1 Q. { r4 \8 ^3 O
6 E, K3 P' ]9 J* c4 N/ T- /* At end of Rx process, restore huart->RxState to Ready */
* L L" _1 S, W! Z& k - huart->RxState = HAL_UART_STATE_READY;3 m' t9 { W* a$ h1 ^( i
- }
. \7 s, W7 U9 W8 f- w - ( N2 K. H+ a$ R& d1 M
- return HAL_OK;. y7 [/ P9 X, M0 q
- }
; `3 ~5 D8 S( t8 P* K* l
复制代码
, ^0 D, G; L$ @: q8 F: G) Q串口空闲中断 `3 ^5 B$ N* a9 H& B+ X& B2 Y
9 @/ b5 H$ E- ?, \2 X
- /**2 `/ ?8 b9 K+ r: C# ~; T( D0 \- |/ D
- * @brief This function handles UART4 global interrupt.
6 r% d& o( w; J! ^& r, p - */
% f5 V: _- w# S - void USART2_IRQHandler(void)
& w, s) N# t& f0 D7 a - {8 i: K, d4 J- o) _% f6 m3 d* v% P
- uint32_t _len_dmarev;
% E2 z: ]) i( f2 ], T0 @ - uint32_t isrflags;
: G2 q& [! x( f! y' F; v/ M l - uint32_t cr1its;
/ {+ @7 d2 h' O- r- E" } - BaseType_t xHigherPriorityTaskWoken;0 g9 |/ m# O- ^' O
7 W; ^2 I" X$ Z+ k" M! r-
* w" D& D0 d+ T - HAL_UART_IRQHandler(&UART2_Handler);, n3 _4 a8 o4 ^" Z
7 `8 f& M: c9 C4 j- isrflags = READ_REG(UART2_Handler.Instance->ISR);
, b1 k& | D1 @3 b$ n - cr1its = READ_REG(UART2_Handler.Instance->CR1);
2 |! R) o! `5 c6 I9 h
; G1 B" K5 r! C0 N0 }5 Q- if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))
0 }1 J, Z: l2 ~7 B2 o - {
: l' T6 x8 X/ ]) j7 ]9 a7 y - __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);
+ h6 i2 H4 S E, x) O - 6 t5 v& V6 i+ K* |
- _len_dmarev = DMA_BUFFER_LENGTH - __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);
; D Z4 w1 @* l" J5 y/ k, z
& j: b3 m: M( V5 S) V7 f, c- if(_len_dmarev)
- R# A# Z" X& }; i$ E - {
|5 b, }+ Z0 Z - //停止DMA. U0 |- @+ v4 I4 q9 x
- HAL_UART_DMAStopRx(&UART2_Handler);
6 N' L, r2 O [4 \, G; o! Q - //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致" ~6 H8 Z; `: m: q0 I
- SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);7 N9 v% q& G! }4 Q4 |% t) Z, D
-
" `; M) F/ E" z/ T6 N7 n5 u - xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);) H7 l3 L8 @# M% T, l% U( j
-
/ k3 F. p- R* H* r# x - portYIELD_FROM_ISR(xHigherPriorityTaskWoken);8 _5 g. H: e D: ]7 g& }
- |3 Y5 B+ a) m. w$ F6 W! ?, A- HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);
. Q. @6 P2 \1 f$ C% p: O - __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);
" o; p7 d% \: h2 R& U6 ? - __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);
" b9 b! D9 r' y! [ - }
$ y: Q3 d1 k1 @: J/ d8 ^/ X9 @, z - else# l1 d: ]& c; F0 {! z# }
- {6 e2 G5 J8 d& \6 ]: c
- READ_REG(UART2_Handler.Instance->RDR);
' U- J8 P% n. s! g - __HAL_UART_CLEAR_OREFLAG(&UART2_Handler); K- `4 f4 ]" [9 S% f! _' [5 w( h
- }3 _( Q" v( T6 j; c+ L \
- + I; v% N7 O1 Y9 |* ^2 z. d
- }9 g4 `8 _( P4 V, H& ^* }) w
- # q4 A# Q5 `& j
- }; N7 S- N, z4 v( Y h& f* ?
复制代码
$ J* Z) Z& U8 [% U& W' M0 k4 E- k3 [+ Z发送函数; K& x% ]! @0 d3 @* q
2 [8 l3 y" V0 i: z; B0 L+ f- unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)
6 Y; [+ n: S4 E2 L4 A' I6 a - {
1 O7 u3 n8 h, y& W% q8 X! \ - UINT16 i;, d+ r+ x% s# L
- ) q& G5 E9 s+ z& j1 w6 m
- //拷贝数据到DMA buffer \6 d8 @) _6 W) b
- for(i = 0; i < len; i++). _) d$ s7 b/ s0 ?+ v
- {
; c) h. K+ T+ l8 i - dma_tx_buf<i> =</i> buffer;
, C S% K0 N! X# V8 R( [7 N5 L - }! E. j/ f6 y2 G4 V7 T" W6 \
- ( E( c2 e& o6 a1 Z! ~7 n4 k7 _
- //使发送RAM和cache一致
3 Q! R( k9 |& \* u) \- l( k, f - SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);( a# u( V8 ?( l4 k7 g3 A
- HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);
8 x/ U, x1 H/ A3 G! s1 \ - return 0;
复制代码 7 T# _2 J, k9 W* @5 \$ K
还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域
4 Y# V1 Q4 \+ `可使用下面的编译指令:% o; w* p* ]- z. ?9 H
- ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;
/ T! z. C2 L1 A4 X - ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
/ Q7 P" D+ C, f/ v. i' c7 V
复制代码
% `6 M7 H/ j1 O; Y+ M6 a: g! H6 C |