找回密码
 立即注册
查看: 84|回复: 3

AI8051 8位模式 UART1 DMA配置发送地址发数据错误 | 已解决

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:11
  • 最近打卡:2025-10-09 17:35:45
已绑定手机

6

主题

9

回帖

158

积分

注册会员

积分
158
发表于 2025-10-3 18:07:27 | 显示全部楼层 |阅读模式
//========================================================================
// 函数: void DMA_Config(void)
// 描述: UART DMA 功能配置.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2024-5-6
//========================================================================
void DMA_Uart1Config(u8 *Uart1TxBuff,u8 *Uart1RxBuff)
{
    DMA_UR1T_CFG = 0x00;        //bit7 0:Disable Interrupt
    DMA_UR1T_STA = 0x00;
    DMA_UR1T_AMT = 0xff;        //设置传输总字节数(低8位):n+1
    DMA_UR1T_AMTH = 0x01;       //设置传输总字节数(高8位):n+1
    DMA_UR1T_TXAH = (u8)((u16)&DmaUart1TXBuffer >> 8);
    DMA_UR1T_TXAL = (u8)((u16)&DmaUart1TXBuffer);
    DMA_UR1T_CR = 0x80;         //bit7 1:使能 UART1_DMA, bit6 1:开始 UART1_DMA 自动发送

    DMA_UR1R_CFG = 0x00;        //bit7 0:Disable Interrupt
    DMA_UR1R_STA = 0x00;
    DMA_UR1R_AMT = 0xff;        //设置传输总字节数(低8位):n+1
    DMA_UR1R_AMTH = 0x03;       //设置传输总字节数(高8位):n+1
    DMA_UR1R_RXAH = (u8)((u16)&Uart1RxBuff >> 8);
    DMA_UR1R_RXAL = (u8)((u16)&Uart1RxBuff);
    DMA_UR1R_CR = 0xa1;         //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
}

根据例程改的,写了一个发送代码。上面的是配置函数,只要把内部的地址改成函数上传递参数的地址就出错。



//========================================================
// 函数: uart1_dma_send(u8 brt)
// 描述: 串口1发送数据
// 参数: *flag  输入标志位   *pbuff
// 返回: 0 发送正常    1发送异常
// 版本: VER1.0
// 日期:
// 备注:
u8  uart1_dma_send(u8 *flag,u16 len)
{
          u16 i ;
          i = len ;
    if(*flag == 1 )
                {
                         //  printf("flag == 1\n");
                           *flag = 0;
                           TI = 0; //清除发送标志(DMA发送完不会自动清除标志位)
                           i--;    //传输字节设置为(i-1)个数据 ;
                     DMA_UR1T_CFG = 0x80;        //bit7 0:Disable Interrupt
         DMA_UR1T_STA = 0x00;
         
       //  DMA_UR1T_TXAH = (u8)((u16)&senddata >> 8);
       //  DMA_UR1T_TXAL = (u8)((u16)&senddata);
                        
                           DMA_UR1T_AMT = (u8)i;       //设置传输总字节数(低8位):n+1
         DMA_UR1T_AMTH = (u8)(i>>8); //设置传输总字节数(高8位):n+1
         DMA_UR1T_CR = 0xc0;         //bit7 1:使能 UART1_DMA, bit6 1:开始 UART1_DMA 自动发送
         //DMA_UR1R_CR = 0xa1;         //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
               
                        
                          return 0 ;
                }
    else
                {
                        //  printf("flag == 0\n");
                   return 1 ;
               
                }

}

上面是DMA发送函数。



输出表现为把发送缓存的地址用参数传递就出错,void DMA_Uart1Config(u8 *Uart1TxBuff,u8 *Uart1RxBuff),用全局定义在内部直接配置就能正常发送。求助!




串口1使用DMA中断模式与电脑收发测试-超时中断.rar

169.89 KB, 下载次数: 8

回复

使用道具 举报 送花

3

主题

1880

回帖

608

积分

等待验证会员

积分
608
发表于 2025-10-3 18:08:00 | 显示全部楼层
您好,关于您在使用国芯AI8051 8位MCU进行UART1 DMA配置时遇到的“发送地址发数据错误”问题,以下从硬件配置、代码逻辑、常见错误点及建议调试方法几个方面进行专业分析,供您参考。

一、问题定位分析

您提供的代码片段中,函数名为DMAUart1Config,参数为两个u8类型变量Uart1TxBuff和Uart1RxBuff,但这两个参数并未在函数体内使用,这可能是潜在的问题来源之一。

此外,发送地址配置部分采用了如下代码:
  1. c
  2. DMAUR1TTXAH = (u8)((u16)&DmaUart1TXBuffer >> 8);
  3. DMAUR1TTXAL = (u8)((u16)&DmaUart1TXBuffer);
复制代码

该段代码的目的是将发送缓冲区DmaUart1TXBuffer的地址拆分为高8位和低8位,分别写入DMA的发送地址寄存器高位和低位。但存在以下几个可能的问题:

1. 地址取值方式是否正确?
若DmaUart1TXBuffer为局部变量或未正确声明为全局数组/指针,其地址可能未被正确解析。
需确认DmaUart1TXBuffer是否为数组类型,且具有固定内存地址。

2. DMA地址寄存器是否支持16位地址?
若芯片DMA模块仅支持8位地址宽度(如低端MCU),则无法支持大于256字节的缓冲区。
您配置了DMAUR1TAMT = 0xff; DMAUR1TAMTH = 0x01;,表示传输长度为0x01FF(511字节),需确保地址寄存器也支持16位寻址。

3. 编译器优化导致地址未被正确计算?
某些编译器在优化时可能对地址计算进行简化或重排,建议使用volatile关键字或查看反汇编确认地址是否正确。

二、建议修改方案

1. 使用正确的地址计算方式
  1. c
  2. extern u8 DmaUart1TXBuffer[]; // 确保缓冲区已在别处定义
  3. DMAUR1TTXAH = (u8)((u16)DmaUart1TXBuffer >> 8);  // 注意去掉取址符&,数组名即为地址
  4. DMAUR1TTXAL = (u8)((u16)DmaUart1TXBuffer & 0xFF);
复制代码
说明:若DmaUart1TXBuffer为数组,使用其数组名即可代表其起始地址;若为指针,应使用DmaUart1TXBuffer或DmaUart1TXBuffer本身(根据上下文判断)。

2. 参数未使用问题

函数定义中参数u8 Uart1TxBuff, u8 Uart1RxBuff未使用,建议删除或用于动态配置缓冲区地址:
  1. c
  2. void DMAUart1Config(u8 txBuff, u16 txLen)
  3. {
  4.     u16 addr = (u16)txBuff;
  5.     DMAUR1TTXAH = (u8)(addr >> 8);
  6.     DMAUR1TTXAL = (u8)(addr & 0xFF);
  7.     DMAUR1TAMT = (u8)(txLen - 1);      // 假设传输长度为n+1
  8.     DMAUR1TAMTH = (u8)((txLen - 1) >> 8);
  9.     DMAUR1TCFG = 0x00;
  10.     DMAUR1TSTA = 0x00;
  11.     DMAUR1TCR = 0x80;
  12. }
复制代码

3. 检查DMA和UART1的时钟使能

确保在调用DMA配置函数前,UART1和DMA模块的时钟已正确开启:
  1. c
  2. CLKCON |= 0x04;  // 使能DMA时钟
  3. PCON |= 0x10;    // 使能UART1
复制代码

三、常见错误点总结

| 错误类型 | 描述 | 解决方法 |
|----------|------|----------|
| 地址错误 | 缓冲区地址未正确传入或未对齐 | 使用全局数组或显式指针,确认地址正确 |
| 传输长度溢出 | 设置长度超过DMA支持范围 | 查阅手册确认最大传输长度 |
| 未初始化UART | UART未正确配置波特率、模式等 | 检查UART初始化函数 |
| 中断未使能 | 发送完成中断未处理 | 若需中断,设置DMAUR1TCFG |= 0x80; |
| 编译器优化问题 | 地址被优化或未正确计算 | 使用volatile或查看反汇编 |

四、调试建议

1. 使用调试器查看寄存器值
检查DMAUR1TTXAH与DMAUR1TTXAL是否写入了正确的地址。
观察DMAUR1TSTA是否反映DMA传输状态(如是否完成)。

2. 使用示波器或逻辑分析仪监测UART输出
确认是否有数据发出,数据内容是否与预期一致。

3. 打印调试信息
若系统支持串口打印,可在DMA传输前后打印调试信息,确认执行流程。

4. 最小系统测试
使用最小缓冲区(如2字节)测试DMA是否能正常发送。

五、结语

DMA配置在嵌入式系统中是提升效率的重要手段,但也因其与硬件强相关而容易出错。建议在开发过程中严格遵循芯片手册规范,结合调试工具进行逐项验证。若您能提供更多上下文(如缓冲区定义、DMA手册片段等),可进一步帮助定位问题。

如需完整DMA+UART1配置示例代码或芯片手册分析,欢迎继续提问。

祝开发顺利!

—— 国芯AI助手

[本文内容由国芯人工智能辅助生成,仅供参考]
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:328
  • 最近打卡:2025-10-15 08:50:20
已绑定手机

85

主题

3256

回帖

7196

积分

荣誉版主

无情的代码机器

积分
7196
发表于 2025-10-3 19:19:18 | 显示全部楼层
指针取地址操作,错误。直接对指针转u16。


截图202510031918192726.jpg
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:11
  • 最近打卡:2025-10-09 17:35:45
已绑定手机

6

主题

9

回帖

158

积分

注册会员

积分
158
发表于 2025-10-4 08:25:58 | 显示全部楼层
erci*** 发表于 2025-10-3 19:19
对指针取地址操作,错误。直接对指针转u16。

感谢指出我的问题,已解决
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-10-16 05:35 , Processed in 0.143284 second(s), 65 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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