|
个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑。; k( p1 y& d1 ]2 h! } A* w 不管什么芯片,当我们遇到问题时,通过查阅datasheet或上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道( 我就是用有道划的)C语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。; O6 V; }2 O! N! M0 a1 _ 程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。( B+ I7 `* o) _; V1 r0 Z2 d4 p 鄙人浅见,请大家不吝赐教。 进入正题: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), S2 b% F/ U1 U4 O* w 当然这当中还会调用传输 Half 中断,这里就不讨论了。: R2 Z* y+ Y9 H. o 3 H0 m1 W: q. f/ a# m 正常模式发送: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), ]2 b+ Q2 C) o- V. H & y0 f/ H- h5 }! W) l7 S 这里只分析 HAL_UART_Receive_DMA 的源码,其它的大家自己分析:) V7 E: e6 Y" W3 B HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) UART以DMA方式接收指定长度数据到指定缓冲区 { uint32_t *tmp;* x" E. e2 W& Z4 M5 W /* Check that a Rx process is not already ongoing */. H3 {; F) q2 ^8 n9 l" S; k. d; q2 W if(huart->RxState == HAL_UART_STATE_READY) 检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY。其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。 {0 e! E, C' L, n& g! x9 o if((pData == NULL) || (Size == 0U))3 p8 }8 N) t+ s$ K/ A {# b) ^) E% n& J3 ?+ j$ w6 g% Q+ i4 G return HAL_ERROR;& M L. Q% \- I1 K$ A# k7 e- y) w } $ s( E9 b9 H' B1 M+ ^% c /* Process Locked */ a! o; Z5 S$ A __HAL_LOCK(huart);- h! V4 O+ A4 t huart->pRxBuffPtr = pData;% @& F- F3 E2 P huart->RxXferSize = Size; huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX;" o6 ]" U7 k; b$ b- r4 I6 _: C /* Set the UART DMA transfer complete callback */; M9 {1 P v; G( y huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; 设置DMA传输完成的回调函数。当DMA以循环方式传输时会调用UART接收完成中断的回调函数;以Normal方式传输时会关闭UART的DMA通道,并使能UART传输完成中断,触发UART传输完成中断,设置huart->RxState为READY,并调用1 u: B+ u; `4 s: a, I- A4 { UART接收完成中断的回调函数。所以,不管DMA按循环或正常模式传输,到最后都会调用UART接收完成中断的回调函数6 l2 y3 |: m, z" y* q7 H /* Set the UART DMA Half transfer complete callback */ huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;& ?/ D8 |0 p+ |3 D0 K" r /* Set the DMA error callback */2 ^( P* I3 d# M3 {( B$ s3 `9 W; m3 d, d3 u huart->hdmarx->XferErrorCallback = UART_DMAError; * t; x2 L# C [2 f4 V% T5 T /* Set the DMA abort callback */; R. m4 ~2 |! E* V& U huart->hdmarx->XferAbortCallback = NULL; 8 W* N- L1 I+ u6 v( g! c /* Enable the DMA channel */6 [$ K# y, L9 n% M( Q, v- v/ p tmp = (uint32_t*)&pData; HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);以中断方式打开DMA传输。所以CubeMx中DMA中断默认是打开的切不可更改$ H/ G$ Q1 }# \1 B /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */, [# E# o8 v. k$ B% G __HAL_UART_CLEAR_OREFLAG(huart); ' }8 [5 t( T: N( O9 P, ^4 @ /* Process Unlocked */ __HAL_UNLOCK(huart); 0 M$ c& L# s, Z: @ /* Enable the UART Parity Error Interrupt */# Y5 f. T. W" B8 W; [) S/ j/ W SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);; `: |+ r2 e+ v3 [ 4 R- }8 [$ M3 h+ u8 s H( f: r9 y# z% b /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ SET_BIT(huart->Instance->CR3, USART_CR3_EIE); /* Enable the DMA transfer for the receiver request by setting the DMAR bit 1 \5 k& k# C# p2 N/ s in the UART CR3 register */ SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);) M" z& H' T: U9 K % Y, y- `8 O8 L# t4 [6 I# X. H M return HAL_OK; }; @( v/ r0 `% E& z+ A& a% I' J else { return HAL_BUSY;3 k0 n% U4 y8 ^# z- w } } 下面上我做的测试:一、Cube配置 1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。. t% k* r) [' x! k 2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。 以上两点大家可以自己改改测试。
% j3 p# J) S' a D 二、Keil例程编写6 V4 P& y3 W& @ U3 Q- R
( d$ u9 |1 I7 O' \; ^ 三、测试 可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。
% \4 X' U2 t8 B4 S! ? 最后,奉上测试工程:
uart_dma_test.rar
(3.7 MB, 下载次数: 2111)
|
微信公众号
手机版
* Z9 A: m+ K" 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