打印
[技术问答]

HC32F4A0 USART+DMA遇到的一个诡异问题

[复制链接]
1454|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
eyesmall|  楼主 | 2025-3-30 13:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
发送长度为N的数据,概率性出现倒数第二个字节发两遍,最终导致虽然串口发出来的数据是N个,但是DMA剩余长度为1,最后一个字节发不出来,导致DMA发送完成状态始终无法置位,不知道有没有人遇到过。还有就是设置重载模式,始终没效果,长度为0时就停了。参考串口DMA例程,使用了链表,但是多通道使用时只有最后一个配置的通道才能正常工作,不适用链表不行吗?

使用特权

评论回复
沙发
eyesmall|  楼主 | 2025-3-30 19:49 | 只看该作者
官方例程串口DMA用的链表+reconfig,但是看例程reconfig都没有配置,链表的话多串口时之后最后配置的可以用

使用特权

评论回复
板凳
eyesmall|  楼主 | 2025-3-30 21:25 | 只看该作者
    DMA_StructInit(&stcDmaInit);
    stcDmaInit.u32IntEn = DMA_INT_DISABLE;
    stcDmaInit.u32BlockSize = 1UL;
    stcDmaInit.u32TransCount = 512;
    stcDmaInit.u32DataWidth = DMA_DATAWIDTH_8BIT;
    stcDmaInit.u32DestAddr = (uint32_t)DMARecBuf_USART4;
    stcDmaInit.u32SrcAddr = (uint32_t)(&CM_USART4->RDR);
    stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_FIX;
    stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_INC;
    DMA_Init(USART4_RX_DMA_UNIT, USART4_RX_DMA_CH, &stcDmaInit);

        pstcDmaRepeatInit.u32Mode=DMA_RPT_DEST;
        pstcDmaRepeatInit.u32DestCount=512;
        pstcDmaRepeatInit.u32SrcCount=0;
        DMA_RepeatInit(USART4_RX_DMA_UNIT, USART4_RX_DMA_CH, &pstcDmaRepeatInit);               
                       
        AOS_SetTriggerEventSrc(USART4_RX_DMA_TRIG_SEL, USART4_RX_DMA_TRIG_EVT_SRC);
                       
        DMA_Cmd(USART4_RX_DMA_UNIT, ENABLE);
        DMA_ChCmd(USART4_RX_DMA_UNIT, USART4_RX_DMA_CH, ENABLE);       
对着手册研究了半天,实在是搞不清错在哪了

使用特权

评论回复
地板
苏山人家| | 2025-3-31 09:01 | 只看该作者
链表虽然能够重设srcAddr.dstAddr,len,ctrl等寄存器,但多串口使用时trig源是不同的,所以没有办法多串口使用链表。
最简单方式再单次dma发送完成后重新设置trig源及各个寄存器,那和链表没啥区别。但也能减少dma使用。
另外这个芯片uart tx使用dma需要先关闭tx然后再打开才能引起dmatx

使用特权

评论回复
5
eyesmall|  楼主 | 2025-3-31 09:11 | 只看该作者
苏山人家 发表于 2025-3-31 09:01
链表虽然能够重设srcAddr.dstAddr,len,ctrl等寄存器,但多串口使用时trig源是不同的,所以没有办法多串口使 ...

其实我最早也发现了这些问题,使用repeat或是链表都有问题,最后只能用手动重置方案,接收完512字节后,进中断重置,但后来测试发现会频繁丢数据,开始以为是外部数据输入的问题,但后来使用链表接收数据都是完整的,所以想再次尝试文档里repeat模式,但是搞来搞去都不行,挂仿真一堆寄存器数据都是对的,但是计数到0之后还是不能自动重载512

使用特权

评论回复
6
eyesmall|  楼主 | 2025-3-31 09:16 | 只看该作者
苏山人家 发表于 2025-3-31 09:01
链表虽然能够重设srcAddr.dstAddr,len,ctrl等寄存器,但多串口使用时trig源是不同的,所以没有办法多串口使 ...

前面一共说了两个问题,第一个是DMA发送留一个字节发送不完的问题,第二个是DMA接收完指定长度后CNT无法自动重置的问题

使用特权

评论回复
7
苏山人家| | 2025-3-31 10:44 | 只看该作者
1.最后1byte发送2次这个没遇见,怀疑是你dmatx trig源问题建议使用完成触发试一下。
2.自动重置也需要触发源,的确很难理解,后来直接偷懒软件重置了。如果想用可以用链表做个环形也算自动重置了

使用特权

评论回复
8
eyesmall|  楼主 | 2025-3-31 12:14 | 只看该作者
苏山人家 发表于 2025-3-31 10:44
1.最后1byte发送2次这个没遇见,怀疑是你dmatx trig源问题建议使用完成触发试一下。
2.自动重置也需要触发 ...

1、第一个问题DMA发送确实诡异,因为发送出来的数据长度也是对的,但是检测到收到的数据没有最后一个字节,反而倒数第二个发了两遍。也就导致发送完成标志无法置位,最早发现这个问题就是因为使用了发送完成标志进行判断,确保下次发送不会覆盖当前发送中的数据。
2、第二个问题DMA接收,我最早也是偷懒用的软件重置,但是高速率下重置会导致接收到的数据不完整,最近有看串口有超时判断功能,正准备用超时+软件重置,结果发现只有4个串口支持该功能,这样会导致多个串口数据处理算法不一致,比如4个用超时,一个用链表,还有3个有问题,还不便于维护。并不能完全解决这个问题。还是希望找到一种所有串口都能用的通用的常规的解决方法
3、说到重置,看资料里DMA1和DMA2公用一个触发源,这样感觉每次重置会重置所有的CHx,显然不行

使用特权

评论回复
9
xch| | 2025-3-31 12:44 | 只看该作者
就发一个字节试试啥情况

使用特权

评论回复
10
eyesmall|  楼主 | 2025-3-31 13:40 | 只看该作者
xch 发表于 2025-3-31 12:44
就发一个字节试试啥情况

高频快速才有概率出,单字节估计费劲

使用特权

评论回复
11
苏山人家| | 2025-4-8 09:06 | 只看该作者
eyesmall 发表于 2025-3-31 12:14
1、第一个问题DMA发送确实诡异,因为发送出来的数据长度也是对的,但是检测到收到的数据没有最后一个字节 ...

说一下我现在的实现,算是最苛刻,效率最高的,10个串口,cpu占用最低
1.所有串口开启RxTimeout,原生不支持的可以用AOS触发定时器
2.所有串口每路单独DMA接受(这里有坑,DMARx后UARTRx Irq正常关闭的但是,UART的ERR irq与Rx使能是一起的所以错误就没法用中断了)
3.再用5路DMA实现UART Tx,其余使用IRQ
优化方向:
1.中断里面软件重置DMA就行,只要压缩中断执行时间,就行,计算baud<2m以内都没问题的。
2.HC32的中断用的是函数数组,可以全部删除直接注册就行
3.中断内逻辑尽量内联生成,代码大但效率高
4.既然都使用了DMATx就不要处理Txr任何中断,不然可能会丢失trig信号(怀疑问题1)
5.要安全关闭DMA不然也有可能出问题(怀疑问题1),使用CHENCLR
6.接受先存储后立即重置或使用双buf,乒乓操作(问题2),RTO不是解决丢数的,是解决实时性

使用特权

评论回复
12
苏山人家| | 2025-4-8 09:06 | 只看该作者
*          定时器使用状态
* TMRA_9               UART3  RXTimeout(借用硬件触发)
* TMRA_10              UART4  RXTimeout(借用硬件触发)
* TMRA_11              UART5  RXTimeout(借用硬件触发)
* TMRA_12              UART8  RXTimeout(借用硬件触发)
* TMR6_7               UART9  RXTimeout(借用硬件触发)
* TMR6_8               UART10 RXTimeout(借用硬件触发)
* TMR0_1_A             UART1  RXTimeout(默认触发)
* TMR0_1_B             UART2  RXTimeout(默认触发)
* TMR0_2_A             UART6  RXTimeout(默认触发)
* TMR0_2_B             UART7  RXTimeout(默认触发)

使用特权

评论回复
13
eyesmall|  楼主 | 2025-4-15 16:59 | 只看该作者
苏山人家 发表于 2025-4-8 09:06
说一下我现在的实现,算是最苛刻,效率最高的,10个串口,cpu占用最低
1.所有串口开启RxTimeout,原生不支 ...

关于问题2,目前测试中断内重置DMA,重置过程中会概率性丢数,中断执行时间压缩到800ns,波特率115200还是会丢数,目前解决不了。
对于问题1,串口满负荷时很容易触发,正常情况下没复现,进行了迂回处理,把CNT=1作为执行完成标志,完美规避

使用特权

评论回复
14
作业粉碎机| | 2025-4-18 18:59 | 只看该作者
这个问题听起来确实有点棘手。你可以尝试检查一下DMA的配置,确保没有遗漏或者错误。有时候硬件的bug或者固件的问题也会导致这种情况,可以尝试更新固件或者查阅最新的硬件手册。

使用特权

评论回复
15
Amazingxixixi| | 2025-4-24 15:24 | 只看该作者
学习一下啊!感觉有点知识慌了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

167

帖子

0

粉丝