|
个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑。# z2 G2 b8 ~ m0 G9 T& n 不管什么芯片,当我们遇到问题时,通过查阅datasheet或上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道( 我就是用有道划的)C语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。! V+ ^" D& O) I 程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。 鄙人浅见,请大家不吝赐教。 进入正题:UART以DMA方式接收和发送的函数调用顺序: 循环模式接收:HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)==》DMA1_Channelx_IRQHandler(void)==》HAL_DMA_IRQHandler(&hdma_usartx_rx)==》UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma)==》HAL_UART_RxCpltCallback(huart) 当然这当中还会调用传输 Half 中断,这里就不讨论了。 % r% w. c! I" U5 U( ?" N/ r 正常模式发送:HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)==》DMA1_Channelx_IRQHandler(void)==》HAL_DMA_IRQHandler(&hdma_usartx_tx)==》UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)==》USART3_IRQHandler(void)==》HAL_UART_IRQHandler(&huart3)==》UART_EndTransmit_IT(huart)==》HAL_UART_RxCpltCallback(huart)7 H* g9 U. i% Q; P$ v/ e2 V8 P 这里只分析 HAL_UART_Receive_DMA 的源码,其它的大家自己分析:5 }* m8 B* `& K& Q HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)1 {# R' I3 q4 P; ` UART以DMA方式接收指定长度数据到指定缓冲区; M1 h$ S, e: m' R: b$ v9 f3 j* D# I {; P" F# Q* z, k/ u% o uint32_t *tmp;2 S5 w% m, E4 b4 m4 \! e5 q' v / N* X0 j5 f+ n /* Check that a Rx process is not already ongoing */ if(huart->RxState == HAL_UART_STATE_READY) 检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY。其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。# C6 L& H/ s/ R# _9 n8 K { if((pData == NULL) || (Size == 0U)) { return HAL_ERROR; }# X8 w2 e" W9 b5 c4 L$ T /* Process Locked */1 I+ e4 h& z; {3 l3 n; w, K __HAL_LOCK(huart); & D8 o" f9 H; ^3 o2 h6 G huart->pRxBuffPtr = pData; huart->RxXferSize = Size;4 o! s& n) }$ G8 d8 J 5 x# D, b0 O% C' N0 p3 m; A! F huart->ErrorCode = HAL_UART_ERROR_NONE;, v( I# z( q6 _6 G. E huart->RxState = HAL_UART_STATE_BUSY_RX;/ U1 _9 W# B7 }$ Y' Z 3 D% C. |7 u% o% r. ] /* Set the UART DMA transfer complete callback */ huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; 设置DMA传输完成的回调函数。当DMA以循环方式传输时会调用UART接收完成中断的回调函数;以Normal方式传输时会关闭UART的DMA通道,并使能UART传输完成中断,触发UART传输完成中断,设置huart->RxState为READY,并调用4 z- U; T9 L; ~- j UART接收完成中断的回调函数。所以,不管DMA按循环或正常模式传输,到最后都会调用UART接收完成中断的回调函数 /* Set the UART DMA Half transfer complete callback */ \# o" y( o+ C0 v4 ] huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt; ( r: t# [% H6 R& `: Y6 }" M }( R' d; G /* Set the DMA error callback */( X) `) s7 g# U+ C0 ^9 o8 M huart->hdmarx->XferErrorCallback = UART_DMAError;, G7 X8 J# |1 G* P: i/ _ /* Set the DMA abort callback *// n( t+ d+ j- ?; \& O- h. R huart->hdmarx->XferAbortCallback = NULL; 6 m' K! k. g8 E$ q3 T3 M /* Enable the DMA channel */ tmp = (uint32_t*)&pData;2 `+ Z. [6 b' i! _$ j9 H HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);以中断方式打开DMA传输。所以CubeMx中DMA中断默认是打开的切不可更改 /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */+ L6 L9 O% M5 o! y; f$ p* y, } __HAL_UART_CLEAR_OREFLAG(huart); /* Process Unlocked */ __HAL_UNLOCK(huart); " n/ A( G; g' u/ q6 U; H /* Enable the UART Parity Error Interrupt */) P Y3 }# [& _" m! j SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);: ^" P! B& h- Q /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */- f: Y9 R0 r% p SET_BIT(huart->Instance->CR3, USART_CR3_EIE);0 i3 Q5 h6 d8 s \6 Y9 O / b: K' A( V* F. x6 L /* Enable the DMA transfer for the receiver request by setting the DMAR bit in the UART CR3 register */ SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);, x- k+ {, A4 l return HAL_OK; }- ]! N* Q$ K' T- u" g3 E. T else { return HAL_BUSY;* X6 z2 @+ \2 d5 ]0 ]8 Y0 b } } 下面上我做的测试:一、Cube配置 1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。; Q3 r& M( m; n( Q2 A 2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。 以上两点大家可以自己改改测试。" A6 F) | P S2 p) S: _- ^
二、Keil例程编写' [4 c7 a5 U- d$ t8 z' a# q, {0 D
& {3 o8 R0 \3 ]; p 三、测试& T( x# p1 h: [/ p5 a/ ` 可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。
最后,奉上测试工程:
uart_dma_test.rar
(3.7 MB, 下载次数: 2111)
|
微信公众号
手机版
' {' `; e, y! ]) T; |2 [6 O
( Y' A; {. b1 G1 @& G! k# M
"no source": Error: #5: cannot open source input file "C:/Users/Administrator/STM32Cube/Repository/STM32Cube_FW_F1_V1.6.0/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c": No such file or directory
https://www.stmcu.org.cn/module/forum/thread-614550-1-1.html