stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法
8 @+ d* L9 E6 L- x. _0 T芯片型号:stm32h743! t( Y* [3 N& F8 v
串口:USART2
- ^4 y- W# x. O' }% s0 U6 f2 ~代码生成:stm32CubeMX
' M; Y ]! J3 |/ }第一步:使用stm32CubeMX生成代码/ e) Y1 U1 s, d& ?: I1 v
2 E* m e2 n/ t# M+ s5 c9 C
第二步:添加自己代码
, P0 Q' t4 h4 F
2 T d! i, F; z& L5 a# `1.发生空闲中断需要reset DMA重新开始接收数据
6 ^8 y7 V5 b! {" m) _$ e; z! T$ I
- HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
# v! |: X! s, v: X. M - {
/ j' T" n" j" W - /* Stop UART DMA Rx request if ongoing */
% g! l# c% d. v% [' [. k% t7 Y - if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&9 k$ v- v! M6 D- N
- (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))- ?& n; L" m0 }+ }! w7 h
- {
1 G! u$ i/ L: Y* O3 b6 j* z - CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);' N) h% F2 H- a' y: T3 B
% _8 }# { ^: ]1 n- /* Abort the UART DMA Rx channel */
$ c6 K" |$ ~4 |0 f( R - if(huart->hdmarx != NULL)- R% \" v. H' X& g$ f. v2 `5 m
- {
3 Q2 _2 U! K' j8 @2 r' m9 }/ t9 D - HAL_DMA_Abort(huart->hdmarx);
% |% a" ~$ a5 D3 B5 P! g - }4 {- t8 h2 `, K2 {( v
- * g$ o/ l: _6 V/ O7 m( @
- //UART_EndRxTransfer(huart);7 H+ N0 f2 X5 E1 U
- /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
0 n0 \7 J: i. H" l/ o - CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
& I/ C0 t" W* g* n - CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
( a5 u ?2 q" X/ _5 x3 Y
; _- {* V( F6 B+ Z2 n) t- /* At end of Rx process, restore huart->RxState to Ready */3 @% q" \* Z& o: w) l
- huart->RxState = HAL_UART_STATE_READY;9 T8 I0 A) d O
- }# ~! M* X+ x6 j
) p! ] k+ i, x- return HAL_OK;2 }: L6 o- a* O3 m
- } b6 `# R8 Z5 M2 j: k' H
复制代码 5 N! v3 n0 q/ R8 P: V
串口空闲中断6 ~. P1 J4 q/ V& C
, U$ n' ~+ ?; r- /**- C1 Q5 @' N# |& h S) f
- * @brief This function handles UART4 global interrupt., s* {$ v" p2 {) D- n: x
- */& t% X5 w- _9 b0 f
- void USART2_IRQHandler(void)
2 Q2 k, N0 M8 Z4 Z! G/ E. w P" N; S - {
% k1 C$ n- e( b% a2 v. _ - uint32_t _len_dmarev;
4 ]& ^- y3 K& |$ b - uint32_t isrflags;
" K5 l0 U0 O( q! A- `! t* U - uint32_t cr1its;
: j% b: ~; O8 [ - BaseType_t xHigherPriorityTaskWoken;! [5 r8 M" O3 t4 Y- w4 |+ O2 }
% x5 z) ^: @" H U3 t- ( V$ [/ a. A) Q: i7 g
- HAL_UART_IRQHandler(&UART2_Handler);
# w! j2 Y7 S5 Z; W& J" t/ ? - " c; t3 h; T& r6 x
- isrflags = READ_REG(UART2_Handler.Instance->ISR); U2 G; V! b& ?7 h
- cr1its = READ_REG(UART2_Handler.Instance->CR1);, M. i" ]/ o) y0 X- v- m- R3 w
- ) {/ A0 i M( u" y$ g5 W* v# c
- if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))' w y8 D; p6 ]! s
- {
8 a( A3 t% W7 q8 s2 d - __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);: J0 u0 ?; [8 d/ \6 R+ \7 n" [5 h
* B* `; c3 `) m E- _len_dmarev = DMA_BUFFER_LENGTH - __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);7 R7 N. [$ j' @$ h$ A; X6 B2 d
3 H6 K1 Y$ }! L. o! M4 n1 m- if(_len_dmarev): b* x! P$ }- O% q) D, Y4 o- s O
- {
% ~7 D9 f: ^. q0 J - //停止DMA
' x2 w- V9 N; s/ J8 E - HAL_UART_DMAStopRx(&UART2_Handler);
; g$ c* h9 M3 Y; D! U2 ?+ n2 y - //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致
$ C: i. f* d% t. F - SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);& ^# w: B) X; T. ]1 A* K" W
- + w6 x Q5 Y. V: X" L, b% h, ^
- xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);
+ ?' E; B' m3 R. o# {8 w2 [ -
" _0 z7 _ A* S' U5 A - portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
0 j, `6 `! P! l; r7 ], g6 W* ^, a
' u% m) f- P' I; D- HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);
" A: J1 g, w1 q - __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);
: p, \1 S* L9 \' B* U: O - __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);
' k, g( v' ? ]" G! s6 M V - }
/ T4 @5 d6 L9 e - else
1 M0 |) {4 G) i( w3 w1 ? - {+ d: W; E9 |; r/ P7 A1 }0 N. @
- READ_REG(UART2_Handler.Instance->RDR);
5 G( p* u4 j C# \$ Q8 ]5 l - __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);) L1 }6 c$ Y. T. ?+ M% T
- }
# S9 ]- Q& q& h9 s/ s" @: ~
- {3 x6 Z8 p* K- }
: j4 a( S% n$ M5 R0 S. S2 x4 D - ; N" d# c3 \! k8 G* v O- \
- }- C2 a- E3 k4 E8 C8 y: q
复制代码
6 [, O2 n- ]) W2 E, w发送函数
. r" @$ R7 s2 Q2 Q+ W C4 g) V
- v+ V# H8 l+ z. P- unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)( { V$ E7 ~( _! i/ V; E
- {1 A7 p$ i" Z5 p3 I! s
- UINT16 i;% R& _5 G2 M/ Z" ^
2 t( z/ Z6 I9 g6 T" S! K- //拷贝数据到DMA buffer
: C' I2 m; B+ M - for(i = 0; i < len; i++)
, n8 Y3 _. S4 G9 G! P& \$ p; B# Z - {1 L5 e2 l3 w' ^: E
- dma_tx_buf<i> =</i> buffer; - m, E$ |+ K! t% |1 q. U! I
- }5 j: F, X: i% ^9 j' g1 ^
- & C7 H4 I0 O) \# f( `8 z: P+ H
- //使发送RAM和cache一致. {0 V9 B: v, H# B' n" |
- SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);
! _" [0 S9 ~5 x. O7 I0 ] - HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);/ K* u& k) `2 d3 D8 E! W6 g
- return 0;
复制代码
, T8 H' x- o; k7 |+ h% b# ?还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域
; l& ?- U1 y" ~" q$ v1 h可使用下面的编译指令:
& d6 R# m: v9 l: h, r9 C8 H5 Q- ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;
4 P0 F: i1 q9 Y* Q - ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);* z6 f* b8 y& p+ H& _$ o7 Z3 {
复制代码
; L9 A0 r9 m, L3 ^5 j |