下面看一下函数具体实现:
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)
{
uint32_t dmarequest = 0x00U;
/* The Lock is not implemented on this API to allow the user application
to call the HAL UART API under callbacks HAL_UART_TxCpltCallback() / HAL_UART_RxCpltCallback():
when calling HAL_DMA_Abort() API the DMA TX/RX Transfer complete interrupt is generated
and the correspond call back is executed HAL_UART_TxCpltCallback() / HAL_UART_RxCpltCallback()
*/
/* Stop UART DMA Tx request if ongoing */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT);
if((huart->gState == HAL_UART_STATE_BUSY_TX) && dmarequest)
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
/* Abort the UART DMA Tx channel */
if(huart->hdmatx != NULL)
{
HAL_DMA_Abort(huart->hdmatx);
}
UART_EndTxTransfer(huart);
}
/* Stop UART DMA Rx request if ongoing */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if((huart->RxState == HAL_UART_STATE_BUSY_RX) && dmarequest)
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel */
if(huart->hdmarx != NULL)
{
HAL_DMA_Abort(huart->hdmarx);
}
UART_EndRxTransfer(huart);
}
return HAL_OK;
}
主要分为2大部分,处理标志,关闭发送和接收DMA。
HAL_StatusTypeDef HAL_UART_AbortReceive(UART_HandleTypeDef *huart)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Disable the UART DMA Rx request if enabled */
if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel : use blocking DMA Abort API (no callback) */
if(huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = NULL;
HAL_DMA_Abort(huart->hdmarx);
}
}
/* Reset Rx transfer counter */
huart->RxXferCount = 0x00U;
/* Restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
return HAL_OK;
}
正常方法是这样。
但是使用空闲中断也有一个问题,就是的发送端发送一帧数据不能被打断。不然stm32就会触发空闲中断,只接收到一帧的一部分数据。
空闲中断就是这个串口线有一个字节的时间没有数据传输就触发空闲中断吧。
那么假设我发送端要发送一帧数据,共20个字节,那么假设在发送到第10个字节的时候,被中断打断了,打断了之后恢复发送,那么打断到恢复发送这段时间超过了传输一个字节的时间,则就会触发接收端的空闲中断。
则接收端只接收到了10个字节,这个时候在中断里面关闭DMA再开启已经来不及接收后面的了?
这个问题怎么解决的阿?
针对第2点,串口DMA接收不能单独停止。
HAL_UART_DMAStop()函数的确是uart接收和发送同时关闭,找了好久终于找到只关闭接收的函数了。
只关闭接收的函数。HAL_UART_AbortReceive()
下面看一下函数具体实现:
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)
{
uint32_t dmarequest = 0x00U;
/* The Lock is not implemented on this API to allow the user application
to call the HAL UART API under callbacks HAL_UART_TxCpltCallback() / HAL_UART_RxCpltCallback():
when calling HAL_DMA_Abort() API the DMA TX/RX Transfer complete interrupt is generated
and the correspond call back is executed HAL_UART_TxCpltCallback() / HAL_UART_RxCpltCallback()
*/
/* Stop UART DMA Tx request if ongoing */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT);
if((huart->gState == HAL_UART_STATE_BUSY_TX) && dmarequest)
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
/* Abort the UART DMA Tx channel */
if(huart->hdmatx != NULL)
{
HAL_DMA_Abort(huart->hdmatx);
}
UART_EndTxTransfer(huart);
}
/* Stop UART DMA Rx request if ongoing */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if((huart->RxState == HAL_UART_STATE_BUSY_RX) && dmarequest)
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel */
if(huart->hdmarx != NULL)
{
HAL_DMA_Abort(huart->hdmarx);
}
UART_EndRxTransfer(huart);
}
return HAL_OK;
}
主要分为2大部分,处理标志,关闭发送和接收DMA。
HAL_StatusTypeDef HAL_UART_AbortReceive(UART_HandleTypeDef *huart)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Disable the UART DMA Rx request if enabled */
if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel : use blocking DMA Abort API (no callback) */
if(huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = NULL;
HAL_DMA_Abort(huart->hdmarx);
}
}
/* Reset Rx transfer counter */
huart->RxXferCount = 0x00U;
/* Restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
return HAL_OK;
}
也是分为2部分,处理标志和关闭接收DMA。
最简单的实现:
1. 先关闭接收DMA,HAL_DMA_Abort(huart->hdmarx);
2. 置位RX ready状态,huart->RxState = HAL_UART_STATE_READY;
忽略了错误标志和IT标志处理,最保险的方式还是使用HAL_UART_AbortReceive()函数。
评分
查看全部评分
正好遇到了这个问题。
群里朋友帮找到了这个帖子,收益匪浅。
HAL_UART_AbortReceive()代替HAL_DMA_STOP()挺好的。
采用缓冲区接收N次IDLE中断接收到的数据,然后再处理。N根据实际情况来定。也可采用环形缓冲区