你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

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

[复制链接]
yjnwjs 提问时间:2016-12-25 23:04 /
用STM32CubeMX V4.17.0 新建了一个串口DMA传输工程,同时使用接收和发送传输,目标器件为STM32F103ZET。STM32CubeMX完成了所有初始化工作。用户的工作是定义了缓存uint8_t uart1TxDmaBuffer[TX_DMA_BUFFER_SIZE],然后调用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);
  }
}

工作正常。
收藏 2 评论7 发布时间:2016-12-25 23:04

举报

7个回答
5265325 回答时间:2016-12-26 10:25:51
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;

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

SlamDunk 回答时间: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;//回调函数
我想这应该是库开发人员为了更加灵活方便,专门这样做的哦。
我现在手头没得环境,不然我就验证下
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版