yjnwjs 发表于 2016-12-25 23:04:57

STM32CubeMX的一个疑似串口DMA传输Bug

用STM32CubeMX V4.17.0 新建了一个串口DMA传输工程,同时使用接收和发送传输,目标器件为STM32F103ZET。STM32CubeMX完成了所有初始化工作。用户的工作是定义了缓存uint8_t uart1TxDmaBuffer,然后调用DMA发送函数HAL_UART_Receive_DMA(huart, (uint8_t *)uart1RxDmaBuffer, (uint16_t)RX_DMA_BUFFER_SIZE)完成发送。但是使用过程中发现,HAL_UART_Receive_DMA只工作一次便拒绝再次工作。即使将它放进while循环,复位后只发送一次便不再工作。按理来说,DMA中断是打开的,发送完毕执行中断服务函数,应该会将状态恢复到READY,下次用户调用便再次发送才对。分析代码发现,DMA发送的最终调用函数为UART_DMATransmitCplt:
static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)   
{
UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
/* DMA Normal mode*/
if ( HAL_IS_BIT_CLR(hdma->Instance->CCR, DMA_CCR_CIRC) )
{
    huart->TxXferCount = 0;

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

    /* Enable the UART Transmit Complete Interrupt */   
    __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
}
/* DMA Circular mode */
else
{
    HAL_UART_TxCpltCallback(huart);
}
}

在Normal模式下,该函数的工作只是清除些标志,没有调回调函数。关键在于,该函数没有将串口的状态从HAL_UART_STATE_BUSY_TX清除为HAL_UART_STATE_BUSY_READY,于是HAL_UART_Receive_DMA判断串口状态为HAL_UART_STATE_BUSY_TX,便拒绝再次发送。后修改代码(红色为增加部分)为:
static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)   
{
UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
/* DMA Normal mode*/
if ( HAL_IS_BIT_CLR(hdma->Instance->CCR, DMA_CCR_CIRC) )
{
    huart->TxXferCount = 0;

    /* Disable the DMA transfer for transmit request by setting the DMAT bit
       in the UART CR3 register */
    CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
               
                /* Check if a transmit process is ongoing or not */
   if(huart->State == HAL_UART_STATE_BUSY_TX_RX)
    {
      huart->State = HAL_UART_STATE_BUSY_RX;
    }
    else
    {
      huart->State = HAL_UART_STATE_READY;
    }
    /* Enable the UART Transmit Complete Interrupt */   
    __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
}
/* DMA Circular mode */
else
{
    HAL_UART_TxCpltCallback(huart);
}
}

工作正常。

5265325 发表于 2016-12-26 10:25:51

:lol:lol:lol:lol

wjandsq 发表于 2016-12-26 11:34:18

1.103的HAL库要修改一次才行。
2.中断函数不应该这么写的,最好是每个中断写一个。
3.回调函数要自己实现的,最好不要改人家的。
4.DMA用起来,HAL库没有Stdperiph 库灵活了。

wjandsq 发表于 2016-12-26 11:35:20

可以参考F4的HAL库,stm32cubemx软件要升级为4.18.0版本。

当幸福来敲men 发表于 2017-2-14 13:58:47

为什么我改了之后还是不正常,楼主能分享个例程吗?

当幸福来敲men 发表于 2017-2-14 15:57:12

只要 在cube配置时开启串口中断就可以用了,不用添加任何代码

无帝老三 发表于 2017-9-28 14:21:50

本帖最后由 无帝老三 于 2017-9-28 14:31 编辑

目前使用f4的HAL库 cubemax 4.18
不开启uart中断,
DMA发送一次后huart->gState = HAL_UART_STATE_BUSY_TX
就再也不会变成HAL_UART_STATE_READY了

开启uart中断后,就会执行HAL_UART_IRQHandler,进入去执行到最后
UART_EndTransmit_IT里面会执行huart->gState = HAL_UART_STATE_READY;

之前想少开一个串口中断,看来是画蛇添足了

taolee520 发表于 2019-11-30 21:17:21

最近也在研究这个,
发表下个人意见:
/* Enable the UART Transmit Complete Interrupt */   
    __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
最后不是打开TCIE中断了吗?传输完成后,UART_TC_FLAG应该已经置位,加之中断TCIE打开,
最后会进入串口中断处理函数,执行到UART_EndTransmit_IT(huart);
该函数里有:
__HAL_UART_DISABLE_IT(huart, UART_IT_TC);
huart->gState = HAL_UART_STATE_READY;
HAL_UART_TxCpltCallback;//回调函数
我想这应该是库开发人员为了更加灵活方便,专门这样做的哦。
我现在手头没得环境,不然我就验证下
页: [1]
查看完整版本: STM32CubeMX的一个疑似串口DMA传输Bug