程序实现:
DMA的使用主要是DMA寄存器的初始设置,设置完成后,DMA接到触发信号即可自动传输数据。
设置函数如下:
void DMAInit(char channel,char trigger,char transMode,char srcMode,char dstMode,
unsigned int src,unsigned int dst,unsigned int size)
{
unsigned int *DMAxCTL,*DMAxSA,*DMAxDA,*DMAxSZ;
DMACTL0 = trigger 《《 (channel 《《 2);
DMACTL1 = 0x04; //DMA收到触发请求时,等待当前指令执行完成后
switch (channel) //选择当前设置哪个DMA通道
{
case 0:
DMAxCTL = (unsigned int *)&DMA0CTL;
DMAxSA = (unsigned int *)&DMA0SA;
DMAxDA = (unsigned int *)&DMA0DA;
DMAxSZ = (unsigned int *)&DMA0SZ;
break; //指针 = 0通道控制
case 1:
DMAxCTL = (unsigned int *)&DMA1CTL;
DMAxSA = (unsigned int *)&DMA1SA;
DMAxDA = (unsigned int *)&DMA1DA;
DMAxSZ = (unsigned int *)&DMA1SZ;
break; //指针 = 1通道控制
case 2:
DMAxCTL = (unsigned int *)&DMA2CTL;
DMAxSA = (unsigned int *)&DMA2SA;
DMAxDA = (unsigned int *)&DMA2DA;
DMAxSZ = (unsigned int *)&DMA2SZ;
break; //指针 = 2通道控制
}
switch (transMode) //设置DMA通道的传输模式
{
case ‘S’: *DMAxCTL = DMADT_0; break; //单次传输
case ‘s’: *DMAxCTL = DMADT_4; break; //重复单次传输
case ‘B’: *DMAxCTL = DMADT_1; break; //块传输
case ‘b’: *DMAxCTL = DMADT_5; break; //重复块传输
case ‘I’: *DMAxCTL = DMADT_2; break; //突发块传输 交错
case ‘i’: *DMAxCTL = DMADT_6; break; //重复突发块传输 交错
}
*DMAxCTL |= (srcMode & 0x04) 《《 2; //源 字或字节
*DMAxCTL |= (srcMode & 0x03) 《《 8; //源 地址改变方式
*DMAxCTL |= (dstMode & 0x04) 《《 3; //目的 字或字节
*DMAxCTL |= (dstMode & 0x03) 《《 10; //目的 地址改变方式
*DMAxSA = src;
*DMAxDA = dst;
*DMAxSZ = size;
*DMAxCTL |= DMAEN; //DMA使能
}
函数比较麻烦,函数内容按参数设置每个寄存器。DMACTL0 = trigger 《《 (channel 《《 2); 这个是设置对应channel通道的的参考源,不大明白的可以看下DMACTL0的寄存器内容;switch (channel)语句则根据通道设置对应指针指向的寄存器;然后对应设置参数即可。
当设置成非重复模式时,需要重新置位DMAEN,本程序就函数DMAReEnable实现:
void DMAReEnable(char channel)
{
switch (channel) //使能对应通道
{
case 0: DMA0CTL |= DMAEN; break; //0通道
case 1: DMA1CTL |= DMAEN; break; //1通道
case 2: DMA2CTL |= DMAEN; break; //2通道
}
}
这个函数比较简单,只是根据传入参数设置对应通道的DMAEN位。
当设置为软件触发时,需要软件启动DMA程序如下:
void DMAStart(char channel)
{
switch (channel) //使能对应通道
{
case 0: DMA0CTL |= DMAREQ; break; //0通道
case 1: DMA1CTL |= DMAREQ; break; //1通道
case 2: DMA2CTL |= DMAREQ; break; //2通道
}
}
这个和上个函数类似:仅仅设置一个控制位,函数很简单,不再解释啦。
程序实现就这么多了,有关详细内容可以下载附件里的程序库,程序的注释很详细。
使用示例:
使用这个程序时,步骤和原来的相同:工程中加入DMA.c文件,然后源文件中包含DMA.h头文件即可。
示例程序主要如下:
#include 《msp430x16x.h》
#include “DMA.h”
unsigned int a[5] = {8693,5689,2356,23565,5656};
unsigned int b[5];
void main( void )
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
ClkInit();
//块传输,5个字(16位) a-》b
DMAInit(0,0x00,‘B’,3,3,(unsigned int)a,(unsigned int)b,5);
DMAStart(0);
//如果需要再次传输 而不改变设置,只需调用DMAReEnable再次启动传输即可
// 如果是重复块传输,则不需要重新使能DMAReEnable 直接启动即可
//这里仅仅演示了使用方法,实际应用中,应根据需要选择适当的触发源。
//
LPM0;
}
示例程序完成功能很简单,仅仅把一个数组的值赋给另外一个数组。数组地址即是数组名强制转换为所需类型(无符号16位),传入函数初始化设置。这里为了简便,设置为软件启动。
运行效果如下:
单步运行完启动DMA传输后,结果即出来了;说明DMA传输数据的速度是很快的。
DMA可以用于对速度要求比较高的程序中。例如:DMA配合硬件乘法器和ADC12模块,可以很容易的实现比较高频率的数字滤波方案。
评论
查看更多