找回密码
 立即注册
查看: 520|回复: 4

关于UART RX DMA使用方法的问题

[复制链接]
  • 打卡等级:偶尔看看II
  • 打卡总天数:28
  • 最近打卡:2025-01-08 16:11:02

12

主题

26

回帖

224

积分

中级会员

积分
224
发表于 2024-11-25 14:40:23 | 显示全部楼层 |阅读模式
最近做项目需要用到串口通信,通信速率500Kbps,且不使用中断而使用主线程轮询检测接收数据,在500Kbps高速率不间断的向MCU发送数据时,主线程轮询的方法来查询RI标志位,在执行其他操作时,会导致数据丢失,因此改用UART RX DMA来进行数据缓存,但是实现过程中出现了莫名其妙的问题,请各位大佬帮忙看一看!感谢!
实现思路:
1、配置UART RX DMA指向1024字节的缓存数组,同时配置RX DMA的接收数据中断生成阈值为1024,同样在主循环中检测接收数据完成标志,标志完成后,重新开启RX DMA的接收工作,这样则可以不间断地接收RX的数据,数据从缓存数组0开始到1023,溢出后,继续从缓存数组0开始存放。(DMA在不断接收,UART_DMA_DONE寄存器在不断从0~1023计数)
2、主循环定时检查DMA已经传输的字节数,检测本次传输字节数与上次检查的传输字节数的差值,如果检测到传输成功字节数发生变化,则取本次与上次的差值,这个差值就是上次检测到本次检测时间内接受到的数据量,然后将这些数据取出放进串口状态机内。
串口及DMA初始化代码如下:
  1. unsigned char xdata Uart_RxBuf[1024];<span style="white-space:pre">                                                </span>/* 串口DMA接收缓存 */
复制代码
DMA中断处理代码如下(此函数放在主线程中不断轮询):
  1. void DMARX_ISRHandler()
  2. {
  3.     if(DMA_UR1R_STA&0x01)
  4.     {               
  5.         LED = !LED;
  6.         /* 清除缓存,并重新开始接收数据 */
  7.         DMA_UR1R_STA &= ~0x01;
  8.         DMA_UR1R_CR |= 0x01;
  9.         DMA_UR1R_CR |= 0x20;
  10.     }
  11. }
复制代码
接收处理代码如下(同样放在主线程中不断轮询):
  1. volatile unsigned long  counter = 0;
  2. volatile unsigned long  lastcounter = 0;
  3. volatile unsigned long rec_count = 0;
  4. volatile unsigned long process_length = 0;
  5. void DMARx_Handler()
复制代码
主函数代码如下:
  1. void main()
  2. {
  3.     HardwareInit();
  4.     SoftwareInit();
复制代码

rec_count 用于记录从上电到当前时间,串口接收到的数据总量,理论上这种思路只要保证每次轮询间隔时间内缓存足够大,MCU就能不丢失的处理高速率串口数据,但是我用STC32G12K128芯片测试的时候,rec_count总会莫名的多余接收的总字节数,如下图所示
截图202411251437089843.jpg
发送78078个字节数据,但是内部记录到的实际接收字节数是00 01 a0 fe换算成十进制就是106750, 这种情况发生在缓存设置成大于256字节时,当缓存设置小于256字节,比如128字节时,记录的数据量就正确,这个代码逻辑放在stm32上测试过,在DMA加持的情况下,能保证发送数据量和接收数据量一致。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:28
  • 最近打卡:2025-01-08 16:11:02

12

主题

26

回帖

224

积分

中级会员

积分
224
发表于 2024-11-25 14:41:54 | 显示全部楼层
补充一下初始化代码,不知道为什么自动删除了
  1. void UartInit()
  2. {
  3.         /* 配置P3.0和P3.1为准双向口 */
  4.         P3M0 &= ~0x03;
  5.         P3M1 &= ~0x03;
  6.        
  7.         /* 配置USART1映射到P3.0和P3.1 */
  8.         P_SW1 &= ~0xC0U;
  9.        
  10.         /* 配置USART1功能 */
  11.         SM0 = 0;                                //数据位8位
  12.         SM1 = 1;
  13.         SMOD = 0;                                //波特率不加倍
  14.         SMOD0 = 0;                                //禁用帧错误检测功能
  15.         S1BRT = 1;                                //选择定时器2作为波特率发生器
  16.         REN = 1;
  17.         ES = 0;                                        //关闭中断
  18.         EA = 0;                                        //全局中断关闭
  19.        
  20.         /* 波特率发生器配置 */
  21.         T2R = 0;                                //TIM2停止计时
  22.         ET2 = 0;                                //关闭TIM2中断
  23.         TM2PS = 0;                                //TIM2 36M时钟
  24.         T2x12 = 1;                                //TIM2工作1T模式
  25.         T2_CT = 0;                                //TIM2用作定时器
  26.         T2CLKO = 0;                                //关闭TIM2时钟输出
  27.         T2L = 0xEE;                         //设置自动重载值
  28.         T2H = 0xFF;
  29.         T2R = 1;                                //TIM2开始计时
  30.        
  31.         /* 配置USART1 TX DMA */
  32.         DMA_UR1T_CFG = 0x0A;       
  33.         DMA_UR1T_CR |= 0x80;
  34.         DMA_UR1T_STA = 0;
  35.         DMA_UR1T_AMT = (23&0x00FF);
  36.         DMA_UR1T_AMTH = ((23&0xFF00) >> 8);
  37.         DMA_UR1T_TXAH = ((unsigned short)&Uart_TxPacket[0]) >> 8;
  38.         DMA_UR1T_TXAL = (((unsigned short)&Uart_TxPacket[0])&0xFF);
  39.         /* 配置USART1 RX DMA */
  40.         DMA_UR1R_CFG = 0x0F;
  41.         DMA_UR1R_STA = 0;
  42.     DMA_UR1R_AMT = (1023 & 0xFF);
  43.         DMA_UR1R_AMTH = (1023>>8);
  44.         // DMA_UR1R_AMT = (1023UL & 0xFF);
  45.         // DMA_UR1R_AMTH = ((1023UL & 0xFF00) >> 8);
  46.         DMA_UR1R_RXAH = (((unsigned short)&Uart_RxBuf[0]) >> 8);
  47.         DMA_UR1R_RXAL = (((unsigned short)&Uart_RxBuf[0])&0xFF);
  48.         DMA_UR1R_CR |= 0xA1;
  49. }
复制代码
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:28
  • 最近打卡:2025-01-08 16:11:02

12

主题

26

回帖

224

积分

中级会员

积分
224
发表于 2024-11-25 14:43:23 | 显示全部楼层
补充一下处理代码,为啥会自动删除呀
  1. void DMARx_Handler()
  2. {
  3.         unsigned short DONEH = DMA_UR1R_DONEH;
  4.         unsigned short DONE = DMA_UR1R_DONE;
  5.         const unsigned short defaultCounter = 1024;
  6.        
  7.         /* 处理DMA接收逻辑 */
  8.         counter = ((DONEH << 8) + DONE);
  9.         if(counter > lastcounter)
  10.         {
  11.                 process_length = counter - lastcounter;
  12.                 rec_count += process_length;
  13.         }
  14.         else if(counter < lastcounter)
  15.         {
  16.                 process_length = ((defaultCounter + counter) - lastcounter);
  17.                 rec_count += process_length;
  18.         }
  19.         else
  20.         {
  21.                 process_length = 0;
  22.         }
  23.         lastcounter = counter;
  24. }
复制代码
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:28
  • 最近打卡:2025-01-08 16:11:02

12

主题

26

回帖

224

积分

中级会员

积分
224
发表于 2024-11-25 14:45:04 | 显示全部楼层
补充主函数代码
  1. void main()
  2. {
  3.         HardwareInit();
  4.         SoftwareInit();
  5.         while(1)
  6.         {
  7.                 DMARx_ISRHandler();
  8.                 DMARx_Handler();
  9.         }
  10. }
复制代码
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:54
  • 最近打卡:2025-05-01 09:07:55

717

主题

1万

回帖

1万

积分

管理员

积分
15613
发表于 2024-11-25 16:51:54 | 显示全部楼层
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 02:18 , Processed in 0.173331 second(s), 72 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表