天天看點

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通道的目的位址值 }

繼續閱讀