DMA中断模式,莫名其妙的问题..

anticrane   2009-4-28 01:25 楼主
最近在做个上下位机通讯的自定义协议,思路如下:
    (1)通过状态机的方法分析数据包,提取需要的信息,这部分是采用【USART1中断接收模式】做的。
    (2)分析数据包内固定位置的【数据长度】信息,在数据包最后一个字节到来并触发【USART1中断服务程序】的时候,在【USART1中断服务程序】中【启动DMA接收之前取得的“确定长度”的数据,同时失能USART1的中断】
    (3)在DMA接收完毕后【自动进入DMA中断服务程序,并重新使能USART1的中断】。
    然后问题就出现在(2)上面,由于这个USART1中断是通过数据包的【最后一个字节的到来】而被触发的,所以进入USART1中断服务程序时,我所用的临时变量读到的就是这【最后一个字节】,而同时,DMA也是在此开启的,我将DMA配置为非循环,每次使用前先Disable并重新配置后再Enable,然后比如设为读10个数据,存入缓冲区TEMP[]中,实际硬件调试中通过串口的输出,我发现TEMP[0]中存放的就是之前提到【最后一个字节】,TEMP[1]~TEMP[9]中是正确的前9个数据,第10个数据不翼而飞...因为在第9个数据被读入时已经进入【DMA中断服务程序】了...
    所以搞得现在要在原来的帧中加了个“流水号”(实为凑数的字节),同时若要收10个数据,我就将长度设为11,收到的就是10个正确的...这么下来貌似一切正常了,但明显这是在掩盖问题...因此希望能了解下到底是怎么回事..

回复评论 (7)

启动DMA接收之前,要先读出接收到的字节并清除接收缓冲区

                                 不通过程序读出数据包的最后一个字节,当然它会被DMA读出。
点赞  2009-4-28 10:00

明白了!

    试过清掉那个标志果然有效,结果现在又碰上一问题........
    发送时USART1使用DMA1传送20个数据,主机是收到20个数据没错,但是,比如我连续发送6组各20个数据,前5组都是每次只发19个,最后个丢失,第6组到是正常,仍然20个。
    给我的感觉就是DMA中断告知数据已发完,实际上这时候是将最后个数据送入缓冲区,并不是指主机已经收到这个数据,然后我再次启动DMA导致下一个数据将这个缓冲区内的数据覆盖掉了,就像在程序中连续执行两句语句:USART1->DR = 0x12; USART1->DR = 0x34;主机只会收到后面那个,不知道我的理解对不对呢?
    那么这个问题是不是可以靠死等某个标志的状态解决呢?比如发送完成标志位USART_FLAG_TC...
点赞  2009-4-28 17:18

我check的是DMA1_FLAG_TCx位

                                 另外还要加上定时器超时判断,别一直死在等待中。
点赞  2009-4-28 17:41

楼上写错了吧,应该是USART_SR寄存器的TC标志

从STM32的参考手册上可以清楚地看到,每次DMA传送的条件是发送缓冲区空,即DMA传输完成的时间也就是最后一个要发送的字节送到发送缓冲区的时候。这与你观察到的一样。

要想再次启动DMA就必须等待上次的数据发送出去之后,既等待USART_SR寄存器的TC标志;另一种更快的方法是再次启动DMA时,不要重新初始化USART,尤其是不要破坏USART的现有状态,这样新的DMA过程会继续上次的数据块继续传送。
点赞  2009-4-28 18:25

谢谢!

“另一种更快的方法是再次启动DMA时,不要重新初始化USART,尤其是不要破坏USART的现有状态,这样新的DMA过程会继续上次的数据块继续传送。”
----------------
还是这方法好,这回一切正常了,而且还没死等的过程....
Mrs.vigia所说的死等...我之前也在担心这个,所以凡遇上死等绝对少不了超时检测,搞得复杂无比,后面发现...加个看门狗及当前状态快速恢复任务,然后去掉所有的超时检测,程序一样健壮无比
点赞  2009-4-28 18:52

这个方法好——加个看门狗及当前状态快速恢复任务

                                 楼主用到OS?
点赞  2009-4-28 19:06

没用到OS..

    软件部分仅仅是用到滴答定时器做了个时基,关键部分全都放在中断中处理(NVIC_PriorityGroup_4模式,优先级高的中断抢占没商量),对实时性不高的部分则在主程序中通过中断部分设置的标志进行判定是否执行,关键数据直接写入FLASH并加入写保护,根据不同复位源有不同现场恢复机制。
    因为是应用在PLC上的,所以可靠性相当重要,因此软件看门狗放在主程序中喂(防止程序跑飞),硬件看门狗放在中断中喂(防止“真”死机状态),试下来效果挺好...
点赞  2009-4-28 20:53
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复