现在的位置: 首页 > 综合 > 正文

S3C2440的DMA资源

2014年01月07日 ⁄ 综合 ⁄ 共 2973字 ⁄ 字号 评论关闭

 DMA,Direct Memory Access,直接存储器访问。在大学学习计算机概论课程时就听说过其大名了。其主要功能是在不需要处理器参与的情况下进行数据传输。《基于ARM的嵌入式系统开发与实例》第12章讲了S3C44B0X的DMA控制器,比较复杂。因为S3C44B0X有通用DMA和桥DMA之分,还有SSB(三星系统总线)和SPB(三星外设总线)之分。此外讲DMA的REQ/ACK协议和DMA传输模式也没讲清楚,再加上一些时序图,我就更不大懂了。这样,原以为会比较难的。可没想到看了下S3C2440A用户手册第8章,没有参考书上或者开发板配套的示例程序,就很容易地写出了在两个内存地址间进行DMA数据传送的程序。原因在于那些复杂的协议和时序图,是做DMA控制器的工程师要关心的事情;对于写使用DMA进行数据传输的工程师来说,只要稍微了解就可以了。

 

    1 简介

    S3C2440A有一个位于系统总线和外设总线间的4通道DMA控制器。每个通道都支持在位于系统总线上和(或)位于外设总线上的设备间进行无限制的数据传输。所谓“无限制的”,意思是每个通道可以处理四种情况:

    (1)源和目标都在系统总线上

    (2)源在系统总线上,目标在外设总线上

    (3)源在外设总线上,目标在系统总线上

    (4)源和目标都在外设总线上

     DMA的主要优点是可以在无需CPU干预的情况下进行数据传输。DMA传输可以由软件、内部外设请求或者外部请求引脚发起。   

    

     2 请求源

     如果通过DCON寄存器设置了外部DMA请求模式,则DMA控制器的每个通道可以在6个请求源之间选择一个,见下表:

     S3C2440A的DMA

     注意:只有在DCON[23]设置为1,表示使用硬件中断模式时,请求源才有效。

 

     3 DMA有限状态机

     DMA使用3状态的有限状态机来进行操作:

     状态一:初始状态。DMA控制器等待DMA请求,DMA ACK和INT REQ都是0。一旦请求到达,则进入状态二。

     状态二:ACK变为1,从DCON[19:0]装载传输计数值到CURR_TC。注意:ACK保持为1直到随后清除它。

     状态三:在此状态下,初始化进行原子操作的子有限状态机。子有限状态机(sub-FSM)从源地址读取数据,写入到目的地址(原子操作)。这个操作会考虑数据尺寸和传输尺寸(单步还是突发)。在完全服务模式(whole service mode)下,此操作会重复直到传输计数值CURR_TC变为0;在单步服务模式下,此操作只进行一次。子有限状态机每完成一次原子操作,主有限状态机会让CURR_TC减1。如果CURR_TC变为0,又在DCON[29]设置了启用中断,则DMA控制器会发起DMA中断请求。此时,如果满足下列条件之一,还会清除DMA
ACK:

     (1)在完全服务模式下CURR_TC变为0

     (2)在单步服务模式下原子操作完成

 

     在单步服务模式下,主有限状态机分别经历这三个状态一次,然后传输停止,等待下一个DMA请求。下一个请求到达时,会重复这三个状态一次。因此,对于每次原子操作,ACK都会被设置然后被清除。相反,在完全服务模式下,主有限状态机会保持在状态三直到CURR_TC变为0。在整个传输过程中,ACK保持为1,直到传输完成,ACK才变为0。然而,无论是单步服务模式还是完全服务模式,都只在CURR_TC变为0时才发起DMA中断请求。

  

    4 寄存器

    S3C2440A对于每个DMA通道有9个寄存器,4个通道共使用了36个寄存器。9个寄存器中有6个是控制寄存器,用于控制DMA传输;3个是状态寄存器,用于监测DMA传输状态。

 

    实际传输的字节数 = DCON[19:0] * DSZ * TSZ

    DCON[19:0]初始传输计数;DSZ = DCON[21:20],传输的数据单元尺寸,类似C标准库中fread()函数第二个参数;TSZ = DCON[28],0表示每次进行一个单元传输,1表示每次进行(突发的)4个单元传输。

 

    软硬件方式选择:

    DCON[23] = 0:软件方式,应该在源和目标地址寄存器中写入有效地址。

    DCON[23] = 1:硬件方式,由DCON[26:24]指明DMA请求源

 

    其他:

    DCON[29]表示是否在传输完成时发起DMA中断请求

    DCON[27]选择单步服务模式还是完全服务模式,一般单步服务模式仅用于调试,常用的是完全服务模式

    DCON[30]选择DREQ/ACK同步方式,不太懂是什么意思

    DCON[31]选择请求模式还是握手模式,建议使用握手模式

 

    5 程序

    程序比较简单。用memcmp()函数来验证DMA传输是正确的。   

 #define DMA_SIZE        0xFFFFF
#define DMA_SRC     (0x30A00000)
#define DMA_DST     (0x31000000)

static volatile int dma_done;

static void __irq DMA_ISR()
{
    rSRCPND = BIT_DMA0;
    rINTPND = BIT_DMA0;
    UART0_printf("\n##### End DMA Transfer #####\n");
    dma_done = 1;
}

static void DMA_memcpy(void* p_dst,const void* p_src,int len)
{
    rDISRC0  = ((int)p_src & 0x7FFFFFFF);
    rDISRCC0 = 0;
    rDIDST0  = ((int)p_dst & 0x7FFFFFFF);
    rDIDSTC0 = 0;
   
    rDCON0 = (len & 0xFFFFF) + (2 << 20) +
             (1 << 22) + (1 << 27) + (1 << 29) + (1 << 30) + (1U << 31);
    rDMASKTRIG0 = 0x03;
}

void DMA_Test()
{
    pISR_DMA0 = (unsigned int)DMA_ISR;
    rINTMSK &= (~BIT_DMA0);
   
    memset((void*)DMA_DST,0,DMA_SIZE*4);
    UART0_printf("BEFORE transfer memcmp = %d\n\n",memcmp((void*)DMA_SRC,(void*)DMA_DST,4*DMA_SIZE));

    dma_done = 0;
    UART0_printf("START DMA Transfer\n");
    DMA_memcpy((void*)DMA_DST,(const void*)DMA_SRC,DMA_SIZE);
    while(0==dma_done);

    UART0_printf("\n\nAFTER transfer memcmp = %d\n\n",memcmp((void*)DMA_SRC,(void*)DMA_DST,4*DMA_SIZE));
}

 

【上篇】
【下篇】

抱歉!评论已关闭.