精华内容
下载资源
问答
  • dma使用

    千次阅读 2012-04-11 13:50:51
    1. DMA : 直接存储访问. 在不带MPU或者DSP的情况下,外设和内存之间高性能数据传输. 2. 一个DMA传输器可以通过一个逻辑DMA通道来编程, 以适应应用需求. 3. 专用DMA控制器: ISP(camera image signal processor) DMA,...
    1. DMA : 直接存储访问. 在不带MPU或者DSP的情况下,外设和内存之间高性能数据传输.
    2. 一个DMA传输器可以通过一个逻辑DMA通道来编程, 以适应应用需求.
    3. 专用DMA控制器: ISP(camera image signal processor) DMA, EDMA(内嵌在IVA2.2子系统), 显示DMA, USB HS(high-speed) DMA.
    4. DMA控制器包含如下特征:
       数据传输方向支持:  内存<-->内存, 内存<-->外设
       32个逻辑DMA通道支持:
         -- 多个同时传输
         -- 每个通道独立配置
         -- 8位,16位,32位数据传输长度
         -- 软件触发或者硬件同步传输
         -- 线性源和目的地址产生
         -- 突发读写
         -- 多通道传输链
         -- 大小端转换
       固定优先级DMA调度起, 先来先服务
       高达96个DMA请求
       常数填充
       4个可编程中断请求输出线
       FIFO深度: 256 x 32位
       电源管理支持
       自动空闲进入省电模式支持
       
    DMA模块有3个端口, 一个读,一个写,一个配置端口. 提供多个逻辑通道支持.
    一个动态申请FIFO队列内存池提供为读写端口之间缓存.
    读写端口是多线程的(写端口有2个线程, 读端口有4个线程), 也意味着在请求方向和响应方向里,每个事务被一个线程ID(0,1,2,3)标志. 这也允许读端口同时有4个未完成的请求. 写端口有两个线程可用.

    * DMA寄存器:
    1) DMA4_REVISION     -- DMA版本寄存器
    2) DMA4_IRQSTATUS_Lj     -- 中断状态寄存器. j表示4个中断线中的一个, 每个位表示一个通道.
    3) DMA4_IRQENABLE_Lj     -- 中断使能寄存器
    4) DMA4_SYSSTATUS     -- 系统状态寄存器, 查看复位状态
    5) DMA4_OCP_SYSCONFIG     -- DMA OCP系统配置寄存器
    6) DMA4_CAPS_0-4     -- DMA能力寄存器
    7) DMA4_GCR         -- 高低优先级通道共享FIFO
    8) DMA4_CCRi         -- 通道控制寄存器
    9) DMA4_CLNK_CTRLi     -- 通道链接控制寄存器
    10)DMA4_CICRi         -- 通道中断控制寄存器
    11)DMA4_CSRi         -- 通道状态寄存器
    12)DMA4_CSDPi         -- 通道源/目的参数
    13)DMA4_CENi         -- 通道一帧中元素个数
    14)DMA4_CFNi         -- 通道一块中的帧数
    15)DMA4_CSSAi         -- 源地址
    16)DMA4_CDSAi         -- 目的地址
    17)DMA4_CSEIi         -- 通道源元素索引
    18)DMA4_CSFIi         -- 通道源帧索引 或者 16位包大小
    19)DMA4_CDEIi         -- 通道目的元素索引
    20)DMA4_CDFIi         -- 通道目的帧索引 或者 16位包大小
    21)DMA4_CSACi         -- 通道源地址当前值(只读)
    22)DMA4_CDACi         -- 通道目的地址当前值(只读)
    23)DMA4_CCENi         -- 通道当前传输元素个数
    24)DMA4_CCFNi         -- 通道当前传输帧数
    25)DMA4_COLORi         -- Color key or solid color pattern
    26)DMA4_CDPi         -- 链接列表机器的各种参数配置
    27)DMA4_CNDPi         -- 下一个链接列表机器的地址
    28)DMA4_CCDNi         -- 包含链接列表中当前激活的的描述符数


    DMA驱动分析
    1.初始化
       1)omap_dma_base 为基地址, dma_lch_count 为通道数=32
       2)dma_chan 为通道链表数组, 结构体struct omap_dma_lch.
       3)dma_linked_lch 通道链表信息数组, 结构体struct dma_link_info.
       4)dma_chan_count 链表数等于通道数. 并初始化通道链表数组
       5)配置DMA4_GCR寄存器.
          *设置一个逻辑通道最大FIFO深度为0x10. 如果小于目标突发大小
          *不保留任何线程ID给高优先级读写端口
          *不固定分配高低优先级FIFO
          *已优先和常规队列任意切换速率为1
       6)建立DMA中断处理函数(setup_irq, 中断号12, L0线)
       7)配置DMA4_OCP_SYSCONFIG寄存器, 自动省电模式

    2. dma中断处理函数
       1)读L0线的中断状态寄存器, 并查看并处理中断的那个DMA逻辑通道
       2)读通道状态寄存器CSR, 并判断该DMA通道的dev_id是否有效
       3)判断是否在DMA链表中, 并设置状态为不启动
         *如果当前通道的链表模式使能, 则下一个通道状态设置为启动.
         *如果链表模式是动态链表, 则禁用链表(禁止通道中断,禁用链表模式,标志为非激活)
       4)调用DMA回掉函数

    3. DMA属性设置
       1) 读写优先级(CCR)
       2) 数据位数(CSDP)
       3) 同步设置(CCR) --- 1.元素 2.块 3.帧 4.包(package)
            注: 传递完之后产生中断信号
       4) 同步源设置(CCR) --- 目的或者源 (包同步的话,包的元素个数由CSFI|CDFI指定)
       5) 同步控制(使用哪个DMA中断号) (CCR)
       6) 设置帧的元素个数, 块的帧数

       7) 设置源地址增长模式, 起始地址, 帧索引和元素索引

       8) 设置目的地址增长模式, 起始地址, 帧索引和元素索引

       9) 设置DMA源或者目的地址的burst方式

       10) 清中断状态,并设置中断使能位(frame, last, block, packet, err)
       11) 使能DMA Linej中断

       12) CCR中的DMA使能位置一.
            如果使用链表的话设置链表,使能各通道中断,并只使用第一个通道的DMA
            停止DMA的时候也要把链表所有通道停掉,并禁用中断

    DMA链表使用必须再DMA使能之前, 禁用必须再DMA停掉之后. 链表是自环的.



















       















    展开全文
  • STM32 DMA使用详解.docx

    2019-07-20 19:54:49
    STM32 DMA使用详解 对DMA的理解与学习都不错了 。对DMA的使用都很不错的
  • IC验证之DMA使用

    2020-07-17 15:25:48
    一、标准DMA使用 1.DMA配置寄存器CONFIG中使能DMA。 2.中断控制寄存器INTTCLR中清掉所有中断。 3.通道0的源地址寄存器C0SRCADDR中设置数据源地址。 4.通道0的目的地址寄存器C0DESTADD中设置数据目的地址。 5.通道0...

    DMA分为标准DMA和集成DMA。比如SD模块内部集成了DMA功能模块,其使用方法与标准DMA存在不同。此外DMA搬运数据过程是不借助于中断进行的!
    一、标准DMA使用
    1.DMA配置寄存器CONFIG中使能DMA。
    2.中断控制寄存器INTTCLR中清掉所有中断。
    3.通道0的源地址寄存器C0SRCADDR中设置数据源地址。
    4.通道0的目的地址寄存器C0DESTADD中设置数据目的地址。
    5.通道0链接列表寄存器C0LLI中设置为零(仅发送一个package的情况),如果使用多个通道,该寄存器的值设置高30位,即reg[31:2]设置第二个通道连接列表寄存器C1LLI的地址,低两位即reg[1:0]设置为0。
    6.通道0的控制寄存器中设置tranfer size、burstsize、
    tranfer width和source increment 和destnation increment等。
    其中,tranfer size为总的传输数据量大小,其计算方法为tranfer size= N* source tranfer width;burst size 就是DMA请求一次总线完成的数据传输量;tranfer width分为source tranfer width 和destnation tranfer size,source tranfer size 就是数据源读取时的位宽,destnation tranfer size 就是向目的地址写数据时的数据宽度;increment代表在读写数据时地址是否递增,而在从memroy向peripheral搬运时,source increment置高,即地址递增,而destnation increment 置低,即地址不变,一直是数据发送寄存器的地址(如I2C、UART)。
    7.通道0的配置寄存器C0CONFIG中使能通道0,并且配置source request peripheral 和 destnation request peripheral,也就是DMA控制器分配好的外设(如I2C、UART、CAN和SPI等,如果是SRAM和DDR等MEMORY,则不需要设置)读写编号。
    如果仅发送一个package,以上配置就结束了,如果需要发送多个package,需要使用别的channel,即DMA的channel1-7,需要继续以下操作:
    8.通道n的源地址寄存器CnSRCADDR中设置数据源地址。
    9.通道n的目的地址寄存器CnDESTADD中设置数据目的地址。
    10.通道n链接列表寄存器CnLLI中设置为下一个通道n+1的链接列表寄存器的地址,若该通道为最后一个通道,其值设置为0,代表是最后一个通道。就实际观察来看,该寄存器设置的正确与否,不影响通道1-7的使用。
    11.通道n的控制寄存器中设置tranfer size、burstsize、
    tranfer width和source increment 和destnation increment等。
    12.通道n的配置寄存器CnCONFIG中使能通道n,并且配置source request peripheral 和 destnation request peripheral,也就是DMA控制器分配好的外设(如果是SRAM和DDR等MEMORY,则不需要设置)读写编号。其中,n小于等于7。
    二、集成DMA使用
    在集成的DMA中,以SD模块为例,每个Descriptor分为4个部分DES0\DES1\DES2\DES3来配置DMA要搬运数据的信息。
    Descriptor分为 dual-buffer模式和chain descriptor 模式, 描述符的结构图如下所示:
    在这里插入图片描述
    Descriptor配置流程如下:
    1.在DES0中设置end of ring、second address chained、first descriptor和last descriptor 等。end of ring 置高代表这是最后一个descriptor;send address chained 置高,代表该descriptor 指向的第二个地址不再是buffer的地址,而是第二个descriptor的地址;first 、last descriptor不再介绍。
    2.DES1设置descriptor指向的两个buffer的大小(dual-buffer中使用两个buffer,而chain descriptor结构中只用到一个buffer)。
    3.DES2中存放buffer1的地址指针;
    4.Dual-buffer模式中,DES3中存放Buffer2的地址指针,而chain descriptor模式中,DES3存放下一个descriptor的地址指针。
    三、DMA从外设(例SPI、UART和I2C等)向sram等memory中搬数据时,判断数据是否搬运完成呢,可以查看外设接收FIFO中是否为空、或者查看标准DMA的通道配置寄存器Channel Configuration Register中的bit17位是否为active,1代表当前DMA还在搬运数据,0代表DMA搬运数据完成!
    以上是个人在验证中的理解,如有错误,欢迎指正!

    展开全文
  • DMA使用指南

    2020-09-23 14:35:48
    DMA寻址限制DMA映射的类型使用一致的 DMA 映射创建一个 `dma_pool `从 DMA 池中分配内存释放`dma_pool`中申请的内存:销毁`dma_pool`DMA方向使用DMA 映射映射单个区域取消映射单个区域解除映射散列表错误处理优化...

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

    Dynamic DMA mapping Guide

    作者:
    David S. Miller davem@redhat.com
    Richard Henderson rth@cygnus.com
    Jakub Jelinek jakub@redhat.com

    这是设备驱动程序编写人员如何使用DMA API和示例伪代码的指南。有关该API的简明描述,请参见DMA-API.txt。

    PCI设备有很好的可配置型和易操作性,这很大方面要归功于其地址空间的可动态分配的特性。而动态分配地址空间就是依赖于BAR(base address register)实现的。

    CPU和DMA地址

    DMA API中涉及到几种不同的地址,理解它们之间的区别是很重要的。

    内核通常使用虚拟地址。kmalloc()vmalloc()和类似接口返回的任何地址都是虚拟地址,可以存储在void *中。

    虚拟内存系统(TLB,页表等)将虚拟地址转换为CPU物理地址,并以phys_addr_tresource_size_t存储。 内核管理设备资源,例如将寄存器注册为物理地址。 这些是/proc/iomem中的地址。物理地址对驱动程序不是直接有用的。它必须使用ioremap()映射空间并生成一个虚拟地址。

    I/O设备使用第三种地址:“总线地址”。 如果设备在MMIO地址上有寄存器,
    或者执行DMA来读取或写入系统内存,则设备使用的地址就是总线地址。
    在某些系统中,总线地址与CPU物理地址相同,但通常不相同。
    IOMMU和主机桥可以在物理地址和总线地址之间产生任意映射。

    从设备的角度来看,DMA使用总线地址空间,但可能仅限于该空间的子集。
    例如,即使系统支持主存储器和PCI BAR的64位地址,它也可以使用IOMMU,
    因此设备仅需要使用32位DMA地址。

    这里有一张图片和一些例子:

                   CPU                  CPU                  Bus
                 Virtual              Physical             Address
                 Address              Address               Space
                  Space                Space
    
                +-------+             +------+             +------+
                |       |             |MMIO  |   Offset    |      |
                |       |  Virtual    |Space |   applied   |      |
              C +-------+ --------> B +------+ ----------> +------+ A
                |       |  mapping    |      |   by host   |      |
      +-----+   |       |             |      |   bridge    |      |   +--------+
      |     |   |       |             +------+             |      |   |        |
      | CPU |   |       |             | RAM  |             |      |   | Device |
      |     |   |       |             |      |             |      |   |        |
      +-----+   +-------+             +------+             +------+   +--------+
                |       |  Virtual    |Buffer|   Mapping   |      |
              X +-------+ --------> Y +------+ <---------- +------+ Z
                |       |  mapping    | RAM  |   by IOMMU
                |       |             |      |
                |       |             |      |
                +-------+             +------+
    

    在列举过程中,内核了解I/O设备及其MMIO空间以及将它们连接到系统的host桥。
    例如:
    如果PCI设备具有BAR,则内核从BAR读取总线地址(A),并将其转换为CPU物理地址(B)。 地址B存储在结构资源中,通常通过/proc/iomem公开。 当驱动操作设备时,通常使用ioremap()将物理地址B映射到虚拟地址(C)。 然后,它可以使用例如ioread32©访问总线地址A处的设备寄存器。

    如果设备支持 DMA,则驱动程序使用 kmalloc ()或类似的接口设置缓冲区,该接口返回一个虚拟地址(x)。虚拟内存系统将 x 映射到系统 RAM 中的物理地址(y)。驱动程序可以使用虚拟地址 x 来访问缓冲区,但是设备本身不能,因为 DMA 不经过 CPU 虚拟内存系统。

    在一些简单的系统中,设备可以直接对物理地址 y 进行 DMA。但在许多其他地方,IOMMU 硬件将 DMA 地址转换为物理地址,例如,它将 z 转换为 y。这就是 DMA API 的部分原因: 驱动程序可以为 DMA_map_single()之类的接口提供虚拟地址 x,该接口设置所需的 IOMMU 映射并返回 DMA 地址 z。然后驱动程序告诉设备执行 DMA 到 z,IOMMU 将其映射到系统 RAM 中地址为 y 的缓冲区。

    为了使 Linux 能够使用动态 DMA 映射,它需要来自驱动程序的一些帮助,也就是说,它必须考虑到 DMA 地址只能在实际使用的时间内映射,并且在 DMA 传输之后不能映射。

    即使在不存在此类硬件的平台上,以下API当然也可以工作。

    请注意,DMA API 与底层微处理器体系结构无关的任何总线都可以工作。您应该使用 DMA API 而不是总线特定的 DMA API,即使用 DMA_map_*()接口而不是 pci_map_*()接口。

    首先,需要确保加入了头文件

    #include <linux/dma-mapping.h>
    

    在你的驱动程序中,它提供了 dma_addr_t 的定义。这种类型可以保存平台的任何有效 DMA 地址,并且应该在保存从 DMA 映射函数返回的 DMA 地址的任何地方使用。

    DMA可以使用什么内存?

    您必须知道的一条信息是DMA映射设备可以使用哪些内核内存。关于这一点有一套不成文的规则,本文试图最终把它们写下来。

    如果您是通过页面分配器获取内存的例如:(__get_free_page*()) 或者通用内存分配器或(kmalloc() or kmem_cache_alloc()) ,那么您可以使用从这些例程返回的地址来DMA访问该内存。

    这意味着您可以不使用从 vmalloc()返回的内存/地址进行DMA。但可以将DMA映射到 vmalloc()区域的底层内存,但这需要遍历页表来获取物理地址,然后使用 _va()之类的东西将每个页转换回内核地址。

    这个规则还意味着您既不能使用内核映像地址(data/text/bss 段中的项) ,也不能使用模块映像地址,也不能使用 DMA 的堆栈地址。这些都可以被映射到与其他物理内存完全不同的地方。即使这些内存类可以在物理上使用 DMA,您也需要确保 I/O 缓冲区是 cacheline 对齐的。如果不这样做,就会在 cpu 上看到使用 DMA-incoherent 缓存的 cacheline 共享问题(数据损坏)。(CPU 可以写入一个单词,DMA 可以写入同一个缓存行中的不同单词,并且其中一个可以被覆盖。)

    同样,这意味着您无法返回kmap()调用和DMA往返。 这类似于vmalloc()

    那么块 I/O 和网络缓冲区呢?块 I/O 和联网子系统确保它们使用的缓冲区对于 DMA from/to 来说是有效的。

    DMA寻址限制

    您的设备有DMA寻址限制吗? 例如,您的设备仅能驱动低序的24位地址吗?
    如果是这样,则需要将此事实通知内核。

    默认情况下,内核假定您的设备可以寻址完整的32位。
    对于支持64位的设备,这需要增加。 如前段所述,对于有局限性的设备,需要减少它。

    关于PCI的特别说明:PCI-X规范要求PCI-X设备支持所有事务的64位寻址(DAC)。
    当IO总线处于PCI-X模式时,至少有一个平台(SGI SN2)需要64位一致的分配才能正确运行。

    为了正确操作,您必须在设备探测例程中询问内核,以查看计算机上的DMA控制器是否可以正确支持设备具有的DMA寻址限制。
    即使您的设备保留默认设置,也要这样做,因为这表明您确实考虑了这些问题。你的设备。

    通过调用dma_set_mask_and_coherent()执行查询::

    int dma_set_mask_and_coherent(struct device *dev, u64 mask);
    

    它将同时查询流式API和一致性API的掩码。
    如果您有一些特殊要求,那么可以使用以下两个单独的查询代替:

    通过以下方式调用流映射查询 dma_set_mask()

    int dma_set_mask(struct device *dev, u64 mask);
    

    通过调用dma_set_coherent_mask()来执行一致分配的查询:

    int dma_set_coherent_mask(struct device *dev, u64 mask);
    

    这里,dev是指向设备的设备结构的指针,而mask是描述设备支持的地址的哪些位的位掩码。
    如果您的卡在给定的地址掩码的情况下可以在机器上正确执行DMA,则返回零。
    通常,设备的设备结构嵌入在设备的总线特定设备结构中。
    例如:&pdev->dev是指向PCI设备的设备结构的指针(pdev是指向设备的PCI设备结构的指针)。

    如果返回非零值,则您的设备将无法在此平台上正确执行DMA,
    并且尝试执行DMA将导致未定义的行为。 您必须使用其他掩码,或者不使用DMA。

    这意味着在失败的情况下,您有三个选择:

    1)如有可能,请使用另一个DMA掩码(请参见下文)。
    2)如果可能,请使用某些非DMA模式进行数据传输。
    3)忽略此设备,不要初始化它。

    建议您的驱动程序在执行 # 2或 # 3时打印一条内核 KERN_warning 消息。通过这种方式,如果您的驱动程序的用户报告性能不好或者甚至没有检测到设备,您可以要求他们提供内核消息,以找出确切的原因。
    标准的32位寻址设备将执行以下操作:

    if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
    	dev_warn(dev, "mydev: No suitable DMA available\n");
    	goto ignore_this_device;
    }
    

    另一个常见的场景是一个64位的设备。这里的方法是尝试64位寻址,但退回到不应该失败的32位掩码。内核可能会失败64位掩码,不是因为平台不能64位寻址。相反,在这种情况下它可能会失败,因为32位寻址比64位寻址效率更高。例如,Sparc64 PCI SAC 寻址比 DAC 寻址更有效。

    这是处理具有64位功能的设备的方法,该设备在访问流DMA时可以驱动所有64位:

    	int using_dac;
    
    	if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
    		using_dac = 1;
    	} else if (!dma_set_mask(dev, DMA_BIT_MASK(32))) {
    		using_dac = 0;
    	} else {
    		dev_warn(dev, "mydev: No suitable DMA available\n");
    		goto ignore_this_device;
    	}
    

    如果卡也能够使用64位一致分配,则情况如下所示:

    int using_dac, consistent_using_dac;
    
    if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
    	using_dac = 1;
    	consistent_using_dac = 1;
    } else if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
    	using_dac = 0;
    	consistent_using_dac = 0;
    } else {
    	dev_warn(dev, "mydev: No suitable DMA available\n");
    	goto ignore_this_device;
    }
    

    相关掩码将始终能够设置与流式掩码相同或较小的掩码。
    但是,在极少数情况下,设备驱动程序仅使用一致性的分配,
    则必须检查dma_set_coherent_mask()的返回值。

    最后,如果您的设备只能驱动低24位地址,则可以执行以下操作:

    if (dma_set_mask(dev, DMA_BIT_MASK(24))) {
    	dev_warn(dev, "mydev: 24-bit DMA addressing not available\n");
    	goto ignore_this_device;
    }
    

    dma_set_mask()dma_set_mask_and_coherent()成功并返回零时,内核将保存您提供的这个掩码。稍后在进行 DMA 映射时,内核将使用此信息。

    目前我们知道有一个案例,值得在本文件中提及。如果你的设备支持多种功能(例如声卡提供播放和记录功能) ,而且各种不同的功能有不同的 DMA 寻址限制,你可能希望探测每个掩码,只提供机器可以处理的功能。对 dma_set_mask()的最后一个调用是针对最特定的掩码的,这一点很重要。

    这是伪代码,显示了如何完成此操作::

    	#define PLAYBACK_ADDRESS_BITS	DMA_BIT_MASK(32)
    	#define RECORD_ADDRESS_BITS	DMA_BIT_MASK(24)
    
    	struct my_sound_card *card;
    	struct device *dev;
    
    	...
    	if (!dma_set_mask(dev, PLAYBACK_ADDRESS_BITS)) {
    		card->playback_enabled = 1;
    	} else {
    		card->playback_enabled = 0;
    		dev_warn(dev, "%s: Playback disabled due to DMA limitations\n",
    		       card->name);
    	}
    	if (!dma_set_mask(dev, RECORD_ADDRESS_BITS)) {
    		card->record_enabled = 1;
    	} else {
    		card->record_enabled = 0;
    		dev_warn(dev, "%s: Record disabled due to DMA limitations\n",
    		       card->name);
    	}
    

    这里使用声卡作为例子,因为这种类型的 PCI 设备似乎充斥着给定 PCI 前端的 ISA 芯片,因此保留了 ISA 的16mb DMA 寻址限制。

    DMA映射的类型

    DMA映射有两种类型:

    1. 一致的DMA映射,通常在驱动程序初始化时进行映射,结束时解除映射, 并且硬件应保证设备和CPU可以并行访问数据,并且可以看到彼此进行的更新,而无需任何显式的软件刷新。

      将“一致”视为“同步”或“连贯”。 当前的默认值是在DMA空间的低32位中返回一致的内存。 但是,为了将来的兼容性,即使此默认值适合您的驱动程序,也应设置一致的掩码。
      关于使用一致映射的示例如下:

      • 网卡DMA环描述符。
      • SCSI适配器邮箱命令数据结构。
      • 设备固件微码从主存储器中执行。

      这些示例都要求不变的是,任何存储在内存中的CPU都对设备立即可见,反之亦然。
      一致的映射可确保这一点。
      重要
      一致的DMA内存并不排除使用适当的内存屏障。CPU可能会将存储重新排序到一致的内存,就像 它可能会正常存储一样。 例如: 如果设备看到描述符的第一个字在第二个字之前更新是很重要的,你必须这样做:

    		desc->word0 = address;
    		wmb();
    		desc->word1 = DESC_VALID;
    
    为了在所有平台上获得正确的行为。
    此外,在某些平台上,驱动程序可能需要刷新 CPU 写缓冲区,就像它需要刷新 PCI 桥中的写缓冲区一样(比如在写入后读取寄存器的值)。
    
    1. 流式 DMA 映射,通常映射为一个 DMA 传输,映射后立即取消映射(除非您使用下面的 DMA_sync_*) ,并且硬件可以为顺序访问优化这些映射。
      可以将“流”看作“异步”或“一致性域之外”。
      使用流映射的好例子有:
      • 设备传输/接收的网络缓冲区。
      • 由 SCSI 设备写/读的文件系统缓冲区。

    使用这种类型映射的接口设计成这样一种方式,即实现可以进行硬件允许的任何性能优化。为此,在使用此类映射时,必须明确说明希望发生什么。

    任何一种 DMA 映射都没有来自底层总线的对齐限制,尽管有些设备可能有这样的限制。此外,当底层缓冲区不与其他数据共享缓存线时,具有非 dma 一致性缓存的系统工作得更好。

    使用一致的 DMA 映射

    To allocate and map large (PAGE_SIZE or so) consistent DMA regions,
    you should do::
    要分配和映射大型(PAGE_size左右)一致的 DMA 区域,您应该:

    	dma_addr_t dma_handle;
    
    	cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, gfp);
    

    其中dev是一个 struct device *。这可以在中断上下文中用 GFP_ATOMIC 标志调用。
    size 是要分配的区域的长度,以字节为单位。

    这个例程将为该区域分配 RAM,因此它的行为类似于 __get_free_pages()(但是采用大小而不是页面顺序)。如果您的驱动程序需要比页面小的区域大小,您可能更喜欢使用 dma_pool接口,如下所述。

    对于非 NULL dev(non-NULL dev),一致的 DMA 映射接口在缺省情况下将返回一个32位可寻址的 DMA 地址。即使设备指示(通过 DMA 掩码)它可以寻址上面的32位,如果通过 dma_set_coherent_mask()显式地改变了一致的 DMA 掩码,那么一致分配将只返回大于32位的 DMA 地址。dma_pool 接口也是如此。

    dma_alloc_coherent()返回两个值: 可用于从 CPU 访问它的虚拟地址和传递给卡的 dma_handle

    CPU虚拟地址和 DMA地址区域都保证对齐到最小的 PAGE_SIZE,该区域大于或等于请求的大小。这个不变量的存在(例如)是为了保证,如果分配的块小于或等于64千字节,那么您接收到的缓冲区的范围将不会跨越64K 的边界。

    要取消映射和释放这样一个 DMA 区域,您可以调用:

    dma_free_coherent(dev, size, cpu_addr, dma_handle);
    

    其中devsize与上面的调用相同,并且返回给您的值dma_alloc_coherent()cpu_addrdma_handle。这个函数不能在中断上下文中调用。

    如果您的驱动程序需要很多较小的内存区域,您可以编写自定义代码来细分dma_alloc_coherent()返回的页,或者您可以使用dma_pool API 来实现这一点。dma_pool类似于 kmem_cache缓存,但它使用dma_alloc_coherent() ,而不是 __get_free_pages()。此外,它还能理解常见的硬件约束对齐,比如队列头需要在 n 个字节边界上对齐。

    创建一个 dma_pool

    像这样创建一个 dma_pool:

    struct dma_pool *pool;
    
    pool = dma_pool_create(name, dev, size, align, boundary);
    

    name用于诊断(如kmem_cache名称) ; devsize 如上所示。对于这种类型的数据,设备的硬件对齐要求是align(以字节表示,必须是2的幂)。如果您的设备没有边界跨越限制,传递0表示边界; 传递4096表示从这个池分配的内存不能跨越4KByte 边界(但是在那个时候最好直接使用 dma_alloc_coherent())。

    从 DMA 池中分配内存

    cpu_addr = dma_pool_alloc(pool, flags, &dma_handle);
    

    如果允许阻塞(不是in_interrupt,也不持有 SMP 锁) ,则标志为 GFP_KERNEL,否则为 GFP_ATOMIC。与dma_alloc_coherent()一样,这返回两个值: cpu_addrdma_handle

    释放dma_pool中申请的内存:

    dma_pool_free(pool, cpu_addr, dma_handle);
    

    其中 pool 是传递给 dma_pool_alloc()的值,cpu_addrdma_handle是返回的值 dma_pool_alloc()。这个函数可以在中断上下文中调用。

    销毁dma_pool

    dma_pool_destroy(pool);
    

    在销毁池之前,确保为从池中分配的所有内存调用了dma_pool_free()释放内存。这个函数不能在中断上下文中调用。

    DMA方向

    本文后续部分描述的接口采用 DMA 方向参数,这是一个整数,并采用以下值之一:

     DMA_BIDIRECTIONAL
     DMA_TO_DEVICE
     DMA_FROM_DEVICE
     DMA_NONE
    

    你应该提供准确的 DMA 方向,如果你知道的话。

    • DMA_TO_DEVICE 意思是”从主存储器到设备”
    • DMA_FROM_DEVICE 意思是”从设备到主存储器”

    它是在 DMA 传输过程中数据移动的方向。
    我们强烈建议你尽可能精确地说明这一点。

    如果您完全不知道 DMA 传输的方向,请指定 DMA_BIDIRECTIONAL。这意味着 DMA 可以朝任何一个方向发展。该平台保证您可以合法地指定这一点,并且它将工作,但是这可能会以性能为代价。

    DMA_NONE 用于调试。在你知道精确的方向之前,你可以在数据结构中保持这个,这将有助于捕捉到你的方向跟踪逻辑没有正确设置事情的情况。

    精确指定这个值的另一个优点(除了可能的特定于平台的优化之外)是用于调试。有些平台实际上有一个写权限布尔值,DMA 映射可以用它来标记,很像用户程序地址空间中的页面保护。当 DMA 控制器硬件检测到违反权限设置的情况时,这些平台可以并且确实报告内核日志中的错误。

    只有流映射隐式地指定了一个方向,一致映射具有 DMA_BIDIRECTIONAL 的方向属性设置。

    SCSI 子系统告诉您在您的驱动程序正在处理的 SCSI 命令的sc_data_direction成员中使用的方向。

    对于网络驱动程序,这是一个相当简单的事情。对于传输数据包,使用 DMA_TO_DEVICE方向说明符map/unmap它们。对于接收数据包,恰恰相反,使用 DMA_FROM_DEVICE 方向说明符map/unmap它们。

    使用流 DMA 映射

    可以从中断上下文调用流式 DMA 映射程序。每个map/unmap有两个版本,一个版本将map/unmap单个内存区域,另一个版本将map/unmap一个散射列表。

    映射单个区域

    	struct device *dev = &my_dev->dev;
    	dma_addr_t dma_handle;
    	void *addr = buffer->ptr;
    	size_t size = buffer->len;
    
    	dma_handle = dma_map_single(dev, addr, size, direction);
    	if (dma_mapping_error(dev, dma_handle)) {
    		/*
    		 * reduce current DMA mapping usage,
    		 * delay and try again later or
    		 * reset driver.
    		 */
    		goto map_error_handling;
    	}
    

    取消映射单个区域

    dma_unmap_single(dev, dma_handle, size, direction);
    

    您应该调用 dma_mapping_error(),因为dma_map_single()可能失败并返回错误。这样做将确保映射代码能够在所有 DMA 实现上正确工作,而不依赖于底层实现的细节。在不检查错误的情况下使用返回的地址可能会导致从恐慌到静默数据损坏等各种失败。这同样适用于 dma_map_page()

    当 DMA 活动完成时,你应该调用 dma_unmap_single(),例如,从告诉你 DMA 传输已经完成的中断。

    对于单个映射使用这样的 CPU 指针有一个缺点: 您不能以这种方式引用HIGHMEM内存。因此,存在一个类似于 dma_{map,unmap}_single()map/unmap接口对。这些接口处理page/offset对,而不是 CPU 指针。
    实例伪代码:

    struct device *dev = &my_dev->dev;
    dma_addr_t dma_handle;
    struct page *page = buffer->page;
    unsigned long offset = buffer->offset;
    size_t size = buffer->len;
    
    dma_handle = dma_map_page(dev, page, offset, size, direction);
    if (dma_mapping_error(dev, dma_handle)) {
    	/*
    	 * reduce current DMA mapping usage,
    	 * delay and try again later or
    	 * reset driver.
    	 */
    	goto map_error_handling;
    }
    ...
    dma_unmap_page(dev, dma_handle, size, direction);
    

    在这里,offset意味着给定页面中的字节偏移量。

    您应该调用dma_mapping_error() ,因为 dma_map_page()可能会失败并返回错误,这在 dma_map_single()讨论中已有概述。

    当 DMA 活动完成时,你应该调用 dma_unmap_page(),例如,从告诉你 DMA 传输已经完成的中断。

    使用散列表,可以通过以下方式映射从多个区域聚集的区域:

    int i, count = dma_map_sg(dev, sglist, nents, direction);
    struct scatterlist *sg;
    
    for_each_sg(sglist, sg, count, i) {
    	hw_address[i] = sg_dma_address(sg);
    	hw_len[i] = sg_dma_len(sg);
    }
    

    其中 nentssglist中的条目数。

    这个实现可以自由地将几个连续的sglist条目合并为一个(例如,如果 DMA 映射是用 PAGE_SIZE 粒度完成的,那么只要第一个条目结束,第二个条目开始于页面边界,任何连续的 sglist 条目都可以合并为一个条目——事实上,这对于卡片来说是一个巨大的优势,因为它既不能进行分散收集,也不能进行非常有限的分散收集条目scatter-gather entries) ,并返回它映射到的 sg 条目的实际数量。失败返回0。

    然后您应该使用循环计数次数(注意: 次数可以小于 nents 次) ,并使用 sg_dma_address()sg_dma_len()宏来访问前面所示的 sg->addresssg->length

    解除映射散列表

    dma_unmap_sg(dev, sglist, nents, direction);
    

    同样,确保 DMA 活动已经结束。

    注意:
    调用的nents参数必须与传递给dma_unmap_sg 调用的nents参数相同,它不应该是从 dma_map_sg调用返回的count值。

    每个 dma_map_{single,sg}()调用都应该有它的 dma_unmap_{single,sg}()对应物,因为 DMA 地址空间是共享资源,您可能会通过消耗所有 DMA 地址使机器无法使用。

    如果您需要多次使用同一个流式 DMA 区域,并在 DMA 传输之间触摸数据,那么缓冲区需要正确同步,以便 CPU 和设备查看 DMA 缓冲区的最新和正确副本。

    因此,首先,只需将其映射为dma_map_{single,sg}(),并且在每个 DMA 传输调用之后:

    dma_sync_single_for_cpu(dev, dma_handle, size, direction);
    

    或者:

    	dma_sync_sg_for_cpu(dev, sglist, nents, direction);
    

    视情况而定。

    然后,如果你想让设备再次进入 DMA 区域,要在 CPU 完成数据访问之后,在给硬件调用缓冲区之前调用一下函数:

    dma_sync_single_for_device(dev, dma_handle, size, direction);
    

    或者:

    dma_sync_sg_for_device(dev, sglist, nents, direction);
    

    视情况而定。

    注意:
    dma_sync_sg_for_cpu()dma_sync_sg_for_device()nents参数必须传递给dma_map_sg()。它是 dma_map_sg()返回的计数。

    在上次 DMA 传输调用之后,DMA 取消映射例程 dma_unmap_{single,sg}()。如果从第一次dma_map_*()调用直到 dma_unmap_*()都没有触及数据,那么就根本不需要调用dma_sync_*()例程。

    下面是伪代码,它显示了你需要使用 dma_sync_*()接口的情况:

    my_card_setup_receive_buffer(struct my_card *cp, char *buffer, int len)
    {
    	dma_addr_t mapping;
    
    	mapping = dma_map_single(cp->dev, buffer, len, DMA_FROM_DEVICE);
    	if (dma_mapping_error(cp->dev, mapping)) {
    		/*
    		 * 减少当前的DMA映射使用率,延迟并稍后重试或重置驱动程序。
    		 */
    		goto map_error_handling;
    	}
    
    	cp->rx_buf = buffer;
    	cp->rx_len = len;
    	cp->rx_dma = mapping;
    
    	give_rx_buf_to_card(cp);
    }
    
    ...
    
    my_card_interrupt_handler(int irq, void *devid, struct pt_regs *regs)
    {
    	struct my_card *cp = devid;
    
    	...
    	if (read_card_status(cp) == RX_BUF_TRANSFERRED) {
    		struct my_card_header *hp;
    
    		/*
    		 * 检查标题以查看是否要接受数据。 
    		 * 但是先将DMA传输与CPU同步,以便我们看到更新的内容。
    		 */
    		dma_sync_single_for_cpu(&cp->dev, cp->rx_dma,
    					cp->rx_len,
    					DMA_FROM_DEVICE);
    
    		/*现在可以安全地检查缓冲区了。 */
    		hp = (struct my_card_header *) cp->rx_buf;
    		if (header_is_ok(hp)) {
    			dma_unmap_single(&cp->dev, cp->rx_dma, cp->rx_len,
    					 DMA_FROM_DEVICE);
    			pass_to_upper_layers(cp->rx_buf);
    			make_and_setup_new_rx_buf(cp);
    		} else {
    			/* 
    			 * CPU不应写入DMA_FROM_DEVICE映射的区域,
    			 * 因此此处不需要dma_sync_single_for_device()。 
    			 * 如果修改了内存,则需要DMA_BIDIRECTIONAL映射。
    			 */
    			give_rx_buf_to_card(cp);
    		}
    	}
    }
    

    完全转换为此接口的驱动程序不应再使用 virt_to_bus(),也不应该使用bus_to_virt()。有些驱动程序需要稍微修改一下,因为在动态 DMA 映射方案中不再有类似于 bus_to_virt()的等价物——您必须总是将 dma_alloc_coherent()dma_pool_alloc()返回的 DMA 地址存储起来,而 dma_map_single()调用(dma_map_sg()存储在 scatterlist本身中,如果平台在硬件中支持动态 DMA 映射) ,则存储在驱动结构和/或寄存器中。

    所有驱动程序都应该使用这些接口,没有例外。计划完全删除 virt_to_bus()bus_to_virt(),因为它们完全不推荐使用。一些端口已经不提供这些功能,因为不可能正确地支持它们。

    错误处理

    DMA 地址空间在某些体系结构上是有限的,分配失败可以通过以下方式来确定:

    • 检查 dma_alloc_coherent()是否返回 NULL 或 dma_map_sg 返回0

    • 检查从 dma_map_single()dma_map_page()返回的 dma_addr_t:
      通过使用dma_mapping_error():

    dma_addr_t dma_handle;
    
    dma_handle = dma_map_single(dev, addr, size, direction);
    if (dma_mapping_error(dev, dma_handle)) {
    	/*
    	 * reduce current DMA mapping usage,
    	 * delay and try again later or
    	 * reset driver.
    	 */
    	goto map_error_handling;
    }
    
    • 当多页映射尝试中出现映射错误时,取消映射已映射的页。这些示例也适用于 dma_map_page()

    示例1:

    dma_addr_t dma_handle1;
    dma_addr_t dma_handle2; 
    
    dma_handle1 = dma_map_single(dev, addr, size, direction);
    if (dma_mapping_error(dev, dma_handle1)) {
    	/*
    	 * 减少当前的DMA映射使用率,延迟并稍后重试或重置驱动程序。
    	 */
    	goto map_error_handling1;
    }
    dma_handle2 = dma_map_single(dev, addr, size, direction);
    if (dma_mapping_error(dev, dma_handle2)) {
    	/*
    	 * 减少当前的DMA映射使用率,延迟并稍后重试或重置驱动程序。
    	 */
    	goto map_error_handling2;
    }
    
    ...
    
    map_error_handling2:
    	dma_unmap_single(dma_handle1);
    map_error_handling1:
    

    示例 2::

    /*
     * 如果在循环中分配了多个缓冲区,则在中间检测到映射错误时,取消映射所有映射的缓冲区
     */
    
    dma_addr_t dma_addr;
    dma_addr_t array[DMA_BUFFERS];
    int save_index = 0;
    
    for (i = 0; i < DMA_BUFFERS; i++) {
    
    	...
    
    	dma_addr = dma_map_single(dev, addr, size, direction);
    	if (dma_mapping_error(dev, dma_addr)) {
    		/*
    		 * 减少当前的DMA映射使用率,延迟并稍后重试或重置驱动程序。
    	 	*/
    		goto map_error_handling;
    	}
    	array[i].dma_addr = dma_addr;
    	save_index++;
    }
    
    ...
    
    map_error_handling:
    
    for (i = 0; i < save_index; i++) {
    
    	...
    
    	dma_unmap_single(array[i].dma_addr);
    }
    

    如果 DMA 映射在传输钩子(ndo_start_xmit)上失败,网络驱动程序必须调用 dev_kfree_skb()来释放套接字缓冲区并返回 NETDEV_TX_OK。这意味着套接字缓冲区只是在故障情况下被删除。

    如果排队指令钩子中的 DMA 映射失败,SCSI 驱动程序必须返回 SCSI_MLQUEUE_HOST_BUSY。这意味着 SCSI 子系统稍后将命令再次传递给驱动程序。

    优化未映射状态空间消耗

    在许多平台上,dma_unmap_{single,page}()只是一个 nop。因此,跟踪映射地址和长度是对空间的浪费。与其让您的驱动程序充满 ifdefs 之类的东西来“解决work around”这个问题(这会破坏可移植 API 的整个目的) ,不如提供以下设施。
    实际上,我们不是逐个描述宏,而是转换一些示例代码。

    1. 在状态保存结构中使用 DEFINE_DMA_UNMAP_{ADDR,LEN}
      示例:
      优化前:
    struct ring_state {
    	struct sk_buff *skb;
    	dma_addr_t mapping;
    	__u32 len;
    };
    

    优化后:

    struct ring_state {
    	struct sk_buff *skb;
    	DEFINE_DMA_UNMAP_ADDR(mapping);
    	DEFINE_DMA_UNMAP_LEN(len);
    };
    
    1. 使用dma_unmap_{addr,len}_set()来设置这些值。
      示例:
      优化前:
    ringp->mapping = FOO;
    ringp->len = BAR;
    

    优化后:

    dma_unmap_addr_set(ringp, mapping, FOO);
    dma_unmap_len_set(ringp, len, BAR);
    
    1. 使用dma_unmap_{addr,len}()来访问这些值.
      示例:
      优化前:
    dma_unmap_single(dev, ringp->mapping, ringp->len,
    		 DMA_FROM_DEVICE);
    

    优化后:

    dma_unmap_single(dev,
    		 dma_unmap_addr(ringp, mapping),
    		 dma_unmap_len(ringp, len),
    		 DMA_FROM_DEVICE);
    

    这应该是不言自明的。我们将 ADDRLEN 分开处理,因为一个实现只需要地址就可以执行 unmap 操作。

    平台问题

    如果您只是在为 Linux 编写驱动程序,而没有维护内核的体系结构端口,那么您可以安全地跳到Closing

    1. 结构散布式要求。

      如果架构支持 IOMMU (包括软件 IOMMU) ,则需要启用 CONFIG_NEED_SG_DMA_LENGTH

    2. ARCH_DMA_MINALIGN
      架构必须确保 kmalloc'ed 缓冲区是 dma 安全的。驱动器和子系统都依赖于它。如果体系结构不是完全符合dma 的(即硬件不能确保CPU 缓存中的数据与主存中的数据相同) ,那么 ARCH_DMA_MINALIGN 必须设置,以便内存分配器确保 kmalloc'ed 缓冲区不与其他缓冲区共享缓存线路。以 arch/arm/include/asm/cache.h 为例。
      注意 ARCH_DMA_MINALIGN 是关于 DMA 内存对齐约束的。您不必担心架构数据对齐约束(例如64位对象的对齐约束)。

    展开全文
  • aurix中DMA使用

    千次阅读 2015-07-06 19:40:23
    首先请注意:DMA的源/目标地址必须是64位对齐 DMA就是从数据源到DMA控制器,再从DMA控制器到目标源。 DMA硬件请求包括自身的请求...设置DMA通道,DMA shadow reg的作用是体现在link DMA使用的时候,指定Shadow Addr

    首先请注意:DMA的源/目标地址必须是64位对齐
    这里写图片描述
    DMA就是从数据源到DMA控制器,再从DMA控制器到目标源。
    DMA硬件请求包括自身的请求或其他的DMA请求通道。
    DMA控制器主要由这三部分组成:DMA channel 、 move engine 、 bus switch
    设置DMA通道,DMA shadow reg的作用是体现在link DMA使用的时候,指定Shadow Addr,等上一段搬完后,能自动把shadow addr赋值到源或者目标地址,开始搬运下一段。
    DMA通道请求控制
    这里写图片描述
    然而触发dma请求,可以通过硬件或软件
    硬件可以由ICU中断单元触发,硬件请求通过TSRz.HTRE.使能或不使能,需要dma转化后,软件reset该位。
    软件请求则是直接设置 CHCSRz.SCH位

    软件操作模式:
    这里写图片描述
    软件操作时通过TSRz.HTRE位不使用硬件操作。
    硬件操作模式:
    ICU中断触发,TSRz.ECH位需要使能硬件模式。
    如果要使用硬件中断请求DMA,一定要注意中,中断优先级SRPN的设置!原话
    这里写图片描述
    说白了,也就是外设的中断如果是向DMA请求,则设置中断优先级一定要等于待处理的DMA的通道ID号,如果不一致,这触发不了该DMA的通道工作。
    还有就是,如果要使用硬件中断控制DMA,进行DMA配置的部分一定要在enable interrupt之前。

    下面则详细说一下DMA整个控制顺序,如下:
    这里写图片描述
    Pending的通道通过DMA仲裁后,选择优先级高的active,给move engine去搬运,其中搬运的时候经过SRI总线,有bus switch来转换。
    这里写图片描述
    其中在bus switch这里的优先级已经确定,Cerberus是作为bus switch的看门狗
    这里写图片描述
    这是在SRI中优先级,然而对于move engine访问spb资源,则move engine 的优先级则需要设置:
    这里写图片描述

    展开全文
  • 海思IVE函数使用1 (DMA使用 HI_MPI_IVE_DMA) 图像算法优化
  • ZYNQ系列(十二)linux的DMA使用 文章目录ZYNQ系列(十二)linux的DMA使用前言 前言
  • L4+系列DMA使用STM32L4系列DMA资源分配图关于L4+系列DMA使用 关于STM32L4&L4+系列DMA使用 STM32L4系列DMA资源分配图 由资源分配图可以得出STM32L4外设使用DMA通道的情况。 关于L4+系列DMA使用 STM32L4+系列是...
  • STM32 DMA使用详解

    2020-08-11 06:51:08
    DMA部分我用到的相对简单,当然,可能这是新东西,我暂时还用不到它的复杂功能吧。下面用问答的形式表达我的思路。
  • 闫刚 stm32-spi-DMA使用注意 Stm32的spi的DMA过程 安装 DMA先把数据发送到SPI1->DR, TXE位被清除 最后1个TXE,不会被DMA清除,发送完成数据,并不是接收最后1个字节发送完成 DMA为什么连续,...
  • stm32 DMA使用详解

    2014-09-19 13:17:00
    转自:http://www.cnblogs.com/121792730applllo/p/3154447.htmlSTM32 DMA使用详解DMA部分我用到的相对简单,当然,可能这是新东西,我暂时还用不到它的复杂功能吧。下面用问答的形式表达我的思路。DMA有什么用? ...
  • Nios_II_中的DMA使用

    2011-06-14 09:44:42
    altera Nios II 中的DMA使用 ,这是一个使用总结,非常好!!
  • linux之DMA使用

    2021-03-05 14:32:50
    一、对于使用DMA控制器有什么内存上限制? dma的内存要求内存上是连续的一片虚拟内存空间, 1、我们不要使用vmalloc以及kmalloc这些通过get_free_page()函数来触发系统异常来分配在内存上可能是不连续的内存地址,...
  • DMA使用注意事项

    2018-07-03 10:44:01
    1、DMA造成脏数据在使用DMA进行数据搬运时,当需要中途停止DMA的传输,需要先停止控制器的dma请求,再强制关闭DMA,最后再释放内存,否则有可能造成DMA搬运数据到释放过的内存中。2、省电对DMA的影响 在使用DMA将...
  • STM32外设DMA使用总结

    千次阅读 2015-06-13 17:24:03
    STM32外设DMA使用总结: 1、根据需要选择DAM模式: 2、对于DMA1的Chanel3,对应外设为USART3的RX 试想:如果串口接收中断和DAM中断同时打开,CPU如何相应? (1)中断优先级不同:这好说,支持嵌套中断(NVIC)的Cortex-...
  • STM32串口+DMA使用1

    千次阅读 2018-05-30 13:22:56
    STM32串口+DMA使用 STM32有5个串口资源(USART1,USART2,USART3及UART4,UART5)。其中3个USART(通用同步/异步收/发器universalsynchronous asynchronous receiver and transmitter);2个UART(通用异步收/发器...
  • STM32 DMA使用

    2019-06-25 10:34:35
    1.使能对应DMA时钟&中断 void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA1_CLK_ENABLE(); /* DMA interrupt init */ /* DMA1_Stream1_IRQn interrupt configuration */ HAL_...
  • DMA使用说明

    2007-01-10 20:36:00
    DMA使用说明DMA(Oracle Data Migration Agent)是ORACLE编写的UNIX下一个比较方便的数据迁移工具,可以在export的同时进行import,适合比较大数据量的exp/imp,能比较好的缩短数据迁移的时间。它是使用UNIX的管道,...
  • CubeMX STM32串口1DMA使用IDLE中断接收、串口2DMA接收DMX512信号(标准)DMX512协议CubeMX代码部分串口1生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚...
  • STM32F030-UART1_DMA使用提示

    千次阅读 2019-09-25 14:40:45
    STM32F030-UART1_DMA使用提示 前言: 今天把STM32F030C8T6的串口DMA学习了一下,为了加快各位研发人员的开发进度,避免浪费大量的时间在硬件平台上,写出个人代码调试的经验。个人水平有限,如有错误,还请指正mr...
  • 1 为什么要用DMA 2 什么时候需要DMA 3 DMA使用前后对比
  • STM32的DMA使用记录

    2020-06-16 22:27:26
    DMA
  • 这次我说的是三星平台的dma,不是三星的某款芯片的dma使用。这主要得益于三星公司统一了接口。比如我后有的例子是在s3c2440上做的但是我是参考s3c64xx的spi驱动。 当然内核还是linux-3.2.36,我们看dma-ops.h /* ...
  • stm32的DMA使用

    2020-08-28 17:19:39
    编写我们的DMA控制函数,表明用哪个DMA的数据流的哪个通道,源,目的,长度 MYDMA_Config(DMA2_Stream7,4,(u32)&USART1->DR,(u32)SendBuff,SEND_BUF_SIZE); DMA2,STEAM7,CH4,外设为串口1,存储器为SendBuff,长度为...
  • 52832的RAM DMA使用

    2020-12-04 10:37:26
    使用DMA的时候需要把局部变量拷贝为静 态变量再使用函数调用DMA 举例 void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len) { uint8_t spi_data[3]; uint16_t i; WIZCHIP_CRITICAL_ENTER(); ...
  • STM32 DAC DMA 使用

    2020-11-11 13:34:07
    目的:STM32 DAC DMA 环形发送音频数据;(ffmpeg.exe 可以将一些常见的音频文件转为原始数据,很强大); 用到的外设:DAC ,TIM,DMA DCA配置 TIM配置 加入代码 HAL_TIM_Base_Start_IT(&...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,958
精华内容 1,983
关键字:

dma使用