stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法
. w3 \8 V( @+ J/ j4 ~芯片型号:stm32h743/ r, n# `* K3 J. h
串口:USART2/ [5 o, X8 m, B [( ~# c3 r
代码生成:stm32CubeMX! {& Q/ b% ]& f1 e/ t
第一步:使用stm32CubeMX生成代码( O/ H8 ]; B0 m6 x& L: O
; i a* @, w& S
第二步:添加自己代码
! k% d) `- \0 |% w( F* G7 c( \. N! r& T9 o* e& t
1.发生空闲中断需要reset DMA重新开始接收数据! a8 P7 ~% I7 Z
3 E, d$ q+ T: C) _9 A. j
- HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
# R) q# [' U; j+ o% O: A - {' [; L" _9 P* y P! A
- /* Stop UART DMA Rx request if ongoing */
. b) U4 O; z6 |8 ~' U - if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&
5 e# z7 C: { L/ r& } - (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))* j* b$ k8 Q3 z3 G* R8 h& G
- {
' h9 T- s B; h( F' G - CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
X9 Y2 D" F3 A d - " ~8 e6 B( u1 E* k4 A% ] F# Y" K
- /* Abort the UART DMA Rx channel */
( p9 [3 X- @* t) P - if(huart->hdmarx != NULL) S! E# ~% W, Z7 r9 {4 A
- {: k, `* C' p0 u1 |' D% j r
- HAL_DMA_Abort(huart->hdmarx);' I9 ~" ^! J8 y+ ^: {/ g p
- }$ `4 u! L6 O4 ~8 M9 M$ G; s w1 v! h
- ' v" i% o+ T/ z( e$ j
- //UART_EndRxTransfer(huart);$ Q. c. S( F- C9 N& o3 O. [1 Q
- /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
, U$ n/ B* _5 W+ Q$ p - CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));7 u& @" r: H* ]8 ?
- CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);" u7 z* [, E8 R f! m
3 e+ y3 J& E* W+ H6 C5 _- W' x; F W% J$ v- /* At end of Rx process, restore huart->RxState to Ready */
: l( g; I% P3 w% M {" n+ [; f - huart->RxState = HAL_UART_STATE_READY;
7 U l9 d" b' D- `) m- Z# p4 H - }
i7 ^/ X4 q* U' u5 m - ' R) w5 n8 G) F' \1 q- |
- return HAL_OK;. y8 w) I$ Y5 a) ^
- }
' C; }. [- |3 j; Z: @, f% @: F
复制代码
( L- b, Q" f& s, r. ]; S串口空闲中断
, ~: P- R2 g0 F4 c, I
- o# b* g8 ?. Y+ J$ @" b7 v- /**% Z9 R A" P6 M; \3 g2 x
- * @brief This function handles UART4 global interrupt.5 s$ s1 E& Q& D
- */( t7 k8 g* v9 X6 P- t- k
- void USART2_IRQHandler(void)
. x% c0 L8 l. M6 Q - {
% ?! v" T* k6 M) r5 P - uint32_t _len_dmarev;
0 }5 c3 ~$ p% `/ k" K - uint32_t isrflags;( S7 V" u( v2 q. s+ s# |/ M& J4 C
- uint32_t cr1its;
' K: l2 F, e' ?% _' z - BaseType_t xHigherPriorityTaskWoken;; _, G+ K* \. s* P) h1 C# F6 Q
/ s& X/ o. q# J) N- k* c5 |$ U; I-
% Z" f& Z7 n( K5 U, I7 l6 ? - HAL_UART_IRQHandler(&UART2_Handler);
( O4 `- W+ g: } - / V& i$ s: J7 [- z7 h. o# q
- isrflags = READ_REG(UART2_Handler.Instance->ISR);
4 {( b- b6 _- C- d: g - cr1its = READ_REG(UART2_Handler.Instance->CR1);
6 V6 i+ N8 i) ~* B. e( H/ X0 Y
+ o' p+ s2 k6 B; S( \ u5 J- if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))# o# ^. Y7 \4 A# z I0 g( R5 i
- {
) V% I" Y! y5 n5 \2 U3 s8 l - __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);
6 ^ a+ D0 V. i1 T9 @
, |( S$ m& A9 S, @* @# p {/ i0 N- _len_dmarev = DMA_BUFFER_LENGTH - __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);
! }# e7 Y; J0 S9 ?$ O. j - 3 r. A$ @. G& |) V2 v9 v
- if(_len_dmarev)7 H# a/ m3 N* Y6 Y- E
- {
) W Q8 s7 N g8 m6 i. i( K - //停止DMA* P" c" T4 h* A E, Q
- HAL_UART_DMAStopRx(&UART2_Handler);% w; B" {1 o# G0 ` K# W
- //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致8 N2 m; p5 o8 r5 x# {' B1 l1 S
- SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);
9 H+ m2 _/ v6 F6 Q; q8 X6 t; v/ Y - ! G' ^+ o' E# G% D; m: \; L
- xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);
6 v, h4 K$ @4 P2 O3 v/ _ -
4 } w, w' R( r% }6 d, p: a: w4 ^ - portYIELD_FROM_ISR(xHigherPriorityTaskWoken);/ B/ I s4 a9 D2 G! S. D* U' d+ k0 f
; u' G; \: {- p" o& m- HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);
6 R1 j$ m) Y0 x% G+ A( H3 X/ P9 L - __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);
! q* x" r% h+ s' i3 v) O - __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);' d' a& V% \6 Z' E s+ q
- }
7 P& _) A/ F! R0 K% E7 F - else; m3 B8 D* v: @7 I U
- {; U- e8 V5 ]5 F- m
- READ_REG(UART2_Handler.Instance->RDR);
( T5 P- D3 U- |3 X4 M# {) t- P) p' w - __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);
9 l# \1 z; Z" l) y - }
* h; M D( I' g I, V% d3 o
( k# y. p. O9 p9 @5 }- }, I, f( h X; D1 Q, m0 J
1 B$ S. O q3 c7 o3 w- }
* A+ `" P; i! F2 ]* Z% D5 s @
复制代码
0 J" k9 g$ ^/ Q% i$ Z! J! |) l1 p发送函数" a5 K+ W) J s7 u1 D
5 I X' u0 V5 U
- unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)
* e Z0 B7 [( B' G h, E - {: c$ t- X( r( Q$ D
- UINT16 i;
( M4 w$ w- k6 v/ @3 N
/ _' |5 g3 F, T' ^1 Q) k+ t3 O- //拷贝数据到DMA buffer
8 h8 {# I, m+ m& p/ D. ]0 O - for(i = 0; i < len; i++)
6 V. o; r/ ?3 | t7 V- B' q - {
7 E! s. s+ O& n) s0 \1 g* B" C - dma_tx_buf<i> =</i> buffer; % R- ]% b$ f; @7 L5 X; b) S
- }
, S" i2 l: v9 }) K- w e1 E2 l; h - / D9 \ f. k' j- g5 o2 b
- //使发送RAM和cache一致! O1 m7 i" D. E7 E% X
- SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);+ p' E: Z ?, o% \, I' G' T e
- HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);- ^& E- p; X+ P! ^; ^
- return 0;
复制代码 8 n) N/ O3 r6 ^
还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域
' u! C7 {- J9 z; c; v1 |* {4 |可使用下面的编译指令:
. G0 n5 O" t9 `4 | y; x& v7 c' B- ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;# {! Z4 O9 B/ ^- v1 C( l
- ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
' W2 H. O1 y$ b1 j R: B0 z+ G
复制代码 $ E3 \: K+ C9 N5 K( ^6 r
|