STM32 DMA 清除传输完成标志错误导致的问题

硬件平台:STM32F407
开发平台:MDK

问题描述:

这几天在调试STM32 串口通讯时,突然发现某些发送的数据不对,如下所示:
请添加图片描述

本来需要发送的是:

24 06 FF 03 00 36 8C 0A AA 55

结果变成了:

24 06 FF 10 00 19 02 0C DD DD

其中,发送的数据变成了下一帧需要发送的数据的一部分。

由于我的串口通讯采用的是DMA发送,模式配置为Normal(每次发送都需要重新启动和清除标志)。

我清除标志的方式采用的是如下方式:

    if(DMA_GetFlagStatus(RS485_USART_DMA_STREAM, RS485_USART_DMA_TCIF_FLAG) != RESET)//等待DMA2_Steam7传输完成
    {        
        DMA_ClearFlag(RS485_USART_DMA_STREAM, RS485_USART_DMA_TCIF_FLAG);//清除DMA2_Steam7传输完成标志
    }

    //开始一次DMA传输!
    DMA_Enable(RS485_USART_DMA_STREAM, g_RS422TxBuf[FRAME_INDEX_FRAME_LENGTH]);  

采用if去判断传输完成标志是否传输完成,然后再启动DMA传输。

这里有一个bug就是:

如果DMA在刚好启动传输的过程中,突然其他任务修改了DMA定义的传输缓存内容,那么传输的内容也会随之而修改。如下图所示:

请添加图片描述

这样也就能解释为什么上述传输的数据改变了的问题了。

解决方案

由于DMA采用的是单次模式(Normal),因此每次开启DMA传输时都需要清除传输完成标志。因此在清除传输完成标志时采用 while() 超时等待的方式去就解决该问题。

    DMASendTimeout = 0xFFFF;

	//开始一次DMA传输!
    DMA_Enable(RS485_USART_DMA_STREAM, g_RS422TxBuf[FRAME_INDEX_FRAME_LENGTH]);     
	
    //等待DMA传输完成
    while(!DMA_GetFlagStatus(RS485_USART_DMA_STREAM, RS485_USART_DMA_TCIF_FLAG))//等待DMA2_Steam7传输完成
    {        
        if((DMASendTimeout--) == 0) return;
    }
    DMA_ClearFlag(RS485_USART_DMA_STREAM, RS485_USART_DMA_TCIF_FLAG);//清除DMA2_Steam7传输完成标志

总结

之前采用 if 的语句判断传输完成标志时是为了避免任务存在while(1) 的死等方式导致卡死系统,就算要使用,必须添加超时溢出机制。

解决该问题的方案有多种,上述方案是最直接的,也是解决源头问题。也可以采用其他方案,例如,将所有设计到修改DMA内存值的代码全部放在一个任务中,由于单片机是单线程,顺序执行的,因此将其放到一个任务中就可以避免该问题的出现。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值