stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法- R) Y# y2 J: h) M
芯片型号:stm32h743
1 p3 V8 w/ I' n% w# t# V串口:USART2
* E. N' V/ t2 ~代码生成:stm32CubeMX
' X- r X8 w5 U第一步:使用stm32CubeMX生成代码
# f2 T! o% B& c8 P; u/ ~% [* k& T) j4 H, a/ [. q
第二步:添加自己代码
; O: `4 I# `4 M6 t: `4 A9 t. _5 T5 u% o8 h, r
1.发生空闲中断需要reset DMA重新开始接收数据
3 K% A6 Y3 W" U' J! a1 D( {$ t& Y! X3 a; f0 M* r6 D1 Y
- HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
5 [8 J/ f$ R) E6 u* ] - {
" r3 ~! _" g" Q - /* Stop UART DMA Rx request if ongoing */
0 H$ B7 E+ W3 q, B. W5 L5 m9 E - if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&
$ [" Q k% X% ` - (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))$ C' ^* r* m) n8 a# X3 |
- {
) Z8 L9 Y# d; n) |! g& ~2 E2 P* X - CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);+ V& s4 y3 k' Z J' b8 e; G% L
- $ x7 h( ]3 E3 ^4 g0 o4 T: b' X
- /* Abort the UART DMA Rx channel *// e/ X, A7 u# C. o
- if(huart->hdmarx != NULL)) C. S6 k) Y* C& t4 V: G9 Y. r
- {' |( J) q* S, r' o0 B
- HAL_DMA_Abort(huart->hdmarx);
$ p @0 ]* T6 I1 E. i7 p) A2 S5 Q - }
) |. C: J) R* C0 D7 F2 G7 R
4 W) r! Q0 Z* N- //UART_EndRxTransfer(huart);# P+ Y. ^6 L) m: L7 \
- /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */0 x4 ]& D# T( r2 l: M
- CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));- o( |( c# C. k' V, }
- CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);8 N& I3 ]) V. Y
- ; ^) j! H9 Y* {6 g
- /* At end of Rx process, restore huart->RxState to Ready */
8 v" }* N: k4 a0 l/ R( { - huart->RxState = HAL_UART_STATE_READY;# o" w* G2 g1 u. B
- }
' o/ {+ p6 a: d1 ~& C8 v
2 U3 h Q2 z9 q* e6 a- return HAL_OK;
+ d+ i0 l; n$ B6 h - }
5 Q: ^2 y' p$ Y& k/ R
复制代码 9 t7 h5 ~$ P# @3 i5 S8 B3 }
串口空闲中断
! X: X3 y8 H3 `6 N; p; K- S( s+ W/ C( G o: h
- /*** r' p& O! f4 l: ~: g( C% ?" x" N& V
- * @brief This function handles UART4 global interrupt.% {" O" P+ p% \. c
- */9 [4 Q% a" a: x8 X. n- W' R: h
- void USART2_IRQHandler(void)2 f. g" e p8 W5 t/ J; y; D
- {7 q8 ]9 l% D f- d- j, V% J
- uint32_t _len_dmarev;
+ \$ U* m5 W C0 j$ q$ Y0 n/ _/ ~ - uint32_t isrflags;9 t: }4 R4 _4 m; W' M
- uint32_t cr1its;
2 \0 L9 l4 z' m* e( H/ z7 C - BaseType_t xHigherPriorityTaskWoken;
) {" l+ n2 C$ c. E& X$ ?
a3 g( z2 I* G8 v0 X1 W+ ~- : J5 K( N& z- Z+ x0 K5 ~, l" ?+ y
- HAL_UART_IRQHandler(&UART2_Handler);- D' L' C3 ~4 N! e6 P
- " |$ I0 \4 p4 l3 p& g+ }$ x* v' G
- isrflags = READ_REG(UART2_Handler.Instance->ISR);: p b! O: e- }4 p- f+ T1 z5 F- m I
- cr1its = READ_REG(UART2_Handler.Instance->CR1);
$ |2 ?& t3 R! U - ! c' N- ~, c4 E1 Q+ R# ?" p" O
- if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))
% w8 \% S0 g% d* X% F - {
0 k/ D' ^5 I+ Q; d: w4 i - __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);: j2 ]9 O F( N0 m
" u6 V4 t$ ^2 D3 [. }- _len_dmarev = DMA_BUFFER_LENGTH - __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);" T/ v. G8 `+ C# K1 _ A
; D9 t) c# x' y$ t3 |/ t- if(_len_dmarev)% _2 k/ U* s- ]' H3 f
- {; R& [3 H* p9 c) a
- //停止DMA' F0 y4 w3 _. b4 M
- HAL_UART_DMAStopRx(&UART2_Handler);! y, G; b, s& q4 f! Z$ M/ T
- //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致! S1 K8 ~' e5 h6 E7 Q+ n
- SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);
; v8 s' S* d8 U, z - % f" E3 } g4 Z* U& V3 |8 ^
- xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);2 e. m) @$ y7 Z! Q! o" d8 x) L
-
/ l6 q1 ^. @2 p5 { - portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
* [# o4 x- W4 D: @. c: N% _ - 7 f% j2 I6 \) P" ?$ Y+ y7 @3 C- R
- HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);
1 R! H% T0 W s0 P/ R% r - __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);
$ p- w/ j4 B) p - __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);$ j- m# b9 H9 z" o( D
- }
$ @* I: ]3 Z$ a) R3 }5 X - else6 D( r1 X7 m$ \' c2 D
- {
$ w+ B, S9 {' D - READ_REG(UART2_Handler.Instance->RDR);
8 k7 ^# K9 f( K& ]- q( I - __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);6 H( v+ x7 p9 s# T R7 \
- }% }( S: o2 ~. p8 X
- & @% E2 ^* R* o& t, L5 R
- }
+ t/ z5 y. n' x( d - % f3 P& l, {9 y& o! _/ Q5 J- U+ b
- }
0 Q; \- a0 W' w1 o* [! {
复制代码 & Y! O, j: b( R# @6 U6 G
发送函数0 Q" O& O$ J2 M/ p
( b6 g7 n: w; a% U4 L. {& H- unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)
+ b' B3 k; {, X" k+ U: T3 o, n3 z0 f - {
& u# L2 B0 }( m5 w( J6 Q( G0 M - UINT16 i;! F7 Z% \6 Q `) n5 M2 F1 ?8 @, y
- $ k5 g& R g: h/ Y* m
- //拷贝数据到DMA buffer
3 l" K6 s3 P8 t - for(i = 0; i < len; i++)3 D/ ?6 F+ _- } ^; d) W t
- {. W( {* T7 j# u: g9 n
- dma_tx_buf<i> =</i> buffer; / i' {- G% M) i
- }
5 S2 B) a. A1 L0 u6 U - , `6 i* L+ k2 C' F( `- \! s. a
- //使发送RAM和cache一致
/ Y7 _, x/ [ d3 M - SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);
& N) F5 O* l' {6 E8 T: m1 s - HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);
* [, s9 O+ u& e# \. z - return 0;
复制代码 % ?* N; `! K& ]9 L( V# x) j5 `
还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域
5 Y3 g* ~: W. k* W3 H可使用下面的编译指令:* \1 D- [) K6 M3 c, {
- ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;
- [! R* b7 L2 l1 c/ L - ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
* O0 @( w. _/ ?' D1 W" w( U
复制代码
5 K- Y9 f" G: y2 @' t |