DMA 簡介
DMA (Direct Memory Access ,直接內存存取)是比一種效率比較高的系統內部的一種數據傳輸方式,在系統運行時經常需要從一個地址空間拷貝大量數據到另一個地址空間,每次拷貝都需要占用cpu大量的時間,不能夠去執行其他的工作,而DMA控制器就是為了解決這個問題,當需要拷貝數據時,cpu只要告訴DMA控制器源地址,目標地址,拷貝大小這些參數后就可以去做其他事情了,DMA會接管相關總線,去完成數據拷貝的工作。當DMA完成傳輸工作后,會通知CPU來進行處理。這樣就大大提高了CPU的工作效率。
S3C6410的DMAC
S3C6410 包括4個DMA控制器,每個DMA控制器有8個傳輸通道,DMA控制器的每個通道都能夠無限制的在AXI SYSTEM 總線和AXI PERIPHERAL 總線之間通過AHBtoAXI 橋路傳輸數據。換句話說,每個通道能夠應用在下面的場合:
- 1 源和目標都在SYSTEM總線上
- 2 源在SYSTEM總線但目標在PERIPHREAL 總線
- 3 源在PERIPHREAL總線但是目標在SYSTEM總線
- 4 源和目標都在PERIPHREAL總線上
DMA的主要優勢就是在沒有CPU的干涉下也能進行數據傳輸,DMA傳輸操作可以被軟件或硬件驅動,或者是內部外設的請求,或者是外部引腳的請求。
一些特性:
- 4個 DMA 控制器,每個含8個通道,每個通道支持一個單向傳輸
- 每個DMA控制器提供16個外圍DMA請求
- 每個外設能夠請求一個突發模式或單次模式的DMA請求,突發模式大小在DMAC寄存器設置
- 支持內存到內存,內存到外設,外設到內存,外設到外設四種請求
- 使用鏈表支持分散或者聚集的DMA請求
- 硬件DMA優先級區分,每個通道都有固定的優先級,從Chanal 0到Chanal 7 優先級依次降低
- 源或目標源地址自動遞增或非遞增
- 可編程的突發模式的數據大小,通常為FIFO的一般
- 每個通道4個字的FIFO
- 支持8,16,32bit 寬度傳輸
- 分離的DMA 錯誤和DMA 總數中斷請求,一個中斷能夠通過DMA 錯誤或者DMA count達到0 產生(通常意味著傳輸完成)
- 中斷屏蔽
- 原始中斷狀態

S3C6410 支持64個DMA 源,四個DMA控制器分為安全DMA控制器和通用DMA控制器兩種,通過系統控制模塊中的SDMA_SEL寄存器進行選擇,64個DMA源如下表:

使能一個DMA通道的步驟
- 1、決定使用安全DMA控制器還是通用DMA控制器,若要使用通用的DMA控制器,關閉系統控制器的安全DMA控制寄存器(SDMA_SEL),復位值是SDMAC
- 2、選擇一個符合優先級要求的空閑的DMA通道 Chanal 0 到Chanal 7 優先級從高到低
- 3、清空通道中斷掛起寄存器和錯誤寄存器 DMACIntTCClr 和 DMACIntErrClr
- 4、寫源地址到源地址寄存器 DMACCxSrcAddr
- 5、寫目的地址到目標地址寄存器 DMACCxDestAddr
- 6、寫下次鏈接地址到DMACCxLLI寄存器,如果傳輸包含一個單數據包,則必須寫入這個寄存器
- 7、編程DMACCxControl 寄存器填寫控制信息
- 8、編程通道配置信息到DMACCxConfiguration 寄存器,如果使能位被設置,則DMA通道會自動使能
寄存器描述
四個DMA控制器被命名為DMAC0,DMAC1,SDMAC0,SDMAC1,寄存器基地址分別為0x7500_0000,0x7510_0000,0x7DB0_0000和0x7DC0_0000。



-
中斷狀態寄存器
中斷狀態寄存器 DMACIntStatus 是一個只讀的用來指示屏蔽后的中斷狀態的寄存器,某位為高表示一個特定的DMA通道中斷請求是激活的,請求能夠被錯誤或終端計數中斷請求產生。
-
終端計數中斷狀態寄存器
-
終端計數請求清零寄存器
-
錯誤中斷狀態寄存器
-
錯誤中斷狀態清零
-
原始終端計數中斷寄存器
-
原始錯誤中斷狀態寄存器
-
通道使能狀態寄存器
-
Burst請求寄存器
-
Single請求寄存器
-
DMACConfiguration 使能寄存器
-
同步寄存器
-
源地址寄存器
-
目標地址寄存器
-
鏈接表寄存器
-
通道控制寄存器0
-
通道控制寄存器1
-
通道配置寄存器
-
通道配置寄存器-額外
簡單代碼分析
/*
S3C6410中DMA操作步驟:
1、決定使用安全DMAC(SDMAC)還是通用DMAC(DMAC);
2、開啟DMAC控制,設置DMAC_Configuration寄存器;
3、清除傳輸結束中斷寄存器和錯誤中斷寄存器;
4、選擇合適的優先級通道;
5、設置通道的源數據地址和目的數據地址(設置DMACC_SrcAddr和DMACC_DestAddr);
6、設置通道控制寄存器0(設置DMACC_Control0);
7、設置通道控制寄存器1,(傳輸大小,設置DMACC_Control1);
8、設置通道配置寄存器;(設置DMACC_Configuration)
9、使能相應通道(設置DMACC_Configuratoin);
*/
#define SDMA_SEL (*((volatile unsigned long *)0x7E00F110))
#define DMACIntTCClear (*((volatile unsigned long *)0x7DB00008))
#define DMACIntErrClr (*((volatile unsigned long *)0x7DB00010))
#define DMACConfiguration (*((volatile unsigned long *)0x7DB00030))
#define DMACSync (*((volatile unsigned long *)0x7DB00034))
#define DMACC0SrcAddr (*((volatile unsigned long *)0x7DB00100))
#define DMACC0DestAddr (*((volatile unsigned long *)0x7DB00104))
#define DMACC0Control0 (*((volatile unsigned long *)0x7DB0010c))
#define DMACC0Control1 (*((volatile unsigned long *)0x7DB00110))
#define DMACC0Configuration (*((volatile unsigned long *)0x7DB00114))
#define UTXH0 (volatile unsigned long *)0x7F005020
char src[100] = "\n\rHello World-> This is a test!\n\r";
void dma_init()
{
//DMA控制器的選擇(SDMAC0)
SDMA_SEL = 0;
/* 如果外設的工作時鐘與DMA控制器的時鐘不相同, 要使能"同步邏輯" */
DMACSync = 0;
//DMA控制器使能
DMACConfiguration = 1;
//初始化源地址
DMACC0SrcAddr = (unsigned int)src;
//初始化目的地址
DMACC0DestAddr = (unsigned int)UTXH0;
//對控制寄存器進行配置
/*
源地址自增
目的地址固定、
目標主機選擇AHB主機2
源主機選擇AHB主機1
*/
DMACC0Control0 =(1<<25) | (1 << 26)| (1<<31);
DMACC0Control1 = 0x64; //傳輸的大小
/*
流控制和傳輸類型:MTP 為 001
目標外設:DMA_UART0_1,源外設:DMA_MEM
通道有效: 1
*/
DMACC0Configuration = (1<<6) | (1<<11) | (1<<14) | (1<<15);
}
void dma_start()
{
//開啟channel0 DMA
DMACC0Configuration = 1;
}