STM32F4 HAL库 串口 DMA正常模式仅发一次问题?

分析STM32F4 HAL库 串口 DMA正常模式仅发一次问题?

芯片:STM32F411CE
串口:串口1
I/O脚:Tx->PA9,Rx-> PA10

初始化代码,直接STM32 CubeMx生成;
发送函数: HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

接下来我们分析下这个函数:

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 == 0))
    {
      return HAL_ERROR;
    }
  /* Process Locked */
    __HAL_LOCK(huart);  **//1.串口操作上锁**
    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->gState = HAL_UART_STATE_BUSY_TX; **//2.串口操作状态切换到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 Stream */
tmp = (uint32_t*)&pData;
HAL_DMA_Start_IT(huart->hdmatx, *(uint32_t*)tmp, (uint32_t)&huart->Instance->DR, Size);
**//3.该函数会让DMA 操作上锁 同时会开启中断;**
/* 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);  **//4.串口操作解锁**    

/* 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;
  }
}

该函数操作的步骤1和4是加锁和解锁串口进程,这两步骤不会有问题;
主要问题出在步骤2和3,

  1. 步骤2会把串口状态切换到busy,但是切回Ready状态的操作需要我们自己动手;
  2. 步骤3,在HAL_DMA_Start_IT()函数里面会将DMA加锁但是没有解锁,同时函数会开启DMA 半传输、完成传输、传输错误、FIFO溢出错误中断位;

解决办法:

1.建议开启DMA传输完成中断
2.在完成中断函数里面将串口状态切换到Ready状况;
3.将DMA解锁
4.Clear相应中断标志位
测试代码:

void DMA2_Stream7_IRQHandler()
{
huart1.gState = HAL_UART_STATE_READY;
hdma_usart1_tx.State = HAL_DMA_STATE_READY;
__HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_TCIF3_7);
__HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_HTIF3_7);
__HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_FEIF3_7 );
__HAL_UNLOCK(&hdma_usart1_tx);
}

然后串口发送传输即可正常操作;
注意:项目中需要在中断函数里面判定中断Flag后在做相应的处理,否则会漏掉错误中断的处理;

你可能感兴趣的:(嵌入式)