打印
[学习笔记]

AC78xx 如何利用DMA接收不定长的数据

[复制链接]
3860|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
利用DMA接收串口数据,完全不需要MCU去轮询串口状态或利用串口的中断去搬运数据,简直爽得不得了
但是,DMA搬运过程中,只能设定一个固定的长度,等到DMA传输到一半或传输完成时,才能有中断产生,或者轮询DMA搬运长度,这不是增加了MCU的负荷嘛。
熟悉AC78xx 串口的小伙伴应该知道,AC78xx的串口有个IDLE中断,简单的说,就是在串口开始接收后,Rxd引脚空闲1byte长度,即产生一个IDLE中断。为了让大家有个直观的认识,来张图吧。

从图中可以看出,RXD空闲1个字节的时候,立即产生IDLE中断。在IDLE的中断中,我们可以查询DMA接收的长度,可以将对搬运到缓存内的数据进行处理。

要执行串口IDLE的中断,有以下步骤:
1. NVIC模块中是能串口中断,NVIC_EnableIRQ(UARTX_IRQn);
2. 串口模块是能IDLE中断和多机通信,    UART_SetIdleEn(UART1, TRUE);  UART_SetMulComEn(UART1, TRUE);
注意:
3. 给串口一个回调函数,在回掉中处理数据,我们在这里就将接收到的内容通过DMA发送出去。
UART_SetEventCallback(UART1, UART_IntHandler);

int32_t UART_IntHandler(uint8_t port, uint32_t lsr0, uint32_t lsr1)
{
    int32_t DMARcvLen = 0;
   
    if (lsr1 & LSR1_IDLE) {         // IDLE
        DMARcvLen = UART_GetDMAReceiveCount(port);
   
        if ((DMARcvLen>0) && (DMARcvLen < UART_DATA_LEN_SEL)) {
            
            GPIOD_OUT(11) = 1;
            memcpy(g_sendDataBuf, g_recvedDataBuf, DMARcvLen);
            
            memset(g_recvedDataBuf, 0, sizeof(g_recvedDataBuf));
            
            UART_StartDMAReceive(1, 8, (uint32_t)g_recvedDataBuf, UART_DATA_LEN_SEL, UART_RxDMACallback);//¿ªÆôDMA,×¼±¸½ÓÊÕÊý¾Ý
            UART_StartDMATransmit(1, 8, (uint32_t)g_sendDataBuf, DMARcvLen, UART_TxDMACallback);//ÅäÖÃDMA´«ÊäÊý¾Ý
            
            GPIOD_OUT(11) = 0;
        }
    }
   
}
我们使用串口助手来演示一下效果。


可以看到,利用IDLE中断接收不定长度的数据,效果还是很不错的。
不过要注意的是,DMA接收缓存需要开得足够大,还有在IDLE的中断内,快速读出缓存并开始下一次的DMA接收,降低数据丢失的概率。
DMA接收函数,被我改动了一点点,后面再跟大家聊聊,为什么会改动DMA的配置吧。
UART_Sample.rar (471.4 KB)

使用特权

评论回复

相关帖子

沙发
chenjun89| | 2021-7-3 08:18 | 只看该作者
谢谢楼主分享经验

使用特权

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

本版积分规则

17

主题

90

帖子

2

粉丝