【Linux内幕】DMA原理

DMA是一种允许外设直接与内存交换数据的技术,减少了CPU的干预。文章介绍了DMA的工作原理,包括DMA请求、响应、传输和结束四个阶段,以及在Linux系统中内存的DMA、DMA32和Normal区域划分。还展示了LinuxDMAAPI函数`DMA_Init`和`DMA_WriteValue/DMA_ReadValue`的示例,用于数据的读写操作。

1.前言

I/O设备与主存信息传送的控制方式分为程序轮询、中断、DMA、RDMA等。
在这里插入图片描述

2.DMA介绍

DMA,全称Direct Memory Access,即直接存储器访问。
DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。
在这里插入图片描述
CPU有转移数据、计算、控制程序转移等很多功能,系统运作的核心就是CPU,CPU无时不刻的在处理着大量的事务,但有些事情却没有那么重要,比方说数据的复制和存储数据,如果我们把这部分的CPU资源拿出来,让CPU去处理其他的复杂计算事务,是不是能够更好的利用CPU的资源呢?
在这里插入图片描述

3.传输方式

DMA的作用就是实现数据的直接传输,而去掉了传统数据传输需要CPU寄存器参与的环节,主要涉及四种情况的数据传输,但本质上是一样的,都是从内存的某一区域传输到内存的另一区域(外设的数据寄存器本质上就是内存的一个存储单元)。四种情况的数据传输如下:

  • 外设到内存
  • 内存到外设
  • 内存到内存
  • 外设到外设

一个完整的 DMA 传输过程必须经过 DMA 请求、DMA 响应、DMA 传输、DMA 结束这四个阶段。

  • DMA 请求:CPU 对 DMA 控制器初始化,并向 I/O 接口发出操作命令,I/O 接口提出 DMA 请求。
  • DMA 响应:DMA 控制器对 DMA 请求判别优先级以及屏蔽位,向总线裁决逻辑提出总线请求,当 CPU 执行完成当前的总线周期之后即可释放总线控制权。此时,总线裁决逻辑输出总线应答,表示 DMA 已经就绪,通过 DMA 控制器通知 I/O 接口开始 DMA 传输。
  • DMA 传输:在 DMA 控制器的引导下,在存储器和外设之间进行数据传送,在传送过程中不需要 CPU 的参与。
  • DMA 结束:当完成既定操作之后,DMA 控制器释放总线控制权,并向 I/O 接口发出结束信号,当 I/O 接口收到结束信号之后,一方面停止 I/O 设备的工作,另一方面向 CPU 提出中断请求,使 CPU 从不介入状态解脱,并执行一段检查本次 DMA 传输操作正确性的代码。最后带着本次操作的结果以及状态继续执行原来的程序。

DMA 的原理就是 CPU 将需要迁移的数据的位置告诉给 DMA,包括源地址,目的地址以及需要迁移的长度,然后启动 DMA 设备,DMA 设备收到命令之后,就去完成相应的操作,最后通过中断反馈给 CPU,结束。

4.Linux DMA

操作系统会将内存分段,分页,分区,在64位的操作系统中,内存划分为DMA、MDA32、Normal区。

[zyq@zyq ~]$ cat /proc/buddyinfo 
Node 0, zone      DMA      0      2      3      2      3      1      0      0      1      1      3 
Node 0, zone    DMA32    218     77     38     26     13      5      2      2      2      2    539 
Node 0, zone   Normal    164     80     71    148     89     49     19     11      6      9   7043

在这里插入图片描述
每一行代表当前的内存区中连续1、2、4、8、16、32、64、128、256、512、1024个可使用空闲页的数量,当前系统默认的页大小为4K,所以分别对应的大小为1x4k、2x4k、4x4k、8x4k、16x4k、32x4k、64x4k、128x4k、256x4k=1M、512x4k=2M、1024x4k=4M,由此可以计算出:

DMA大小为:

3x4M+1x2M+1x1M+…=16M

DMA32大小为:

539x4M+22M+21M+…=2G

Normal大小为:

7043x4M+9x2M+6x1M+…=27G

5.API函数

int DMA_Init(void)
{
    /* Disable interrupts, we use polling mode */
    XAxiDma_IntrDisable((uint32_t)g_axi_dma1_vaddr,XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
    XAxiDma_IntrDisable((uint32_t)g_axi_dma1_vaddr,XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
    return 0;
}


int DMA_WriteValue(unsigned int addr, unsigned char *data, unsigned int len)
{
    memcpy((g_axi_dma1_buf_vaddr_write + addr), data, len);
    XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_SRCADDR_OFFSET, AXI_DMA1_BUF_BASEADDR_WRITE);
    XAxiDma_ReadReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_SRCADDR_OFFSET);

    XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_BUFFLEN_OFFSET, len);
    XAxiDma_ReadReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_BUFFLEN_OFFSET);

    /* Wait till DMA MM2S Transfer Complete */
    while(!(XAxiDma_ReadReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_SR_OFFSET)    & 0x1000));

    return 0;
}

int DMA_ReadValue(unsigned int addr, unsigned char *data, unsigned int len)
{
    unsigned int reg = 0;
    for(int ii = 0; ii < len; ii++)
    {
        *(g_axi_dma1_buf_vaddr_read + addr + ii) = 0;
    }
    // 停止
    XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_CR_OFFSET + XAXIDMA_RX_OFFSET, XAXIDMA_CR_RUNSTOP_MASK);
    /* 向48h寄存器写入 */
    XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_DESTADDR_OFFSET + XAXIDMA_RX_OFFSET, AXI_DMA1_BUF_BASEADDR_READ);
    XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_BUFFLEN_OFFSET + XAXIDMA_RX_OFFSET, len);
    //XAxiDma_ReadReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_BUFFLEN_OFFSET + XAXIDMA_RX_OFFSET);

    /* Wait till DMA MM2S Transfer Complete */
    do{
        reg = (unsigned int)XAxiDma_ReadReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_SR_OFFSET + XAXIDMA_RX_OFFSET);
    }
    while(!(reg & 0x1000));
    //sync();
    //清除中断寄存器
    XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_SR_OFFSET + XAXIDMA_RX_OFFSET, reg);

    ///*读数据*/
    memcpy(data, (g_axi_dma1_buf_vaddr_read + addr), len);
    return 0;
}

6.参与讨论

==============================
新的文章内容和分享已更新在:

|工|·-·|重|·-·|号|:协议森林

==============================

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值