天天看点

mini2440裸机之DMA

原文出自 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" #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启动|目的信息|   |源信息| | 请求源代号 | | 通道号     |      //  

mini2440裸机之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)这个函数主要通过写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通道的目的地址值 }

继续阅读