[学习笔记] AC78xx 如何利用DMA接收不定长的数据

[复制链接]
 楼主| GrootBrain 发表于 2021-7-2 14:32 | 显示全部楼层 |阅读模式
利用DMA接收串口数据,完全不需要MCU去轮询串口状态或利用串口的中断去搬运数据,简直爽得不得了
但是,DMA搬运过程中,只能设定一个固定的长度,等到DMA传输到一半或传输完成时,才能有中断产生,或者轮询DMA搬运长度,这不是增加了MCU的负荷嘛。
熟悉AC78xx 串口的小伙伴应该知道,AC78xx的串口有个IDLE中断,简单的说,就是在串口开始接收后,Rxd引脚空闲1byte长度,即产生一个IDLE中断。为了让大家有个直观的认识,来张图吧。
1625204291(1).jpg
从图中可以看出,RXD空闲1个字节的时候,立即产生IDLE中断。在IDLE的中断中,我们可以查询DMA接收的长度,可以将对搬运到缓存内的数据进行处理。

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

  2. int32_t UART_IntHandler(uint8_t port, uint32_t lsr0, uint32_t lsr1)
  3. {
  4.     int32_t DMARcvLen = 0;
  5.    
  6.     if (lsr1 & LSR1_IDLE) {         // IDLE
  7.         DMARcvLen = UART_GetDMAReceiveCount(port);
  8.    
  9.         if ((DMARcvLen>0) && (DMARcvLen < UART_DATA_LEN_SEL)) {
  10.             
  11.             GPIOD_OUT(11) = 1;
  12.             memcpy(g_sendDataBuf, g_recvedDataBuf, DMARcvLen);
  13.             
  14.             memset(g_recvedDataBuf, 0, sizeof(g_recvedDataBuf));
  15.             
  16.             UART_StartDMAReceive(1, 8, (uint32_t)g_recvedDataBuf, UART_DATA_LEN_SEL, UART_RxDMACallback);//¿ªÆôDMA,×¼±¸½ÓÊÕÊý¾Ý
  17.             UART_StartDMATransmit(1, 8, (uint32_t)g_sendDataBuf, DMARcvLen, UART_TxDMACallback);//ÅäÖÃDMA´«ÊäÊý¾Ý
  18.             
  19.             GPIOD_OUT(11) = 0;
  20.         }
  21.     }
  22.    
  23. }
我们使用串口助手来演示一下效果。
2021-07-02-14-18-21.gif

可以看到,利用IDLE中断接收不定长度的数据,效果还是很不错的。
不过要注意的是,DMA接收缓存需要开得足够大,还有在IDLE的中断内,快速读出缓存并开始下一次的DMA接收,降低数据丢失的概率。
DMA接收函数,被我改动了一点点,后面再跟大家聊聊,为什么会改动DMA的配置吧。
UART_Sample.rar (471.4 KB, 下载次数: 18)
chenjun89 发表于 2021-7-3 08:18 来自手机 | 显示全部楼层
谢谢楼主分享经验
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

93

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部