jrh200310 发表于 2025-10-3 18:07:27

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

//========================================================================
// 函数: 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
// 日期:
// 备注:
u8uart1_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),用全局定义在内部直接配置就能正常发送。求助!




国芯人工智能 发表于 2025-10-3 18:08:00

您好,关于您在使用国芯AI8051 8位MCU进行UART1 DMA配置时遇到的“发送地址发数据错误”问题,以下从硬件配置、代码逻辑、常见错误点及建议调试方法几个方面进行专业分析,供您参考。

一、问题定位分析

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

此外,发送地址配置部分采用了如下代码:

c
DMAUR1TTXAH = (u8)((u16)&DmaUart1TXBuffer >> 8);
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. 使用正确的地址计算方式

c
extern u8 DmaUart1TXBuffer[]; // 确保缓冲区已在别处定义

DMAUR1TTXAH = (u8)((u16)DmaUart1TXBuffer >> 8);// 注意去掉取址符&,数组名即为地址
DMAUR1TTXAL = (u8)((u16)DmaUart1TXBuffer & 0xFF);
说明:若DmaUart1TXBuffer为数组,使用其数组名即可代表其起始地址;若为指针,应使用DmaUart1TXBuffer或DmaUart1TXBuffer本身(根据上下文判断)。

2. 参数未使用问题

函数定义中参数u8 Uart1TxBuff, u8 Uart1RxBuff未使用,建议删除或用于动态配置缓冲区地址:

c
void DMAUart1Config(u8 txBuff, u16 txLen)
{
    u16 addr = (u16)txBuff;

    DMAUR1TTXAH = (u8)(addr >> 8);
    DMAUR1TTXAL = (u8)(addr & 0xFF);

    DMAUR1TAMT = (u8)(txLen - 1);      // 假设传输长度为n+1
    DMAUR1TAMTH = (u8)((txLen - 1) >> 8);

    DMAUR1TCFG = 0x00;
    DMAUR1TSTA = 0x00;
    DMAUR1TCR = 0x80;
}

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

确保在调用DMA配置函数前,UART1和DMA模块的时钟已正确开启:

c
CLKCON |= 0x04;// 使能DMA时钟
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助手

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

ercircle 发表于 2025-10-3 19:19:18

对指针取地址操作,错误。直接对指针转u16。



jrh200310 发表于 2025-10-4 08:25:58

ercircle 发表于 2025-10-3 19:19
对指针取地址操作,错误。直接对指针转u16。

感谢指出我的问题,已解决
页: [1]
查看完整版本: AI8051 8位模式 UART1 DMA配置发送地址发数据错误 | 已解决