文章转载自: http://blog.chinaunix.net/uid-26435987-id-3081120.html
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include "dma.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include "dma.h"
#define DMA_CHECK_ATTR 1
typedef struct{
volatile U32 DISRC; //0x0 //初始源基地址寄存器
volatile U32 DISRCC; //0x4 //初始源控制寄存器
volatile U32 DIDST; //0x8 //初始目的基地址寄存器
volatile U32 DIDSTC; //0xc //初始目的控制寄存器
volatile U32 DCON; //0x10 //DMA控制寄存器
volatile U32 DSTAT; //0x14 //状态/计数寄存器
volatile U32 DCSRC; //0x18 //当前源地址寄存器
volatile U32 DCDST; //0x1c //当前目的地址寄存器
volatile U32 DMASKTRIG; //0x20 // DMA屏蔽触发寄存器
volatile U32 DISRC; //0x0 //初始源基地址寄存器
volatile U32 DISRCC; //0x4 //初始源控制寄存器
volatile U32 DIDST; //0x8 //初始目的基地址寄存器
volatile U32 DIDSTC; //0xc //初始目的控制寄存器
volatile U32 DCON; //0x10 //DMA控制寄存器
volatile U32 DSTAT; //0x14 //状态/计数寄存器
volatile U32 DCSRC; //0x18 //当前源地址寄存器
volatile U32 DCDST; //0x1c //当前目的地址寄存器
volatile U32 DMASKTRIG; //0x20 // DMA屏蔽触发寄存器
}DMAReg;
//DMA寄存器结构体变量,用于描述某个DMA通道的9个寄存器
static struct{
U16 used; //DMA通道使用情况:忙/闲
U16 DevID; //请求DMA的外设ID号
DMAReg *pDMA; //DMA寄存器地址指针
}DMAChannel[MAX_DMA_CHANNEL]; //DMA通道信息数组,共4个(0--3)
U16 used; //DMA通道使用情况:忙/闲
U16 DevID; //请求DMA的外设ID号
DMAReg *pDMA; //DMA寄存器地址指针
}DMAChannel[MAX_DMA_CHANNEL]; //DMA通道信息数组,共4个(0--3)
/*********************************************************************************/
//attr高16位为设备ID,低16位的高8位为DMA传送源,目的属性(AHP/APB,INCREASE/FIX)低8位为
//attr高16位为设备ID,低16位的高8位为DMA传送源,目的属性(AHP/APB,INCREASE/FIX)低8位为
请求源,返回值失败为REQUEST_DMA_FAIL,
返回值成功高16位为设备ID,低8位为申请到的通道
31---------------------16-15---13------12---9------8-7------------4-3------------0
| 设备ID
| | DMA传送源 | | DMA请求源 |
DMA启动|目的信息| |源信息| | 请求源代号 | | 通道号 |
//********************************************************************************//
![](https://i-blog.csdnimg.cn/blog_migrate/05eb857b517070997a70f60fdd67af77.jpeg)
//DMA请求开关
U32 RequestDMASW(U32 attr, U32 mode)
{
U16 channel;
U32 ret;
attr &= ~0xff; //清attr低16位,只保留高16位设备ID
mode &= ~HW_TRIG; //关闭硬件请求模式
请求源------> 0 1 2 3 4
通道号
ch-0: 0x0, 0x1, 0x2, 0x3, 0x4
ch-1:0x10,0x11,0x12,0x13,0x14
ch-2:0x20,0x21,0x22,0x23,0x24
ch-3:0x30,0x31,0x32,0x33,0x34 (查看头文件dma.h)
for(channel=0; channel<(MAX_DMA_CHANNEL*0x10); channel+=0x10)
for(channel=0; channel<(MAX_DMA_CHANNEL*0x10); channel+=0x10)
{
ret = RequestDMA(attr|channel,mode); //更新attr
if(ret!=REQUEST_DMA_FAIL)
break;
}
return ret; //返回值为请求的信息
}
//请求DMA
U32 RequestDMA(U32 attr, U32 mode)
{
U16 DevID, ReqSrc, ch;
U32 ret=REQUEST_DMA_FAIL, r;
DevID = attr>>16; //取attr高16位,为设备ID号
ReqSrc = attr&0xff; //取attr低8位,为请求源信息,其中,低四位为请求源代号[0--4];高四位为通道号[0--3](看上面讲述)
if(((ReqSrc>>4)>=MAX_DMA_CHANNEL)||((ReqSrc&0xf)>4)) //如果通道号>=4或请求源代号>4,无意义
ret = RequestDMA(attr|channel,mode); //更新attr
if(ret!=REQUEST_DMA_FAIL)
break;
}
return ret; //返回值为请求的信息
}
//请求DMA
U32 RequestDMA(U32 attr, U32 mode)
{
U16 DevID, ReqSrc, ch;
U32 ret=REQUEST_DMA_FAIL, r;
DevID = attr>>16; //取attr高16位,为设备ID号
ReqSrc = attr&0xff; //取attr低8位,为请求源信息,其中,低四位为请求源代号[0--4];高四位为通道号[0--3](看上面讲述)
if(((ReqSrc>>4)>=MAX_DMA_CHANNEL)||((ReqSrc&0xf)>4)) //如果通道号>=4或请求源代号>4,无意义
return ret;
//返回REQUEST_DMA_FAIL,表示请求失败
EnterCritical(&r); //进入临界区,现场保护,不允许其他中断发生
if(DMAChannel[ReqSrc>>4].used!=DMA_IS_FREE) //判断DMA通道使用情况:忙/闲,如果忙,执行if程序
{
U8 src = ReqSrc;
if(src==REQ_IISDI) //REQ_IISDI的信息为0x21,代表2通道请求源1
{
if(DMAChannel[2].used!=DMA_IS_FREE) //判断DMA2通道使用情况:忙/闲
goto RequestDmaExit;
else
ReqSrc = 0x21; //给ReqSrc赋值为0x21,表示2通道请求源1
}
else if(src==REQ_SDI) //REQ_SDI的信息为0x2,代表0通道请求源2
{
if(DMAChannel[2].used!=DMA_IS_FREE) //判断DMA2通道使用情况:忙/闲
{
if(DMAChannel[3].used!=DMA_IS_FREE) //判断DMA3通道使用情况:忙/闲
goto RequestDmaExit;
else
ReqSrc = 0x31; //给ReqSrc赋值为0x31,表示3通道请求源1
}
else
ReqSrc = 0x22; //给ReqSrc赋值为0x22,表示2通道请求源2
}
else if(src==REQ_SPI) //REQ_SPI的信息为0x13,表示1通道请求源3
{
if(DMAChannel[3].used!=DMA_IS_FREE) //判断DMA3通道的使用情况
goto RequestDmaExit;
else
ReqSrc = 0x32; //给ReqSrc赋值为0x32,表示3通道请求源2
}
else if(src==REQ_TIMER) //REQ_TIMER的信息为0x3,表示0通道请求源3
{
if(DMAChannel[2].used!=DMA_IS_FREE) //判断DMA2通道的使用情况
{
if(DMAChannel[3].used!=DMA_IS_FREE) //判断DMA3通道的使用情况
goto RequestDmaExit;
else
ReqSrc = 0x33; //给ReqSrc赋值为0x33,表示3通道请求源3
}
else
ReqSrc = 0x23; //给ReqSrc赋值为0x23,表示2通道请求源3
}
else
goto RequestDmaExit; //如果不是REQ_IISDI,REQ_SDI,REQ_SPI,REQ_TIMER,退出
}
ch = ReqSrc>>4; //申请到的通道号
;接下来的代码功能:区别请求的外设编号(if-else分支结构选择)
if(mode&HW_TRIG) //如果DMA请求源为硬件
DMAChannel[ch].used = DMA_IS_HWTRIG;
else //如果DMA请求源为软件
DMAChannel[ch].used = DMA_IS_SWTRIG; //改写DMA状态为忙(软件/硬件)
DMAChannel[ch].DevID = DevID; //取DMA设备ID
DMAChannel[ch].pDMA = (DMAReg *)(0x4b000000+(ch)*0x40); //赋DMA寄存器的地址
DMAChannel[ch].pDMA->DMASKTRIG = 1<<2; //当一个基本操作完成后立即停止DMA操作
DMAChannel[ch].pDMA->DISRCC = (attr>>8)&3;
//获取源信息(???)
DMAChannel[ch].pDMA->DIDSTC = (attr>>12)&3; //获取目标信息(???)
mode &= ~0x07000000; //某DMA通道请求源选择位000
mode |= (ReqSrc&0x7)<<24; //换成某通道某模式
DMAChannel[ch].pDMA->DCON = mode;
DMAChannel[ch].pDMA->DIDSTC = (attr>>12)&3; //获取目标信息(???)
mode &= ~0x07000000; //某DMA通道请求源选择位000
mode |= (ReqSrc&0x7)<<24; //换成某通道某模式
DMAChannel[ch].pDMA->DCON = mode;
//DbgOut("Request DMA %x success\n", ReqSrc);
ret = (DevID<<16)|ReqSrc; //请求成功
ret = (DevID<<16)|ReqSrc; //请求成功
RequestDmaExit:
ExitCritical(&r); //退出临界区,返回请求失败信息
return ret;
}
ExitCritical(&r); //退出临界区,返回请求失败信息
return ret;
}
//*****************************************************
//DMA的有关开关函数
//****************************************************//
//(释放DMA)这个函数主要通过写DMASKTRIG寄存器关闭DMA通道并写相应通道的状态为空闲
U16 ReleaseDMA(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR //如果DMA_CHECK_ATTR定义过
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return 1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return 1;
#endif
DMAChannel[ch].pDMA->DMASKTRIG = 0; //4; //stop dma and channel off
DMAChannel[ch].used = DMA_IS_FREE;
return 0;
}
//DMA的有关开关函数
//****************************************************//
//(释放DMA)这个函数主要通过写DMASKTRIG寄存器关闭DMA通道并写相应通道的状态为空闲
U16 ReleaseDMA(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR //如果DMA_CHECK_ATTR定义过
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return 1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return 1;
#endif
DMAChannel[ch].pDMA->DMASKTRIG = 0; //4; //stop dma and channel off
DMAChannel[ch].used = DMA_IS_FREE;
return 0;
}
//(开始DMA)这个函数可以根据硬件/软件请求模式通过写DMASKTRIG寄存器打开DMA通道
U16 StartDMA(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return 1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return 1;
#endif
if(DMAChannel[ch].used==DMA_IS_HWTRIG)
DMAChannel[ch].pDMA->DMASKTRIG = 2; //开启DMA通道
if(DMAChannel[ch].used==DMA_IS_SWTRIG)
DMAChannel[ch].pDMA->DMASKTRIG = 3; //开启DMA通道,(软件模式)触发DMA操作
return 0;
}
U16 StartDMA(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return 1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return 1;
#endif
if(DMAChannel[ch].used==DMA_IS_HWTRIG)
DMAChannel[ch].pDMA->DMASKTRIG = 2; //开启DMA通道
if(DMAChannel[ch].used==DMA_IS_SWTRIG)
DMAChannel[ch].pDMA->DMASKTRIG = 3; //开启DMA通道,(软件模式)触发DMA操作
return 0;
}
//(停止DMA)这个函数直接将DMASKTRIG寄存器第三位赋1,即bit[2]=1,stops as soon as the current
atomic transfer ends. If there is no current running atomic transfer, DMA stops immediately. The CURR_TC, CURR_SRC, and CURR_DST will be 0。
U16 StopDMA(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return 1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return 1;
#endif
atomic transfer ends. If there is no current running atomic transfer, DMA stops immediately. The CURR_TC, CURR_SRC, and CURR_DST will be 0。
U16 StopDMA(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return 1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return 1;
#endif
DMAChannel[ch].pDMA->DMASKTRIG = 1<<2;
//当一个基本操作完成后立即停止DMA操作
return 0;
}
//(设置DMA运行状态)这个函数开启一个DMA过程的准备工作:读取源地址,读取目标地址,初始化计数器,读取数据长度并赋值给计数器,将相关通道状态改写为忙。
U16 SetDMARun(U32 attr, U32 src_addr, U32 dst_addr, U32 len)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return 1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return 1;
#endif
DMAChannel[ch].pDMA->DISRC = src_addr;
DMAChannel[ch].pDMA->DIDST = dst_addr;
DMAChannel[ch].pDMA->DCON &= ~0xfffff; //先将DCON[19:0]=TC对应的DMA计数值为0
DMAChannel[ch].pDMA->DCON |= len&0xfffff; //重新赋值给DCON[19:0]=TC
if(attr&DMA_START)
{
if(DMAChannel[ch].used==DMA_IS_HWTRIG)
DMAChannel[ch].pDMA->DMASKTRIG = 2; //开启DMA通道
if(DMAChannel[ch].used==DMA_IS_SWTRIG)
DMAChannel[ch].pDMA->DMASKTRIG = 3; //开启DMA通道,(软件模式)触发DMA操作
}
return 0;
}
//(查询DMA启动状态)读取DMA状态寄存器当前的状态:忙/闲;计数器的现值
U32 QueryDMAStat(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return -1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return -1;
#endif
return 0;
}
//(设置DMA运行状态)这个函数开启一个DMA过程的准备工作:读取源地址,读取目标地址,初始化计数器,读取数据长度并赋值给计数器,将相关通道状态改写为忙。
U16 SetDMARun(U32 attr, U32 src_addr, U32 dst_addr, U32 len)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return 1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return 1;
#endif
DMAChannel[ch].pDMA->DISRC = src_addr;
DMAChannel[ch].pDMA->DIDST = dst_addr;
DMAChannel[ch].pDMA->DCON &= ~0xfffff; //先将DCON[19:0]=TC对应的DMA计数值为0
DMAChannel[ch].pDMA->DCON |= len&0xfffff; //重新赋值给DCON[19:0]=TC
if(attr&DMA_START)
{
if(DMAChannel[ch].used==DMA_IS_HWTRIG)
DMAChannel[ch].pDMA->DMASKTRIG = 2; //开启DMA通道
if(DMAChannel[ch].used==DMA_IS_SWTRIG)
DMAChannel[ch].pDMA->DMASKTRIG = 3; //开启DMA通道,(软件模式)触发DMA操作
}
return 0;
}
//(查询DMA启动状态)读取DMA状态寄存器当前的状态:忙/闲;计数器的现值
U32 QueryDMAStat(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return -1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return -1;
#endif
return DMAChannel[ch].pDMA->DSTAT;
//STAT[21:20]为DMA控制器的状态,CURR_TC[19:0]为当前DMA计数器的值
}
//(查询DMA当前源寄存器状态)返回源的地址
U32 QueryDMASrc(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return -1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return -1;
#endif
}
//(查询DMA当前源寄存器状态)返回源的地址
U32 QueryDMASrc(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return -1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return -1;
#endif
return DMAChannel[ch].pDMA->DCSRC;
//CURR_SRC[30:0]为当前DMA通道的源地址值
}
//(查询DMA当前目的寄存器状态)返回目标地址
U32 QueryDMADst(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return -1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return -1;
#endif
}
//(查询DMA当前目的寄存器状态)返回目标地址
U32 QueryDMADst(U32 attr)
{
U16 DevID, ReqSrc, ch;
DevID = attr>>16; //DMA设备ID
ReqSrc = attr&0xf; //DMA请求源代号[0--4]
ch = (attr&0xf0)>>4; //DMA通道选择[0--3]
#if DMA_CHECK_ATTR
if((ch>=MAX_DMA_CHANNEL)||(ReqSrc>4))
return -1;
if((DMAChannel[ch].used==DMA_IS_FREE)||(DMAChannel[ch].DevID!=DevID))
return -1;
#endif
return DMAChannel[ch].pDMA->DCDST;
//CURR_DST[30:0]为当前DMA通道的目的地址值
}