1. DMA实验概述
DMA(Direct Memory Access)直接存储器访问是DSP28335芯片中一个极为重要的外设模块,它允许数据在外设和存储器之间直接传输而无需CPU干预。这个特性在实时信号处理系统中尤为关键,比如在电机控制、电力电子或音频处理等场景中,数据吞吐量大且对时序要求严格。
我在工业伺服驱动器开发中就深刻体会到了DMA的价值。当时需要同时处理编码器反馈、PWM输出和ADC采样,如果全部通过CPU搬运数据,即使28335跑在150MHz主频下也会捉襟见肘。后来将ADC结果通过DMA传输到指定内存区域,CPU只需处理运算逻辑,系统实时性立即提升了40%以上。
2. 实验环境搭建
2.1 硬件准备清单
- 普中DSP28335开发板(核心板+底板)
- XDS100v2仿真器(或更高版本)
- USB转串口模块(用于调试输出)
- 示波器(可选,用于观察时序)
特别注意:开发板供电要稳定,建议使用配套电源适配器而非USB供电。我在早期测试时就遇到过因供电不足导致DMA传输不稳定的情况。
2.2 软件工具链配置
- CCS开发环境:建议使用Code Composer Studio v6以上版本
- ControlSUITE安装:从TI官网获取最新DSP2833x库
- 串口终端软件:Putty或Tera Term,波特率设置为115200
在CCS中新建工程时,务必包含以下关键库文件:
DSP2833x_DMA.h/cDSP2833x_Device.hDSP2833x_Examples.h
3. DMA寄存器详解
3.1 核心控制寄存器组
DSP28335的DMA控制器有6个独立通道,每个通道都有完整的寄存器组:
| 寄存器名 | 地址偏移 | 功能描述 |
|---|---|---|
| DMACCR | 0x00 | 通道控制寄存器 |
| DMACICR | 0x02 | 中断控制寄存器 |
| DMACSR | 0x03 | 状态寄存器 |
| DMATCDMA_SRC | 0x04 | 传输源地址 |
| DMATCDMA_DST | 0x06 | 传输目的地址 |
| DMATCDMA_TRANS | 0x08 | 传输数据量配置 |
3.2 关键位域解析
以DMACCR寄存器为例,几个关键配置位需要特别注意:
c复制// 典型配置示例
DmaRegs.CH1.DMACCR.all = 0x0000;
DmaRegs.CH1.DMACCR.bit.CHINT = 0; // 中断使能
DmaRegs.CH1.DMACCR.bit.CONTINUOUS = 1;// 连续模式
DmaRegs.CH1.DMACCR.bit.SYNCE = 1; // 同步事件使能
DmaRegs.CH1.DMACCR.bit.SYNCSEL = 4; // 选择ADC为同步源
4. 实验代码实现
4.1 DMA初始化流程
完整的DMA通道初始化应遵循以下步骤:
-
外设时钟使能:
c复制EALLOW; SysCtrlRegs.PCLKCR0.bit.DMAENCLK = 1; // 开启DMA时钟 EDIS; -
通道复位:
c复制DmaRegs.CH1.DMACTRL.bit.HARD_RESET = 1; DELAY_US(10); DmaRegs.CH1.DMACTRL.bit.HARD_RESET = 0; -
地址配置:
c复制DmaRegs.CH1.DMATCDMA_SRC.all = (Uint32)&AdcMirror.ADCRESULT0; DmaRegs.CH1.DMATCDMA_DST.all = (Uint32)&AdcBuffer[0]; DmaRegs.CH1.DMATCDMA_TRANS.all = ADC_BUFFER_SIZE;
4.2 中断服务程序
DMA传输完成中断的处理要点:
c复制interrupt void DMA_CH1_ISR(void)
{
// 清除中断标志
DmaRegs.CH1.DMACSR.bit.CHINT = 1;
// 数据处理逻辑
ProcessAdcData();
// 重新使能DMA
DmaRegs.CH1.DMACCR.bit.CHINT = 0;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP7;
}
5. 典型应用场景
5.1 ADC采样数据搬运
在电机控制系统中,通常需要高速采集三相电流。通过DMA将ADC结果直接搬运到指定缓冲区,可以大幅降低CPU开销:
- 配置ADC序列采样模式
- 设置DMA源地址为ADC结果寄存器
- 目的地址指向环形缓冲区
- 每次ADC转换完成触发DMA传输
5.2 串口大数据传输
当需要通过串口传输大量数据(如固件升级)时,DMA可以自动搬运数据到SCITXBUF寄存器:
c复制// 配置DMA到SCIA发送
DmaRegs.CH2.DMATCDMA_SRC = (Uint32)&FirmwareData[0];
DmaRegs.CH2.DMATCDMA_DST = (Uint32)&SciaRegs.SCITXBUF;
DmaRegs.CH2.DMACCR.bit.SYNCSEL = 8; // SCIA TX为同步事件
6. 调试技巧与常见问题
6.1 传输异常排查步骤
-
检查时钟使能:
c复制if(SysCtrlRegs.PCLKCR0.bit.DMAENCLK != 1){ DebugPrint("DMA时钟未开启!"); } -
验证地址对齐:
- 源地址和目的地址必须16位对齐
- 传输数据量必须是偶数
-
同步事件确认:
- 使用示波器观察同步信号
- 检查SYNCSEL配置是否正确
6.2 性能优化建议
-
使用PING-PONG缓冲区:
c复制#define BUF_SIZE 256 Uint16 PingBuffer[BUF_SIZE], PongBuffer[BUF_SIZE]; volatile Uint8 ActiveBuffer = 0; // 0:Ping, 1:Pong -
合理设置中断优先级:
- DMA中断优先级应低于关键控制中断(如PWM)
- 但高于非实时性任务(如通信协议)
-
内存访问优化:
- 将DMA缓冲区分配到SARAM而非外部存储器
- 使用
#pragma DATA_SECTION指定存储区域
7. 进阶应用:多通道协同
7.1 级联传输配置
对于需要多级处理的数据流,可以配置DMA通道级联:
- 通道1负责从ADC搬运原始数据
- 通道1完成触发通道2启动
- 通道2将数据搬运到算法处理区
- 通道2完成触发CPU中断
配置关键代码:
c复制// 通道1完成触发通道2
DmaRegs.CH1.DMACCR.bit.CHINT = 1;
DmaRegs.CH2.DMACCR.bit.PERINT = 1;
DmaRegs.CH2.DMACCR.bit.PERINTSEL = 1; // 选择通道1为触发源
7.2 与CLA协同工作
在复杂系统中,可以结合CLA(控制律加速器)和DMA构建高效处理流水线:
- DMA将ADC数据搬运到CLA专用内存
- 触发CLA进行实时算法处理
- DMA将处理结果搬运到输出缓冲区
- 整个过程无需CPU干预
这种架构在数字电源控制中特别有效,我在某光伏逆变器项目中实测可将控制周期从50μs缩短到15μs。