个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑。 不管什么芯片,当我们遇到问题时,通过查阅datasheet或上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道(我就是用有道划的); Z2 i) g- l3 f& }4 W- }0 a, e C语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。8 F4 k3 N+ x }- X 程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。 鄙人浅见,请大家不吝赐教。! `7 M7 v+ x4 s' ^4 B 进入正题:UART以DMA方式接收和发送的函数调用顺序:2 ~: _3 ^$ m, A' x 循环模式接收: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)* P4 Y5 Q9 B; {% X6 E2 y# J D. `& j 当然这当中还会调用传输 Half 中断,这里就不讨论了。0 v5 V9 ?# @) R I! b4 Y . [0 m( l) L9 @' B* m: Y, G& f 正常模式发送: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)# e+ o \# D# w" v* U 这里只分析 HAL_UART_Receive_DMA 的源码,其它的大家自己分析:; B0 M5 r/ u$ G Y HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) UART以DMA方式接收指定长度数据到指定缓冲区1 ^, I3 p* I; u3 e { uint32_t *tmp;- L5 b8 c/ U: a6 o! I2 u S; e; { : S2 {9 q7 G: M2 J# ~ /* Check that a Rx process is not already ongoing */ if(huart->RxState == HAL_UART_STATE_READY) 检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY。其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。 {2 }; G1 ]: p, W0 Q, W if((pData == NULL) || (Size == 0U)) {' Y/ l2 t" o/ _5 z: _ return HAL_ERROR; }# I: `1 ]: D- m( U5 c, Q: p / V/ x4 o5 ]/ R1 g' b. |7 v+ w4 S /* Process Locked */ __HAL_LOCK(huart); 2 X4 c2 E8 [6 r6 ]% w0 f) R: s huart->pRxBuffPtr = pData; huart->RxXferSize = Size; " a) h$ K4 i& ~# Y- {% s huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX;* M w1 S3 Z- p8 ^6 I, B 7 E, _* D' s( _2 e /* Set the UART DMA transfer complete callback */ huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; 设置DMA传输完成的回调函数。当DMA以循环方式传输时会调用UART接收完成中断的回调函数;以Normal方式传输时会关闭UART的DMA通道,并使能UART传输完成中断,触发UART传输完成中断,设置huart->RxState为READY,并调用) K" n3 n5 F. N; u: E8 h q UART接收完成中断的回调函数。所以,不管DMA按循环或正常模式传输,到最后都会调用UART接收完成中断的回调函数 /* Set the UART DMA Half transfer complete callback */+ ^' {, u' s0 a5 q3 _+ u5 S huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt; Q' U% W( m2 p/ y5 a1 P# j /* Set the DMA error callback */, p+ L0 W/ ?) d7 G huart->hdmarx->XferErrorCallback = UART_DMAError;7 n+ P2 Z r0 C$ f& H* G * j" \7 N1 e+ L /* Set the DMA abort callback */ huart->hdmarx->XferAbortCallback = NULL;+ z0 Y, ?- H2 F6 E6 i7 j /* Enable the DMA channel */( m" w/ r2 ~. {% x1 O2 s tmp = (uint32_t*)&pData; HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);以中断方式打开DMA传输。所以CubeMx中DMA中断默认是打开的切不可更改. q" ^4 Z0 `, z+ I. t8 X& F5 y /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */! X: I4 r1 k, v __HAL_UART_CLEAR_OREFLAG(huart); /* Process Unlocked */! L, L6 S0 E/ U1 I9 }- w __HAL_UNLOCK(huart); 8 L- H1 L6 M6 M( t# W /* Enable the UART Parity Error Interrupt */1 Y6 _( O+ Z0 u. X0 c5 g& c- R& j SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);/ J/ K. w/ q; [6 P( N8 W4 a6 G5 e( G , n2 S* C# v& H /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ SET_BIT(huart->Instance->CR3, USART_CR3_EIE); 1 ~: ~0 o$ K' l3 O7 v /* 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);5 _8 f8 j# U- H- i1 ]7 a! A6 n" b3 K return HAL_OK;! R; l, s& M1 C* E } else { return HAL_BUSY; }! S& L9 `9 ~ l: B& @* T } 下面上我做的测试:一、Cube配置; d: @8 s' K0 w% G# Q' C6 A: j 1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。 2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。% W: N; \2 Y! a: _( y/ W 以上两点大家可以自己改改测试。$ }% o2 w! [1 h; M 二、Keil例程编写% b' G7 v) z0 l, x $ a) V% {$ r1 }6 Y! Q+ D 三、测试/ Q" L) Q0 F" t' u0 K+ [ 可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。) Q' W1 B/ S: i0 w6 I/ a+ r / I! e% N# S5 s2 S) s% I 最后,奉上测试工程: |
, v* ]5 U' B) a" ]! Q. u. _
a5 _7 Q7 \% L+ k
"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