Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1146635
  • 博文数量: 177
  • 博客积分: 761
  • 博客等级: 上士
  • 技术积分: 1518
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-04 22:37
文章分类

全部博文(177)

文章存档

2017年(1)

2016年(3)

2015年(33)

2014年(48)

2013年(60)

2012年(32)

分类: 嵌入式

2013-03-14 14:25:05

原文地址:mini2440裸机之DMA 作者:

#include "def.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屏蔽触发寄存器
}DMAReg;     //DMA寄存器结构体变量,用于描述某个DMA通道的9个寄存器
static struct{
 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位为
请求源,返回值失败为REQUEST_DMA_FAIL,返回值成功高16位为设备ID,低8位为申请到的通道
31---------------------16-15---13------12---9------8-7------------4-3------------0
        设备ID        |  |        DMA传送源      | |        DMA请求源          |
                        DMA启动|目的信息|   |源信息| | 请求源代号 | | 通道号     |     
//********************************************************************************//
 

//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) 
 {
  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; 
//DbgOut("Request DMA %x success\n", ReqSrc);
 ret = (DevID<<16)|ReqSrc;                              //请求成功 
 
RequestDmaExit:
 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)这个函数可以根据硬件/软件请求模式通过写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; 
}
//(停止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 
 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 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 
 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 
 return DMAChannel[ch].pDMA->DCDST; //CURR_DST[30:0]为当前DMA通道的目的地址值
}
阅读(1327) | 评论(0) | 转发(0) |
0

上一篇:DMA数据传输

下一篇:工作队列(workqueue)

给主人留下些什么吧!~~