什么是DMA?(转)

FROM: Soul of Angel
什么是DMA? 
当我们向计算机中加入了一块新的声卡或其它适配卡时,安装程序可能会提醒我们应该选择一个DMA通道。那DMA是什么呢? DMA(Direct Memory Access),即直接存储器存取,是一种快速传送数据的机制。数据传递可以从适配卡到内存,从内存到适配卡或从一段内存到另一段内存。DMA技术的重要 性在于,利用它进行数据传送时不需要CPU的参与。每台电脑主机板上都有DMA控制器,通常计算机对其编程,并用一个适配器上的ROM(如软盘驱动控制器 上的ROM)来储存程序,这些程序控制DMA传送数据。一旦控制器初始化完成,数据开始传送,DMA就可以脱离CPU,独立完成数据传送。 
在DMA传送开始的短暂时间内,基本上有两个处理器为它工作,一个执行程序代码,一个传送数据。利用DMA传送数据的另一个好处是,数据直接在源地址和目 的地址之间传送,不需要中间媒介。如果通过CPU把一个字节从适配卡传送至内存,需要两步操作。首先,CPU把这个字节从适配卡读到内部寄存器中,然后再 从寄存器传送到内存的适当地址。DMA控制器将这些操作简化为一步,它操作总线上的控制信号,使写字节一次完成。这样大大提高了计算机运行速度和工作效 率。 
计算机发展到今天,DMA已不再用于内存到内存的数据传送,因为CPU速度非常快,做这件事,比用DMA控制还要快,但要在适配卡和内存之间传送数据,仍 然是非DMA莫属。要从适配卡到内存传送数据,DMA同时触发从适配卡读数据总线(即I/O读操作)和向内存写数据的总线。激活I/O读操作就是让适配卡 把一个数据单位(通常是一个字节或一个字)放到PC数据总线上,因为此时内存写总线也被激活,数据就被同时从PC总线上拷贝到内存中。 
对于每一次写操作,DMA控制器都控制地址总线,通知应将数据写到哪段内存中去。 DMA控制数据从内存传送到适配卡的方法与上面类似。对每一个要传送的单位数据,DMA控制器激活读内存和I/O写操作的总线。内存地址被放到地址总线 上,像从适配卡到内存传送数据一样,以数据总线为通道,数据从源地址直接传送到目的地址。 DMA从DMA请求线(DREQ)上接收DMA请求,正像中断控制器从中断请求线(IRQ)上接收中断请求一样。 
一个典型的从适配卡到内存的数据传送是这样进行的,首先,对DMA控制器编程,写入数据要到达的内存地址和要传送的字节数。适配器可以开始传送数据时,它 将激活DREQ线,与DMA控制器连通。DMA控制器在与CPU取得总线控制权后,输出内存地址,发送控制信号,使得一个字节或一个字从适配器读出并写入 相应内存中,然后更新内存地址,指向下一个字节(或字)要写入的地址,重复上面的操作,直至数据传送完毕。对控制器进行不同编程,就可以实现单字节传送 (即每传送一个字节都要求一个DREQ信号)或块数据传送(即全部数据传送只需要一个DREQ信号)。 
如果你要往计算机中插一块适配卡,而且适配卡使用DMA,通常安装程序会让你选择一个DMA通道,设定DIP开关或跳线,来为相应适配器设置DMA通道。 尽管从理论上讲,只要不是同时使用DREQ线,不同的适配卡可以共享这条线的,但是按常规,我们最好为每个适配卡单独安排一个DMA通道,这样就可以保证 不会发生DMA冲突。附表是DMA的缺省分配情况。通道 功能通道 功能 O 空闲 4 用于级联DMA控制器 1 空闲 5 空闲 2 软盘 6 空闲 3 空闲 7 空闲从中可以看出,DMA通道2和4已被占用,在大多数微机上,通道1、3、5、6和7可由你任意分配。我们平时最好对自己的计算机上DMA通道的分配情 况记录下来,以免我们向计算机增加新硬件时出现两个适配卡共用一个通道,导致冲突。 

DMA---Direct Memory Access,直接内存访问,是一种数据传输模式。DMA方式下由于不直接访问计算机的CPU,而直接在RAM与设备之间传输,因而大大提高了数据传输速度。 

呵呵,看过上面的DMA的含义及用途了,所以我们只需要打开DMA传输方式就可以了~~~操作方法: 

Windows 98/Me 启用内存直接存取DMA 

右击Windows桌面上的“我的电脑” 图标并从弹出菜单选择“属性”。系统属性窗口出现。单击“设备管理”标签。双击“CDROM驱动器”,查看硬盘驱动器列表。右击IDE DISK(可能会有其他名称,例如 GENERIC IDE DISK)并从弹出菜单选择 “属性”。该硬盘属性窗口出现。单击“设置”标签。选择“DMA”如果该项未选,然后单击“确认”。Windows问您是否要重新启动,单击是。 

在Windows 2000启用内存直接存取DMA 

作为管理员(或具管理员特权的用户)登录进入Windos。右击Windows 桌面上的“我的电脑”图标并从弹出菜单选择属性。系统属性窗口出现。单击硬件标签, 然后单击设备管理器。设备管理员窗口出现。双击 IDE ATA/ATAPI 控制器来查看控制器列表。双击主IDE 通道。主IDE信道属性窗口出现。单击高级设置标签。选择DMA,如果该项可从设备0的传输模式列表中找到的话。单击确认。Windows问您是否要重新 启动, 单击是。 

在Windows XP启用内存直接存取DMA 

作为管理员(或具管理员特权的用户)登录进入Windows。单击“开始”按钮,,然后右击“我的电脑”并从弹出菜单选择属性。系统属性窗口出现。单击 “硬件” 标签,,然后单击“设备管理员”。设备管理员窗口出现。双击“IDE ATA/ATAPI”控制器来查看控制器列表。双击“从IDE 通道”。从IDE通道属性窗口出现。单击“高级设置”标签。选择DMA,如果该项可从装置0(或1,视您的刻录机的跳线设置而定)的传输模式列表中找到的 话。单击确认。您不必重新启动 Windows。 

================================================ 
附录:DMA精读 

/********************************************************************************/ 
* Copyright (C) 2000 Texas Instruments Incorporated. 
* All Rights Reserved 
*------------------------------------------------------------------------------ 
* FILENAME...... dma1.c 
* DATE CREATED.. 01/11/2000 
* LAST MODIFIED. 01/04/2001 
/******************************************************************************/ 
#include <std.h> 
#include <log.h> 

/* Include DSPBIOS/CSL GUI configuration header file */ 
#include "dma1cfg.h" 

#include <csl.h> 
#include <csl_irq.h> 
#include <csl_dma.h> 

/* Constant defines transfer length */ 
#define N 128 

/* Place src and dst of DMA transfer in seperate memory section */ 
/* to better control placement in user specified memory range */ 
#pragma DATA_SECTION(src,"dmaMem") 
Uint16 src[N]; 

#pragma DATA_SECTION(dst, "dmaMem") 
Uint16 dst[N]; 


/* This example effects a single-frame transfer of 128 */ 
/* elements from DARAM to DARAM, via DMA */ 
/* The macro invocation reflect the settings required in */ 
/* DMA control registers to make this happen. */ 

/* DMACSDP dstben == 0 */ 
/* dstpack == 0 */ 
/* dst == 0 */ 
/* srcben == 0 */ 
/* srcpack == 0 */ 
/* src == 0 */ 
/* datatype == 1 */ 
/* */ 
/* DMACCR dstamode == 1 */ 
/* srcamode == 1 */ 
/* endprog == 0 */ 
/* fifoflush == 0 */ 
/* repeat == 0 */ 
/* autoinit == 0 */ 
/* en == 0 */ 
/* prio == 0 */ 
/* fs == 0 */ 
/* sync == 0 */ 
/* */ 
/* DMACICR blockie == 1 */ 
/* lastie == 1 */ 
/* frameie == 1 */ 
/* firsthalfie == 1 */ 
/* dropie == 1 */ 
/* timeoutie == 1 */ 

DMA_Config myconfig = { 
DMA_DMACSDP_RMK( 
DMA_DMACSDP_DSTBEN_NOBURST, 
DMA_DMACSDP_DSTPACK_OFF, 
DMA_DMACSDP_DST_DARAM, 
DMA_DMACSDP_SRCBEN_NOBURST, 
DMA_DMACSDP_SRCPACK_OFF, 
DMA_DMACSDP_SRC_DARAM, 
DMA_DMACSDP_DATATYPE_16BIT 
), /* DMACSDP */ 
DMA_DMACCR_RMK( 
DMA_DMACCR_DSTAMODE_POSTINC, 
DMA_DMACCR_SRCAMODE_POSTINC, 
DMA_DMACCR_ENDPROG_OFF, 
DMA_DMACCR_FIFOFLUSH_OFF, 
DMA_DMACCR_REPEAT_OFF, 
DMA_DMACCR_AUTOINIT_OFF, 
DMA_DMACCR_EN_STOP, 
DMA_DMACCR_PRIO_HI, 
DMA_DMACCR_FS_ENABLE, 
DMA_DMACCR_SYNC_NONE 
), /* DMACCR */ 
DMA_DMACICR_RMK( 
DMA_DMACICR_BLOCKIE_OFF, 
DMA_DMACICR_LASTIE_OFF, 
DMA_DMACICR_FRAMEIE_ON, 
DMA_DMACICR_FIRSTHALFIE_OFF, 
DMA_DMACICR_DROPIE_OFF, 
DMA_DMACICR_TIMEOUTIE_OFF 
), /* DMACICR */ 
(DMA_AdrPtr) &src, /* DMACSSAL */ 
0, /* DMACSSAU */ 
(DMA_AdrPtr) &dst, /* DMACDSAL */ 
0, /* DMACDSAU */ 
N, /* DMACEN */ 
1, /* DMACFN */ 
0, /* DMACFI */ 
0 /* DMACEI */ 
}; 

/* Define a DMA_Handle object */ 
DMA_Handle myhDma; 
int i, j; 
Uint16 err = 0; 
volatile Bool WaitForTransfer = TRUE; 

void main(void) 

/* Initialize source and destination buffers */ 
for (i = 0; i <= (N - 1); i++) { 
dst[i] = 0; 
src[i] = i + 1; 



void taskFxn(void) 

/* Open DMA Channel 0 */ 
myhDma = DMA_open(DMA_CHA0, 0); 

/* By default, the TMS320C55xx compiler assigns all data symbols word */ 
/* addresses. The DMA however, expects all addresses to be byte */ 
/* addresses. Therefore, we must shift the address by 2 in order to */ 
/* change the word address to a byte address for the DMA transfer. */ 
myconfig.dmacssal = 
(DMA_AdrPtr)(((Uint16)(myconfig.dmacssal))<<1); 
myconfig.dmacdsal = 
(DMA_AdrPtr)(((Uint16)(myconfig.dmacdsal))<<1); 

/* Write configuration structure values to DMA control registers */ 
DMA_config(myhDma, &myconfig); 

/* Enable DMA channel for to begin transfer */ 
DMA_FSETH(myhDma,DMACCR,EN,1); 

/* Wait for FRAME status bit in DMA status register to signal */ 
/* transfer is complete. */ 
while (!DMA_FGETH(myhDma,DMACSR,FRAME)) { 



/* Check dta values to make sure transfer happened correctly */ 
for (i = 0; i <= (N - 1); i++) { 
if (dst[i] != src[i]) { 
++err; 



if (err) { 
LOG_printf(&trace, ">>> Warning, DMA Example 1 Failed"); 

else { 
LOG_printf(&trace, "...DMA Example 1 Complete"); 


/* We are through with DMA, so close it */ 
DMA_close(myhDma); 


DMA Functions 

Function Purpose 
DMA_close() Closes the DMA and its corresponding handler 
DMA_config() Sets up DMA using configuration structure (DMA_Config) 
DMA_configArgs() Sets up DMA using register values passed to the function 
DMA_getConfig() Reads the DMA configuration 
DMA_getEventId() Returns the IRQ Event ID for the DMA completion interrupt 
DMA_open() Opens the DMA and assigns a handler to it 
DMA_pause() Interrupts the transfer in the corresponding DMA channel 
DMA_reset() Resets the DMA registers with default values 
DMA_start() Enables transfers in the corresponding DMA channel 
DMA_stop() Disables the transfer in the corresponding DMA channel

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章