DMA介绍

DMA(Direct Memory Acess, 直接内存访问),是计算机的一种内存访问技术,它允许在外设和内存之间直接传输数据,而不需要CPU介入处理。DMA具有速度快,节省CPU负担的特点。DMA的初始化需要CPU来完成,初始化完成之后,数据传输就由DMA控制器来完成。
Alt text

在实现DMA传输时,是由DMA控制器直接掌管总线,因此,存在着一个总线控制权转移问题。即DMA传输前,CPU要把总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU。一个完整的DMA传输过程必须经过DMA请求、DMA响应、DMA传输、DMA结束4个步骤。

2440的DMA控制器支持4个DMA通道,各个通道的请求源如下所示:
Alt text

2440的DMA基本时序如下图所示:
Alt text

2440的DMA控制器有两种工作模式:

  • Demand模式:DMA完成一次请求后如果Request仍然有效,那么DMA就认为这是下一次DMA请求,并立即开始下一次的传输
  • Handshake模式:DMA完成一次请求后即使Requqest有效,也不会立刻传输,而是等待Request信号无效,等Request无效后,再等Request有效。

6410有4个DMA控制器,每个控制器有8个通道。210则支持两种类型的DMA访问,一种是内存到内存的DMA,使用的控制器是DMA,另一种是外设到内存的DMA,使用的控制器是DMA0和DMA1。对应的描述可从芯片手册的DMA相关章节找到。

DMA程序设计

下面使用DMA来完成将内存中的数据发送到串口,参考芯片手册的DMA编程指引部分,在11.7小节。

要完成使用DMA传输数据,至少需要完成以下几步:

  1. 初始化DMA的源地址和目的地址
  2. 初始化DMA源和发送数据量
  3. 启动DMA传输

而针对6410,还需要进行以下几步设置:

  1. 选择SDMAC0作为DMA控制器,要设置的寄存器是SDMA_SEL
  2. 使能DMA控制器,使用DMACCONFIGURATION

代码如下:

#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控制器选择(SDMA0)
    SDMA_SEL = 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;    
}

  • 无标签