AXI DMA总结、内核axidmatest.c测试程序分析、SG mode

2023-05-16

AXI DMA

概述:

  1. XILINX提供的AXI DMA支持Scatter/Gather mode和Direct Register mode

  1. 数据位宽支持32,64,128,256,512,1024bits,stream数据位宽支持8,16,32,64,128,256,512,1024bits,这里数据位宽表示DDR到上图中DataMover的数据位宽,stream数据位宽表示的DataMover到设备的数据位宽,表示一次可以传输多少位的数据。最高支持64bit地址。
  2. AXI DMA在Scatter/Gather mode下可以支持16个通道进行数据传输。
  3. 最大频率及速率

Direct Register mode寄存器:

该模式下有MM2S_DMACR、MM2S_DMASR、MM2S_SA、MM2S_SA_MSB、MM2S_LENGTH、S2MM_DMACR、S2MM _DMASR、S2MM _DA、S2MM _SA_MSB、S2MM _LENGTH。DMACR(DMA控制寄存器),DMASR(DMA状态寄存器),DMA_SA、DMA_DA(源地址和目的地址寄存器),LENGTH(数据长度寄存器),MM2S表示内存到设备的数据传输,S2MM表示设备到内存的数据传输。

  • DMACR控制寄存器:该寄存器可以设置DMA软复位和启动DMA传输以及相关标志位的使能(比如中断标志和错误标志等)。

   

  • DMASR状态寄存器:该寄存器可以获取DMA的各种状态,例如中断标志、错误标志以及DMA是否传输完成等。

   

 

  • DMASA源地址寄存器:该寄存器的值表示DMA从内存的何处地址开始搬移数据到设备。

  • DMADA目的地址寄存器:该寄存器的值表示DMA从设备搬移数据到内存的什么地址。

  • LENGTH长度寄存器:该寄存器表示DMA传输的数据长度。

MM2S传输步骤(S2MM传输步骤一样,设置对应寄存器即可):

  1. 设置MM2S_DMACR.RS = 1;设置后DMASR.Halted为1,表示MM2S channel在running。
  2. 如果希望使能中断,设置MM2S_DMACR.IOC_IrqEn和MM2S_DMACR.Err_IrqEn位为1。
  3. 写地址到MM2S_SA寄存器,地址必须4字节对齐(也就是地址只能以0、4、8、c结尾)。
  4. 写传输的数据长度到LENGTH寄存器。

内核驱动分析,(驱动分控制器驱动和设备驱动):

设备树:

DMA控制器设备树:

这里只是发送通道的,接收通道的只是名字不一样,然后寄存器的偏移地址不一样

MAC_axi_dma_0: dma@40400000 {

     #dma-cells = <1>;

  clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk";

     clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>;

     compatible = "xlnx,axi-dma-1.00.a";

     //interrupt-parent = <&intc>;

     //interrupts = <0 31 4>;

     reg = <0x40400000 0x10000>;

     xlnx,addrwidth = <0x20>;

     dma-channel@40400000 {

        compatible = "xlnx,axi-dma-mm2s-channel";

          dma-channels = <0x1>;

          //interrupts = <0 31 4>;

          xlnx,datawidth = <0x20>;

          xlnx,device-id = <0x0>;

     };

};

DMA 测试驱动设备树:

dmatest_0: dmatest@0 {

  compatible ="xlnx,axi-dma-test-1.00.a";

  dmas = <&axi_dma_0 0 &axi_dma_0 1>;

  dma-names = "axidma0", "axidma1";

} ;

DMA设备驱动设备树:
ad9361_vnet: ad9361_vnet@40400000 {

     compatible = "ad9361_vnet";

     reg = < 0x40400000 0x1000

           0x40410000 0x1000

           0x40420000 0x1000

           0x40430000 0x1000

           0x40440000 0x1000

           0x40450000 0x1000
            
           0x40460000 0x1000
           //mac reg

           0x40000000 0x10000

           //axi intc reg

           0x41800000 0x10000

           //bram

           0x42000000 0x10000

           //fpga version

           0x43c10000 0x10000

     >;

     interrupt-parent = <&intc>;

     interrupts = <0 31 4>;

     //interrupts = <0 29 4>;

     dmas = <&MAC_axi_dma_0 0

           &MAC_axi_dma_1 0

           &MAC_axi_dma_2 0

           &MAC_axi_dma_3 0

           &MAC_axi_dma_4 0

           &MAC_axi_dma_5 0
            
           &MAC_axi_dma_6 0
     >;

     dma-names = "tx0","tx1","tx2","tx3","tx4","tx5","rx0";

};

控制器驱动(内核版本:4.9):

控制器设备树里compatible = "xlnx,axi-dma-1.00.a",使用的是drivers/dma/xilinx/xilinx_dma.c。

  • COMPATIBLE:

  • Probe函数:

 

以上代码获取了设备树里的地址以及其他属性的设置,比如地址位宽等。

这部分代码比较关键,根据DMA类型的不同,设置了设备驱动会调用的相关接口。

最后注册DMA设备。这段代码里还有一个probe函数,

xilinx_dma_child_probe:

函数里获取设备树里dma-channel的个数,调用

xilinx_dma_chan_probe:

处理设备树里的信息。

这部分代码根据设备树里dma-channel的compatible设置通道的传输方向,比如DMA_MEM_TO_DEV或者DMA_DEV_TO_MEM,根据不同的方向设置了desc寄存器的偏移地址等。

dma-channel@40400000 {

     compatible = "xlnx,axi-dma-mm2s-channel";

最后申请注册中断、复位通道。

XILINX DMA测试驱动(内核版本:4.9):

  • COMPATIBLE:

 

申请dma channel:

/**

 * dma_request_slave_channel - try to allocate an exclusive slave channel

 * @dev: pointer to client device structure

 * @name:  slave channel name

 *

 * Returns pointer to appropriate DMA channel on success or NULL.

 */

struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name)

该部分代码申请了DMA通道,调用dma_test_add_slave_channels函数,内容如下:

该函数中调用了dmatest_add_slave_threads,该函数创建了一个内核线程,如下:

线程调用的函数dmatest_slave_func主要是分配内存、构造数据、发送数据、校验数据;

分配内存:

Consistent DMA mappings(一致性):

函数原型:

static inline void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag)

使用方法:

dma_addr_t dma_handle;

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

………

dma_free_coherent(dev, size, cpu_addr, dma_handle);

Streaming DMA mapping(流式)

函数原型:

dma_map_single(dev, addr, size, direction);

使用方法:

  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;

}

Unmap:

dma_unmap_single(dev, dma_handle, size, direction);

两种方式分配的内存的区别:

  1. 一致性和流式最大的区别就是一致性分配的内存可以一直使用到最后不使用时释放即可,而流式分配的内存使用完一次以后必须释放重新申请。
  2. 一致性分配内存的方式,分配可以在中断上下文中,但释放不可以在中断上下文中释放,一般分配的内存较大。
  3. 流式分配无法使用高端内存,但提供了新的接口取代。
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);

   4.流式分配需要先分配好缓冲区,然后返回dma_addr_t地址,一致性是一次性分配好缓冲区和dma_addr_t。

更多信息参见

Kernel_code\Documentation\DMA-API-HOWTO.txt

Dma pool:

如果程序里需要使用很多很小的buffer,可以使用dma pool,dma pool类似于kmen_cache,它使用dma_alloc_coherent,非__get_free_pages,dma_alloc_coherent分配的内存比较大,dma pool使用dma_alloc_coherent分配出一块大的内存,在从中取一小部分使用。如下:

struct dma_pool *pool;

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

Allocate memory from a DMA pool:

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

Free memory:

dma_pool_free(pool, cpu_addr, dma_handle);

Destroy a dma_pool:

dma_pool_destroy(pool);

这里看一下dmatest_slave_func,了解dma使用的内存如何分配和使用。

程序里使用常规的函数分配出了CPU使用的地址,紧接着定义了completion,设置了超时时间,定义了两个散列表结构,代码里的rx_cmp以及rx_tmo用于判断传输是否超时或者完成,完成后则会调用设置的回调函数,回调函数的设置在后边的代码中,下边的代码获取了设备的地址位宽进行对齐,初始化了分配的空间,然后使用流式map的方式将分配的CPU地址和映射到dma使用地址,该函数设置了dma传输的方向和传输的长度。

紧接着在下边的代码中初始化了scatterlist,获取描述符

初始化了completion,设置了回调函数,提交并发起传输,等待传输完成。

最后释放分配的空间

获取传输描述符:

slave_sg - DMA a list of scatter gather buffers from/to a peripheral

dma_cyclic  - Perform a cyclic DMA operation from/to a peripheral till the operation is explicitly stopped.

interleaved_dma   - This is common to Slave as well as M2M clients. For slave address of devices' fifo could be already known to the driver.

Various types of operations could be expressed by setting appropriate values to the 'dma_interleaved_template' members.

  函数:       

 struct dma_async_tx_descriptor

*dmaengine_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_data_direction direction,unsigned long flags);

(slave_sg以散列表的形式可以一次性发起多次dma传输)

 struct dma_async_tx_descriptor

*dmaengine_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_data_direction direction);

(dmaengine_prep_dma_cyclic可循环的发起传输,类似于环形链表一般,进行循环传输)

         struct dma_async_tx_descriptor

*dmaengine_prep_interleaved_dma( struct dma_chan *chan, struct dma_interleaved_template *xt, unsigned long flags);

        (多用于M2M,进行内存到内存数据的拷贝)

提交传输、开始传输:

提交传输:

cookie = chan->desc->tx_submit(chan->desc);

  if (dma_submit_error(cookie)) {

     axidma_err("dma_submit_error.\n");

      }

开始传输:

  dma_async_issue_pending(tx_chan);

释放dma channel:

void dma_release_channel(struct dma_chan *chan)

测试驱动(内核版本:4.9):

直接操作寄存器:

DMA框架:

     

 

  1. 参考:
  1. Kernel_code\Documentation\DMA-API-HOWTO.txt
  2. Kernel_code\Documentation\client.txt
  3. Kernel_code\Documentation\provider.txt
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AXI DMA总结、内核axidmatest.c测试程序分析、SG mode 的相关文章

  • UART+DMA数据传输

    DMA的概念 DMA xff08 Direct Memory Access xff09 即直接内存访问 xff0c DMA传输方式无需CPU直接控制传输 xff0c 通过硬件为RAM I O设备开辟一条直接传输数据的通路 xff0c 能使C
  • AXI STREAM ,AXIS总线的理解

    全兼容ZEDBOARD 开发板子 SYSCLK TAOBAO COM 1 xff0c VALID和READY 是所有AXI总线必须有的 xff0c VALID是MASTER告诉SLAVE数据已经展现在了总线上了 xff0c 你可以取走了 x
  • ZYNQ系列(十二)linux的DMA使用

    ZYNQ系列 xff08 十二 xff09 linux的DMA使用 文章目录 ZYNQ系列 xff08 十二 xff09 linux的DMA使用前言开发环境准备工作petalinux工程建立建立工程配置内核1 配置DMA2 配置CMA 修改
  • 轮询、中断和DMA三种方式的原理和联系

    CPU控制外部设备的方式 xff1a 中断 轮询 DMA 轮询中断DMA 由于外部设备的速度差异 xff0c CPU可以使用不同的方式控制外部设备的访问 常见的方式轮询 中断和DMA 轮询 轮询最简单 xff0c CPU通过不断地查询某个外
  • 深入 AXI4 总线(一)握手机制

    VALID READY 握手机制 AXI 总线共有 5 个独立的通道 分别为写地址 写数据 写回应 读地址 读数据通道 5 条通道相互独立 有一些细小的差别 但共同使用一套握手机制 VALID READY 机制 VALID READY 机制
  • STM32ADC多通道采集(基于DMA)

    首先简单介绍DMA DMA Direct Memory Access 直接内存存取 用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输 无需CPU干预 节省CPU资源 ADC转换出来的值直接赋值给定义好的变量中 配置好的DMA可
  • FreeRTOS例程4-串口DMA收发不定长数据

    FreeRTOS例程4 串口DMA收发不定长数据 知乎 zhihu com
  • 深入 AXI4 总线(二)架构

    五个独立通道 AXI4 总线的一大特征是它有 5 个独立的传输通道 这些通道都只支持单向传输 作为类比 SPI 总线有 2 条传输通道 MISO MOSI SPI 输入输出的数据 大路朝天 各走一条 而作为对比 IIC 协议则只有 SDA
  • Xilinx ISE、MicroBlaze系列教程

    本文是Xilinx MicroBlaze系列教程的第0篇文章 这个系列文章是我个人最近两年使用Xilinx MicroBlaze软核的经验和笔记 以Xilinx ISE 14 7和Spartan 6 Vivado 2018 3和Artix
  • GD32F4xx MCU ADC+DMA 多通道采样

    1 GD32F4xx ADC GD32F4xx 的12位ADC是一种采用逐次逼近方式的模拟数字转换器 1 1 主要特征 可配置12位 10位 8位 6位分辨率 ADC采样率 12位分辨率为2 6MSPs 10位分辨率为3 0 MSPs 分辨
  • STM32CubeMX HAL库串口+DMA+IDLE空闲中断不定长度数据接收和发送

    本文开发环境 MCU型号 STM32F103ZET6 IDE环境 MDK 5 29 代码生成工具 STM32CubeMx 5 3 0 HAL库版本 STM32Cube FW F1 V1 8 0 STM32Cube MCU Package f
  • Numpy 中 Scipy 模式函数的替代方案?

    numpy 中是否有另一种方法来实现 scipy stats mode 函数以获取 ndarrays 中沿轴最频繁的值 无需导入其他模块 即 import numpy as np from scipy stats import mode a
  • 如何在 Vim 中实现类似 MATLAB 的单元格模式

    在 MATLAB 中 我们可以向编辑器写入以下内容 a example cell plot rand 3 another cell A rand 2 10 t linspace pi pi 2 10 compass fft A sin t
  • 在数组中查找模式的最有效方法?

    最近我尝试使用C来查找一组数字中的众数 当集合很小时 我的代码可以做得很好 这是我的代码 int frequency 10001 This array stores the frequency of a number that betwee
  • 如何 groupby().transform() 在数据框中查找模式?

    我有一个像这样的数据框 lst High A High A High B Medium A Medium B Medium C df pd DataFrame lst columns Class Grade 我需要获得每个 班级 中 等级
  • 将 NA 替换为基于 ID 属性的模式

    我有一个数据集dt我想更换NA值与mode基于 id 的每个属性如下 Before id att 1 v 1 v 1 NA 1 c 2 c 2 v 2 NA 2 c 我正在寻找的结果是 id att 1 v 1 v 1 v 1 c 2 c
  • 在jshell中创建自定义反馈模式

    从 jshell 中 set Feedback 的文档来看 有以下几种内置模式 verbose normal concise and silent 是否可以打造一种兼具简洁和静音功能的反馈模式 或者我们可以改变上述任何一种模式吗 或者我们可
  • PHP 5.2.17 的 round() 模式 ROUND_HALF_DOWN

    我需要在 PHP 5 2 17 中模拟 ROUND HALF DOWN 模式 我无法升级服务器的 PHP 版本 有什么想法如何实现这一目标 基本思想是 1 895 变成 1 89 而不是像通常使用 round 那样变成 1 90 编辑 这个
  • 复合颜色:iPhone 上的 CALayer 和混合模式

    我正在尝试在 iPhone 上使用核心图像 我可以使用石英合成颜色来绘制 uiview 但我想将每个组件分成CALayer UIview消耗较多资源 所以我有一个白色蒙版 我想用它来过滤背景位图 并且我想尝试不同的混合模式 不幸的是 这些图
  • 按频率对字符串数组进行排序的最有效方法

    我有一个字符串数组 String stringArray x y z x x y a 将其订购为更小的最快 最有效的方法是什么Collection按照每个频率的顺序String是和它的频率有关吗 我想使用String作为一个关键HashMa

随机推荐

  • POST请求返回:401 Unauthorized

    Postman 做接口测试 xff0c 提交请求后 xff0c 模拟获取数据 xff0c 输入入参正确时 xff0c 却返回status 401 Unauthorized 原因 xff1a 是我的token有误 xff0c token是一串
  • Django从header请求头中的Authorization获取token验证数据

    前言 之前使用django开发api接口时 xff0c 约定是要每次请求都要带token这个参数 xff0c 这样很不方便 xff0c 最近学了vue xff0c 也使用了axios xff0c 发现在axios拦截器中可以设置每次请求头中
  • char类型的数字转int

    char的本质 xff1a char The char data type is a single 16 bit Unicode character It has a minimum value of 39 u0000 39 or 0 an
  • Android串口通信

    编前记 今天在刷博客 郭老师 的时候评论区看见有人在聊单片机的串口通信 xff0c 刚好之前做过一个项目通过NFC读取IC门禁卡片的项目所以拿出来分享 复习 一下 xff0c 先讲了解一下什么是串口通信 xff1a 串口通信 xff08 S
  • Studio One 5机架设置一键切换效果通道

    Studio One是当前主流的直播机架软件 xff0c 操作非常方便 xff0c 但是呢默认情况下 xff0c 要切换效果时 xff0c 只能手动关闭一个效果的后 xff0c 再开另一个效果 xff0c 切换效果有点不方便 现在孤狼分享S
  • VScode设置C/C++编译环境详解

    一 xff1a 下载安装C C 43 43 编译器 在windows下有很多集成的编译器 xff0c 我们只是需要使用gcc exe 编译而已 xff0c 所以我们可以随便下 xff0c 这里推荐使用 xff1a MinGW xff1a x
  • 2021校招_大华

    大华面试 xff1a 一面和二面 一面 xff1a 首先自我介绍 1 序列化的使用方式以及情景 2 Springboot的启动过程 3 Mysq中lB 43 树和B树索引区别 xff0c 聚簇索引和非聚簇索引区别 4 Spring中bean
  • 2021校招_海康威视

    2021届海康威视面试 一面 xff1a 1 https与http协议的区别 2 Spring的启动过程 3 Springboot相比较Spring的优点 4 Linux修改文件权限命令 5 项目中所用到的技术 6 Restful风格 7
  • 2021校招_满帮(运满满)

    一面 xff08 电话面 xff09 xff1a 25min 1 询问HashMap相关结构以及原理 2 红黑树的基本结构 xff0c 以及什么时候会LL xff08 左转 xff09 3 Spring如何解决循环依赖的 4 Redis缓存
  • 2021校招_思科

    思科给我发的太晚了 xff0c 十一月份才给我消息 思科一面凉凉 主要是针对你的简历 问到我的主要内容包括 xff1a 数据库设计 xff0c 是否使用到设计模式 xff0c 以及遇到问题如何解决 包括ngnix xff0c redis h
  • 音视频开发之音频基础知识

    音视频开发之音频基础知识 转自https blog jianchihu net av develop audio basis html 什么是声音 介质振动在听觉系统中产生的反应 是一种波 因为是一种波 xff0c 所以我们可以用频率 振幅
  • 机器学习中神经网络,支持向量机以及贝叶斯分类器总结

    第五章神经网络 5 1神经元模型 神经网络中最基本的成分是神经元模型 xff0c 即 简单单元 在 M P神经元模型 中 xff0c 神经元接受收到来自n个其他神经元传递过来的输入信号 xff0c 这些输入信号经过带权重的连接进行传递 xf
  • 机器学习中的降维与度量学习(reduce dimension and metric learning)

    降维与度量学习 k近邻学习 k近邻 k Nearest Neighbor 简称kNN 学习是一种监督学习方法 其工作机制为 xff1a 在样本中 xff0c 根据距离度量找出训练集中临近的k个样本 xff0c 基于这k个样本进行预测 一般
  • Warning: Invalid argument “/map“ passed to canTransform argument target_frame in tf2 frame_ids···

    Warning Invalid argument map passed to canTransform argument target frame in tf2 frame ids cannot start with a like at l
  • CAN为什么会发送失败

    CAN总线调试过程中出现报文发送失败 xff0c 很多工程师都对此只知其一不知其二 xff0c 这里就CAN报文发送失败的问题我们来做一次探讨 在了解CAN报文为什么会发送失败之前我们先看看一条正确的CAN报文到底应该是怎么样的 xff0c
  • git分支和tag

    分支管理 查看当前分支 git branch创建分支 git branch git branch index one切换分支 git checkout lt 分支名称 xff0c 主分支是master gt git checkout ind
  • TT无人机扩展模块库分析(default.ino)补篇2

    这个简单 请对照 因为源码在这里出现了和手柄相关的源码 设置tof传感器的超时时间 xff08 500 xff09 什么单位 xff1f 没有搜索到 xff0c 我用SI了 搜索到了 有很多函数 定位位置 在这里 找到了 xff0c 为什么
  • TCP建立连接的过程

    TCP是面向连接的 可靠的 基于字节流的传输层协议 xff0c 是TCP IP协议中最重要的协议之一了 我们都知道TCP通过三次握手建立连接 xff0c 那么每一次握手的作用 为什么要三次握手 如果某次握手丢包会发生什么呢 xff1f 文章
  • CANanlystII 基于linux的二次开发实践

    1 USBCAN分析仪国内现状 这是目前国内市场上的USBCAN分析仪现状 2 创芯科技产品 创芯科技的这个红色盒子是我比较下来综合性价比最高的 同时支持windows和linux的设备只要320元左右 你既可以用可视化界面发送 接收报文
  • AXI DMA总结、内核axidmatest.c测试程序分析、SG mode

    AXI DMA 概述 xff1a XILINX提供的AXI DMA支持Scatter Gather mode和Direct Register mode 数据位宽支持32 64 128 256 512 1024bits xff0c strea