stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法
4 n$ ] h2 j+ F4 \& `) [0 O! o芯片型号:stm32h7430 W6 A- J& [+ P3 w- k
串口:USART2/ Q+ H9 M3 f3 r/ A& M
代码生成:stm32CubeMX. H9 G# I0 W+ {; N7 t9 A' q0 ~
第一步:使用stm32CubeMX生成代码
2 \' w. q1 i5 t1 R$ b* P2 ~/ l
& t1 ]: J8 c+ z: T第二步:添加自己代码! P1 @) v+ C; W H
+ D+ G( r4 n- W% Q1.发生空闲中断需要reset DMA重新开始接收数据/ K: q/ H! `# ]
3 A! n3 d; n1 @0 U8 D A- HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)) c7 m0 F' ?7 v9 [4 S
- {
/ L7 i x0 a- }4 I7 I - /* Stop UART DMA Rx request if ongoing */
! E$ o& w3 d+ b. q - if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&9 \; J O* [- s8 k" L
- (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
) u# ~. _% y) A% L - {: F$ s# C) c6 s" Q; |
- CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
. e8 v8 w% P, b: |/ ` - " M7 Z4 m4 O8 D: e( Q% b
- /* Abort the UART DMA Rx channel */
& y/ Y8 h3 N0 e$ R4 ]4 b3 k - if(huart->hdmarx != NULL)
. L- Q! o+ k5 i - {, d3 Y' Z9 S. X8 I
- HAL_DMA_Abort(huart->hdmarx);
, ^6 _% w7 B: M; Y# A - }- f9 O; V0 q9 Y' e
- " K# `& ^# |- z3 ^1 X. J, N8 H
- //UART_EndRxTransfer(huart);
# C# @0 ?' [- F7 E* I6 Q/ J2 C6 Y - /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */* ]: e9 J2 h8 {4 g, ]
- CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE)); E) o5 @+ ]# Z5 _
- CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/ N: Y* k9 a! P+ Q! Y- y - 9 H- T. \3 {- j# |
- /* At end of Rx process, restore huart->RxState to Ready */$ w- E# q8 S3 l6 x, c% f& w
- huart->RxState = HAL_UART_STATE_READY;4 {1 T7 v$ B9 M* q n1 u
- }: D% U5 ^; b9 n. t
- & S+ l( S6 W- `
- return HAL_OK;
2 z/ ]: J3 [' I7 ^: H0 b. D8 q - }
6 E. O( B; M5 L9 Q# P: A
复制代码 . H& P+ w- C! |6 P2 X
串口空闲中断9 X q% H6 k+ w% D) d9 |
" [/ h9 m8 F5 s) S `; O" {& P
- /**3 [9 ]% w3 a; N% o- u; g4 |0 {
- * @brief This function handles UART4 global interrupt.* D3 I8 Y; G% z! G3 A
- */
' n( T9 t' g6 O& O5 u% L - void USART2_IRQHandler(void)
! ~# F; L; ?+ `4 r - {( r J" ^* w1 r' l
- uint32_t _len_dmarev;
9 B. i: U+ H: {2 H+ I - uint32_t isrflags;
0 ?$ ^! w4 ]8 @3 z2 {: \ - uint32_t cr1its;
2 _( ?, w; I( [) | - BaseType_t xHigherPriorityTaskWoken;
* {% [' j& ?. G5 i8 F8 `( x! J - . }3 x6 [: j( m- h9 Y8 j0 f* W+ _
- % s) s0 \) f/ A$ c% g* A" [
- HAL_UART_IRQHandler(&UART2_Handler);
! o5 I( N7 Q* e" M* t; J& Y% ^
- ` g. V, d4 Z5 K* s- isrflags = READ_REG(UART2_Handler.Instance->ISR);
5 Y: Q H3 s3 j+ G! b$ e - cr1its = READ_REG(UART2_Handler.Instance->CR1);
3 v) ?" l" F3 _. w - : n0 _+ H, E5 s7 o) T8 R1 E6 H
- if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))) t5 V- [4 Z/ ]; L
- {# E; B- i- y3 L2 v3 N5 z
- __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler);
/ T c h8 n2 F - $ N9 }+ a& m; C2 c/ P P/ R* J& J
- _len_dmarev = DMA_BUFFER_LENGTH - __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx);
" R) k$ i9 W$ J Q6 D Q7 V - 4 l& ~2 i( S2 |) y8 s
- if(_len_dmarev). j9 d! p8 ?# Z1 y7 C
- {/ p- Z- W5 F ` ]/ S2 g- R+ H
- //停止DMA
: ^# a! i! N, q- a - HAL_UART_DMAStopRx(&UART2_Handler);
2 p) X# K# w4 H* E5 R - //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致! o1 a/ G( Q! a* u3 c
- SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH);+ B$ m$ a2 }& o7 M
- , i) C4 R0 k% E, h0 d7 S
- xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken);9 l6 d; p9 J9 }
-
+ P7 l: f& \- Y% ~ - portYIELD_FROM_ISR(xHigherPriorityTaskWoken);* j& H2 f8 p: {9 B, Y X
; }5 o/ V0 g B6 d+ Y9 [( B" o9 J* C- HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH);& d: J; J; ]- }/ R2 u/ s7 k8 p
- __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR);* ^) V8 m9 [) L8 l% v$ e
- __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE);
% ^$ Q. e M8 l4 M - }; h) W1 a' Q0 F3 z/ o$ Z
- else& `5 V2 M8 I( M) `8 X7 l3 `, M$ ^
- {
' p& h5 y" ^* w) [1 A W' @3 m - READ_REG(UART2_Handler.Instance->RDR);
! s, s' @, ^' K2 m - __HAL_UART_CLEAR_OREFLAG(&UART2_Handler);4 o( R' ~9 W6 ]& N" h: b
- }6 H* A) A- L ] G* [0 f; O2 q
1 U& g9 ?8 s: F( o- H1 o- }
) a+ G3 O t6 J/ Q' a) ?# j - " Q% e0 _& `* S1 i' G: P
- }
' S1 @0 ~5 V, `
复制代码
0 ?; T0 b: A5 e K发送函数6 z7 s' }) p' {: U9 C
& {8 T3 {8 w5 ~1 b- unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len)+ X- I6 `+ f8 ?4 u& @
- {
2 h `5 @. v! W( m: ? - UINT16 i;) n# s" y0 k2 h4 F- J' B
6 t/ _4 \/ J l* x l) b; W- //拷贝数据到DMA buffer
6 T6 }2 {# o; Z% j2 t, @ - for(i = 0; i < len; i++)
, u* l% m4 T% V" F+ L- ]( n - {
2 N# e: k/ m! C7 B8 n2 O3 o" U - dma_tx_buf<i> =</i> buffer;
& ` b) t3 E3 t- `) K - }: I" }2 Y+ U- e% Z- h7 v
- : J8 f' e. l1 G7 E5 U2 j7 C
- //使发送RAM和cache一致5 c' H( j5 Z& a# U
- SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH);% E2 S. U* i2 X) c2 n% S
- HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len);
( T( X5 I, E2 s7 z! X - return 0;
复制代码
, ~) q9 H U! C- m% T还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域& X2 V2 ]) D5 X' x+ E
可使用下面的编译指令:
: C1 d6 a% d. N: G9 b$ O% l# T$ T- ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ;
+ J0 C2 s: O i2 b" d$ u; a - ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
* o$ G! C1 q0 K4 A9 S% H1 ^( a
复制代码
& Y& d$ A/ {7 _0 m |