原文出自 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啟動|目的資訊| |源資訊| | 請求源代号 | | 通道号 | //
//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通道的目的位址值 }