解决串口发送DMA只能发送一次的问题方法:修改HAL_UART_Transmit_DMA()函数

参考文章:1. http://t.csdn.cn/FT6Mg

                  2. http://t.csdn.cn/ejFIQ

今天用STM32F1的HAL库开发遇到一个奇怪的问题,在主函数循环调用中用串口1的DMA请求,将内存中的数据发送给串口,无论延迟Delay开了多大,始终只能发送一次DMA数据。后来在网上查阅大佬的资料终于有了思路。

废话不多说,先上代码:

在 stm32f1xx_hal_uart.c 文件中找到HAL_UART_Transmit_DMA()函数实现,在解锁操作__HAL_UNLOCK;后添加代码:huart -> gState = HAL_UART_STATE_READY;  编译以后运行完美解决。而且在低延迟的高速while循环中反复调用串口DMA请求,都可以运行。

HAL_UART_Transmit_DMA()函数实现修改:(也就多加了一行代码而已[doge])

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  uint32_t *tmp;

  /* Check that a Tx process is not already ongoing */
  if (huart->gState == HAL_UART_STATE_READY)     
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->gState = HAL_UART_STATE_BUSY_TX;   //修改串口的工作状态为Busy

    /* Set the UART DMA transfer complete callback */
    huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;

    /* Set the UART DMA Half transfer complete callback */
    huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;

    /* Set the DMA error callback */
    huart->hdmatx->XferErrorCallback = UART_DMAError;

    /* Set the DMA abort callback */
    huart->hdmatx->XferAbortCallback = NULL;

    /* Enable the UART transmit DMA channel */
    tmp = (uint32_t *)&pData;
    HAL_DMA_Start_IT(huart->hdmatx, *(uint32_t *)tmp, (uint32_t)&huart->Instance->DR, Size);

    /* Clear the TC flag in the SR register by writing 0 to it */
    __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);

    /* Process Unlocked */
    __HAL_UNLOCK(huart);
		huart -> gState = HAL_UART_STATE_READY;    //这一句官方好像给落下了???

    /* Enable the DMA transfer for transmit request by setting the DMAT bit
       in the UART CR3 register */
    SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

简要分析:每当调用一次HAL_UART_Transmit_DMA()都会先进行一次串口状态的判断:if (huart->gState == HAL_UART_STATE_READY) 如果串口处于READY状态,则开始本次的DMA传输,否则会返回一个BUSY状态:

else
  {
    return HAL_BUSY;
  }

当第一次调用HAL_UART_Transmit_DMA()时,串口处于READY状态,于是进行DMA传输,注意,在DMA传输过程中,会将串口从READY状态改为发送BUSY状态(软件修改):huart->gState = HAL_UART_STATE_BUSY_TX;但是在DMA完成本次传输工作以后,并没有将串口从发送BUSY状态改回READY状态,一开始我认为可能硬件自动修改该标志,但是不确定,还没有翻参考手册,如果有知道的大佬烦请指教!因此这里我索性添加一句代码软件修改该状态:huart -> gState = HAL_UART_STATE_READY;

这样就能保证每次调用完HAL_UART_Transmit_DMA()函数后,串口的状态均为READY,为下一次的串口发送DMA请求做准备。

物联沃分享整理
物联沃-IOTWORD物联网 » 解决串口发送DMA只能发送一次的问题方法:修改HAL_UART_Transmit_DMA()函数

发表评论