|
个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑。) g9 a: R9 r b9 v/ u/ K6 G 不管什么芯片,当我们遇到问题时,通过查阅datasheet或上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道( 我就是用有道划的)/ \* e; ^" H. s# ~6 C4 x* uC语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。- @$ H4 A- m: v4 x5 B 程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。 鄙人浅见,请大家不吝赐教。; P9 ~+ d, s( r. g, K8 ~) ? 进入正题:UART以DMA方式接收和发送的函数调用顺序:# U- X# J6 E! _( h) E* C 循环模式接收: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 中断,这里就不讨论了。6 T' {. I" `, y, B" k7 b+ h. @) s& m , i/ u/ ?% o, ?( } 正常模式发送: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)! o) N6 d4 i, N! R) p; |) S5 H # @1 r9 d- e T 这里只分析 HAL_UART_Receive_DMA 的源码,其它的大家自己分析:# N7 ]3 p L9 p1 a" s1 U8 @ HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) UART以DMA方式接收指定长度数据到指定缓冲区 { uint32_t *tmp; # x0 [- t, n1 b8 ?2 Y) K2 ]5 a /* Check that a Rx process is not already ongoing */9 J0 c* ^& h! e+ n2 E$ v9 { if(huart->RxState == HAL_UART_STATE_READY) 检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY。其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。3 x- d6 r& E( F# K { if((pData == NULL) || (Size == 0U)): d8 ]* ?& ?* x% R { return HAL_ERROR; }. k2 s8 @( K$ \# ? /* Process Locked */ __HAL_LOCK(huart); ' }3 P* X# y W' T' x huart->pRxBuffPtr = pData;6 H0 R* a( a6 _0 C& [" {, ^& i7 l huart->RxXferSize = Size; huart->ErrorCode = HAL_UART_ERROR_NONE;, S" `( o2 X( _ J: h huart->RxState = HAL_UART_STATE_BUSY_RX;- X2 O1 A2 U& d$ i) t /* Set the UART DMA transfer complete callback */ huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; 设置DMA传输完成的回调函数。当DMA以循环方式传输时会调用UART接收完成中断的回调函数;以Normal方式传输时会关闭UART的DMA通道,并使能UART传输完成中断,触发UART传输完成中断,设置huart->RxState为READY,并调用 UART接收完成中断的回调函数。所以,不管DMA按循环或正常模式传输,到最后都会调用UART接收完成中断的回调函数4 H. Y; j1 U5 `* I6 V' E+ ] /* Set the UART DMA Half transfer complete callback */ huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt; W5 e. y6 j3 Y * q6 x: {; K* P% U. a( ` /* Set the DMA error callback */$ E* c7 Z1 q) f6 U huart->hdmarx->XferErrorCallback = UART_DMAError;: G) o) r7 u* k3 Q2 J$ ~4 ^' C/ U /* Set the DMA abort callback */ huart->hdmarx->XferAbortCallback = NULL;' j5 ~6 Y. n0 a# V9 R /* Enable the DMA channel */ tmp = (uint32_t*)&pData; HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);以中断方式打开DMA传输。所以CubeMx中DMA中断默认是打开的切不可更改 : v9 q; P; H1 G6 w: d8 R8 ?3 f /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */ __HAL_UART_CLEAR_OREFLAG(huart); /* Process Unlocked */ __HAL_UNLOCK(huart); /* Enable the UART Parity Error Interrupt */; s/ z9 ]! [7 R+ v4 Q SET_BIT(huart->Instance->CR1, USART_CR1_PEIE); /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */8 K( J1 |2 r; e0 B7 c7 U1 N5 \8 L SET_BIT(huart->Instance->CR3, USART_CR3_EIE);( u0 y# E( R( m! l6 b . D( |* G1 c6 W0 B: g. b" t) { /* 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);. @. [6 M6 E# m/ n( P, {% V 5 I. }$ Z+ e: t0 |2 W Z return HAL_OK;: _. I% B% b- h' n8 L }# |" O* P. F7 r2 V V' ? else+ m. J. `9 {6 B: k% }! H$ B { return HAL_BUSY; } } 下面上我做的测试:一、Cube配置 1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。 2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。 以上两点大家可以自己改改测试。
q. ^$ V) s7 J/ o) t 二、Keil例程编写) e u! C H( n1 B5 b* k
三、测试 Z6 @4 ]' x& ?4 U 可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。! z: l: q& T, m5 G' m F
最后,奉上测试工程:
uart_dma_test.rar
(3.7 MB, 下载次数: 2111)
|
微信公众号
手机版
2 w# W8 e% e" ]6 l4 i( }8 o/ L' a
"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