stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法6 h; o( y5 Y1 k+ a* A+ U
芯片型号:stm32h7432 U5 C- \3 L) w D0 t( O6 W
串口:USART2* j* u! G0 u8 O, |& Z, U
代码生成:stm32CubeMX. C+ C/ w! j }2 \% U8 b: W5 Y7 C7 f' x
第一步:使用stm32CubeMX生成代码0 e. I8 q; g" o1 I! I) T$ E5 n: W
8 P B9 m! o; D+ o
第二步:添加自己代码% u" O% A; C* T2 P, H; S7 Z
5 i% n; G+ @5 ]5 X/ W+ P
1.发生空闲中断需要reset DMA重新开始接收数据
3 v' \, y; O9 T2 j: O2 J
" d7 O- |3 n4 S5 O7 Z# }- HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
2 O& u. b) T& M- V4 o - {. b; [$ I' B9 ]) G @
- /* Stop UART DMA Rx request if ongoing */6 J5 n# @2 f! R0 o6 ?6 q0 x4 g- d& c
- if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&
& H$ c4 H* s3 P" x/ u - (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
* u* C- ]( F* c2 p, Q - {
( \* t- d( ^; ^7 j" a( g4 U" A$ ` - CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);8 C6 t, c& e- o
2 Q6 Z) f6 Z' ]4 v, L3 _# ]6 y- /* Abort the UART DMA Rx channel */
7 _+ P8 i! g- J0 m* j3 v% |( i& T/ H - if(huart->hdmarx != NULL)
5 p" s& T0 f0 H4 x2 R - {" J8 J4 _- O0 j2 g6 X
- HAL_DMA_Abort(huart->hdmarx);& W4 k* y' F. M1 P$ V1 S+ z T
- }( ]4 o5 X7 F) B! m8 h. S7 b
- ' r0 \5 }4 h0 ?7 o; k
- //UART_EndRxTransfer(huart);
. G% w# @6 i- p& e% u/ z - /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
: E% D7 _2 n0 d3 A: V) Z% G& R) O - CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE)); i% U( O3 v% Z" o! O: B
- CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
; b7 T+ ~0 H! M% ]8 v: h" D" b
9 m0 E) k" L* U3 j- /* At end of Rx process, restore huart->RxState to Ready */5 V1 n! ~0 \- y$ \
- huart->RxState = HAL_UART_STATE_READY;
( k: n5 H* M: l - }6 t3 I0 S6 ?. ?& D
6 F) V5 T# N; |5 P- return HAL_OK;. B/ x9 O. E: h
- }
$ j0 ?+ H5 T! b8 o
复制代码 ' k8 _6 y) H4 a% t. G! D% K$ p
串口空闲中断% M0 K# Y) f* D) b% A3 q
/ c# _2 w, m1 d$ j9 E% |6 f* k7 [- /**8 R; F* \" B* d: r
- * @brief This function handles UART4 global interrupt.! G8 b" Y9 O) \. L' T" Q
- */
7 c9 K/ u6 D& ~+ @+ r - void USART2_IRQHandler(void); a i% o# ?' W! B* C
- {$ n" l+ V$ Y& O3 k3 @
- uint32_t _len_dmarev;. C8 e4 ?% [% n, q
- uint32_t isrflags;
: V. K8 e! G4 l& `! f4 q - uint32_t cr1its;( H0 q8 N' z. m0 I/ Z1 \) m
- BaseType_t xHigherPriorityTaskWoken;
1 d' z( Z0 D& G% U0 G2 k' i8 R - * \$ d" \; K% I$ ~9 U! M- _
-
& L. g* b) a- \. A - HAL_UART_IRQHandler(&UART2_Handler);1 T, c) i" a5 i" k* c9 D
- * y w u$ I0 E6 @' t) s8 c
- isrflags = READ_REG(UART2_Handler.Instance->ISR);
$ a6 T# {$ K+ `# ~; t) W' G - cr1its = READ_REG(UART2_Handler.Instance->CR1);( D4 t8 N; R3 p) y" r
- ) ~$ k" _+ ~; T& D
- if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))
7 [7 Y9 [+ i- q - {. I) C+ I- i2 z% U8 T: x6 W
- __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);
. A* n2 A! z' Z7 N - ! r4 P# K, E: y
- _len_dmarev = DMA_BUFFER_LENGTH - __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);
$ `2 z- C5 B( F% H0 S- x# T - ' C7 T- b/ H6 q: e
- if(_len_dmarev)
* p6 E+ h% Q- I8 k5 ^ - {$ W; G8 x( j. g9 q
- //停止DMA
/ q/ t$ q/ W* A- J& O - HAL_UART_DMAStopRx(&UART2_Handler);
9 I, B# U$ C/ K i3 A" S - //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致
2 y2 ?7 y; t: L' U5 Y5 [ - SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);, P a' ]3 f" |7 @, C- g
- 3 w0 x+ G7 h0 a$ g5 _
- xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);3 C5 x2 N: ?" G( ~8 p
-
/ o: o* G0 ?( o3 t( H - portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
8 b& y* p9 [& A( b0 A; X
3 l# L0 W) O8 k: d! ^' w+ }0 W5 a- HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);
8 [2 {, w0 f4 E/ |. A8 ` - __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);& I9 t3 U9 y' x+ l* n7 f f2 b
- __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);- [* Z& K" M! L2 c; }& T( Y9 T
- }1 @9 K( {+ m' {; s( g, W: R# z
- else; e# _/ ^ F, T5 ~7 e8 j1 g8 \& E
- {
* g1 k, k9 E0 ^' e - READ_REG(UART2_Handler.Instance->RDR);
' k) Z U- z% E9 `: w - __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);+ L4 A8 N: M9 {, X9 e
- }! i+ f9 b' u6 X5 t# K1 w/ T
- 3 @6 m( l l1 h
- }
) W6 P" _" l/ T- ?5 O9 x Z( x
1 c3 e/ ]) J8 r5 a- }
3 J: X% Z6 P& M
复制代码 0 `8 g" D) r( |
发送函数
0 P0 W! n! P" N- G$ f! Y' L! W G+ [' F9 B
- unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len); [, T$ s. Q3 Z7 I7 S4 M
- {
/ V. ^4 Y T* y1 Z9 y }8 M k - UINT16 i;
2 S! d. q& u u3 X5 S. ?! C- E! ] - 0 G8 V( u n* x/ F0 W3 P, s. J% n
- //拷贝数据到DMA buffer) j! Y# @0 W1 h0 u4 t
- for(i = 0; i < len; i++)
! V2 b- y0 B+ m+ U/ D9 h+ V - {
S% Q4 J3 y9 C - dma_tx_buf<i> =</i> buffer; 8 j( Q4 n9 J: Y! ~
- }
: O7 c4 c) w# }/ k( q% e* }$ O - ; w- O0 P8 m5 y+ ^1 P& d
- //使发送RAM和cache一致4 U5 n- s# S! L# g
- SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);
5 ]8 B7 O4 c6 a7 _ - HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);
4 r1 F% H! c6 T& O6 N3 } - return 0;
复制代码
7 G$ w( r! } b- j/ d% a还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域
* V8 q4 k: o: E, ^7 {! b2 O" Z8 v可使用下面的编译指令:/ S5 ]; @4 {& Q& b, Y
- ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;4 R0 ?4 u8 i5 ` ~! t
- ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
! z& O! n) ^1 {* ?& H! M/ h
复制代码
8 Y' L2 c& m- X& k8 D |