- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试在基于 Zynq-7000 的平台上使用 DMA 引擎将 PCM 流传输到 Zynq PL 中的自定义 I2S Controller 。我的 I2S Controller 连接到外部放大器。我想通过 AXI-DMA Controller 使用 DMA。这是我目前的数据路径:
我在 Zynq PS 上使用 Linux 4.10 内核。我使用 Linux ASoC 子系统生成 pcm 流并控制我的外部音频放大器。我有 512MB 的 DDR RAM 连接到 Zynq。我想使用该 RAM 的一部分来运行我的 DMA 引擎。我的 I2S Controller 运行 AXI-Lite 控制接口(interface)并使用 AXI4-Stream 接口(interface)进行音频流。此 IP 已经过测试,可以假定与这些接口(interface)配合良好。
以前,我用过Zynq PS中的PL330来驱动DMA引擎。我的 I2S Controller 过去在其 AXI-Lite 寄存器空间中内置了一个 FIFO,因此所有 DMA 传输都通过 AXI-Lite 接口(interface)进行。我只是将 DMA 引擎指向这个 FIFO 地址,如下所示:
struct axi_i2s {
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct snd_dmaengine_dai_dma_data capture_dma_data;
};
static int axi_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
&i2s->capture_dma_data);
return 0;
}
static struct snd_soc_dai_driver axi_i2s_dai = {
.probe = axi_i2s_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 8,
.rates = I2S_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
};
static int axi_i2s_probe(struct platform_device *pdev)
{
axi_i2s *i2s;
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s)
return -ENOMEM;
platform_set_drvdata(pdev, i2s);
i2s->playback_dma_data.addr = I2S_BASE_ADDRESS + TX_FIFO_OFFSET;
i2s->playback_dma_data.addr_width = 4;
i2s->playback_dma_data.maxburst = 1;
i2s->capture_dma_data.addr = I2S_BASE_ADDRESS + RX_FIFO_OFFSET;
i2s->capture_dma_data.addr_width = 4;
i2s->capture_dma_data.maxburst = 1;
devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
return 0;
}
设备树:
dmac_s: dmac@f8003000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0xf8003000 0x1000>;
interrupt-parent = <&intc>;
interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3",
"dma4", "dma5", "dma6", "dma7";
interrupts = <0 13 4>,
<0 14 4>, <0 15 4>,
<0 16 4>, <0 17 4>,
<0 40 4>, <0 41 4>,
<0 42 4>, <0 43 4>;
#dma-cells = <1>;
#dma-channels = <8>;
#dma-requests = <4>;
clocks = <&clkc 27>;
clock-names = "apb_pclk";
};
axi_i2s@0x43C00000 {
#sound-dai-cells = <1>;
compatible = "my,driver";
reg = <0x43C00000 0x10000>;
clocks = <&clkc 15>;
clock-names = "axi";
dmas = <&dmac_s 0>, <&dmac_s 1>;
dma-names = "tx", "rx";
xlnx,dma-type = <0x1>;
};
新设置:
/* AXI DMA */
axi_dma_0: axidma@40400000 {
compatible = "xlnx,axi-dma-1.00.a";
#dma-cells = <1>;
reg = < 0x40400000 0x10000 >;
xlnx,addrwidth = <0x20>;
clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>, <&clkc 15>;
clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";
interrupt-parent = <&intc>;
interrupts = < 0 33 4 0 34 4>;
dma-ranges = <0x00000000 0x00000000 0x20000000>;
//xlnx,include-sg ;
dma-channel@40400000 {
compatible = "xlnx,axi-dma-mm2s-channel";
dma-channels = <0x1>;
interrupts = < 0 33 4 >;
xlnx,datawidth = <0x20>;
xlnx,device-id = <0x0>;
//xlnx,include-dre ;
} ;
dma-channel@40400030 {
compatible = "xlnx,axi-dma-s2mm-channel";
dma-channels = <0x1>;
interrupts = < 0 34 4 >;
xlnx,datawidth = <0x20>;
xlnx,device-id = <0x0>;
//xlnx,include-dre ;
} ;
};
/* New stream version */
axi_i2s@0x43C10000 {
#sound-dai-cells = <1>;
compatible = "my,driver";
reg = <0x43C10000 0x10000>;
clocks = <&clkc 15>;
clock-names = "axi";
dmas = <&axi_dma_0 0
&axi_dma_0 1>;
dma-names = "axidma0", "axidma1";
xlnx,dma-type = <0x1>;
};
显然,有些细节被遗漏了,但这些是相关的部分。
现在,我不太明白如何使用 AXI-DMA IP 而不是 PL330 将此驱动程序更改为 DMA。由于 DMA 传输将在没有 FIFO 的不同内存区域中完成,我如何设置 snd_dmaengine_dai_dma_data 结构以写入 AXI-DMA 内存?特别是这一部分:
i2s->playback_dma_data.addr = I2S_BASE_ADDRESS + TX_FIFO_OFFSET;
i2s->playback_dma_data.addr_width = 4;
i2s->playback_dma_data.maxburst = 1;
i2s->capture_dma_data.addr = I2S_BASE_ADDRESS + RX_FIFO_OFFSET;
i2s->capture_dma_data.addr_width = 4;
i2s->capture_dma_data.maxburst = 1;
AXI-DMA IP 可以访问我的 DDR 的所有 512MB,但我不知道内核会在哪里为我的 DMA 传输分配内存。
最佳答案
您将需要一个 linux 内核驱动程序来分配将用作 DMA 缓冲区的内存。如果你需要一个大的连续缓冲区,你需要在你的 linux 内核中启用 CMA。在您的驱动程序中,您可以使用 kmalloc 来分配内存。
作为内核驱动程序的引用,我建议使用 udmabuf ( https://github.com/ikwzm/udmabuf )。
udmabuf 显示为/sys/class/udmabuf 中的设备,DMA 缓冲区的物理地址可以在用户空间中读取。将此地址作为要将数据推送到的目标区域传递到您的 AXI DMA 缓冲区。
关于 Zynq 上 Linux 中 DMA 的更多信息:https://forums.xilinx.com/xlnx/attachments/xlnx/ELINUX/10658/1/drivers-session4-dma-4public.pdf
编辑:您可以在此处找到 AXI DMA 的示例 linux 驱动程序 https://forums.xilinx.com/xlnx/attachments/xlnx/ELINUX/10658/2/axidma.c.golden
关于linux - 在基于 Xilinx Zynq 的平台上使用 AXI-DMA IP 的 PCM DMA 引擎,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42423867/
在 PCIe 配置中,设备具有专用地址,并且它们以点对点模式相互发送数据 - 每个设备都可以随时写入,并且交换机会注意正确地转发数据。不需要“总线主控器”来决定何时以及如何传输数据。 DMA 如何在这
我正在尝试使用 Linux DMA 驱动程序。目前,当我发送交易并开始等待时,我的请求超时。我相信这与我在执行 DMA 映射时设置缓冲区的方式有关。 char *src_dma_buffer = km
如上所述,dma 引擎和 dma Controller (重点是 linux)有什么区别? linux dma 引擎什么时候到位?这是一个特殊的设备还是所有支持 dma 的外围设备的一部分? 在浏览l
DMA 缓冲区是由驱动程序映射的内存。例如,在使用 rtl8319 的 pci-skeleton.c 中,我们有: tp->tx_bufs = pci_alloc_consistent(tp->p
什么是 Linux 内核上下文中的 DMA 映射和 DMA 引擎?什么时候可以在 Linux 设备驱动程序中使用 DMA 映射 API 和 DMA 引擎 API?任何真正的 Linux 设备驱动程序示
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 5 年前。
我正在更新一个旧的 linux 驱动程序,该驱动程序通过 DMA 将数据传输到用户空间页面,这些页面通过 get_user_pages() 从应用程序向下传递。 我的硬件是一个新的基于 x86 Xeo
我想将 8 位并行数据从 IO 传输到内存,数据以大约 5 Mhz 的速度非常快地传输,我正在通过使用 S3C2440(400Mhz)处理器的友好 arm 在基于 ARM9 的套件上使用嵌入式 lin
我正在尝试在基于 Zynq-7000 的平台上使用 DMA 引擎将 PCM 流传输到 Zynq PL 中的自定义 I2S Controller 。我的 I2S Controller 连接到外部放大器。
假设 CPU 修改了位置 x+50 的值并且没有将其刷新回主存(回写)。 与此同时,设备发起从 x 到 x+100 的 DMA 读取请求。 在那种情况下,如何通知 CPU 刷新脏缓存行? 最佳答案 D
假设CPU要从PCI Express设备进行DMA读取传输。与PCI Express设备的通信由事务层数据包(TLP)提供。从理论上讲,TLP的最大有效负载大小为1024个双字。那么,当CPU向PCI
这是引用this对类似 dma/pci 问题的回答。我从这个答案中得知,PC 没有能够将数据传输到 PCI 卡或从 PCI 卡传输数据的 DMA,并且 PCI 卡必须提供 DMA 功能。我从同事那里收
我一直在使用 Teensy 3.6 微 Controller 板(180 MHz ARM Cortex-M4 处理器)来尝试实现传感器驱动程序。传感器通过 SPI 进行控制,当命令它进行测量时,它会通
我给你讲个故事: 我有两个缓冲区设置,用于执行所谓的 ping ponging。我有一个指向每个缓冲区的 DMA 系统。 系统设置为 DMA 将数据写入一个缓冲区,而中断处理另一个缓冲区中的数据。 看
在 AMD APP 编程指南中写道(第 4-15 页): 对于传输 <=32 kB:对于从主机到设备的传输,数据由 CPU 复制 到运行时固定的主机内存缓冲区,然后 DMA 引擎传输 数据到设备内存。
我目前正在使用 STM32f407G-DISC1,并尝试使用 ADC 和 DMA 回调捕获缓冲区。 频率发生器连接到引脚 A0,并且电路板接地。我用示波器确认我的电线没有损坏。 现在的问题是,在设置我
memcpy via user space DMA: 是否有可能在 linux 中通过用户空间 DMA 实现 memcpy?我知道有一些方法可以通过 DMA 将内核缓冲区复制到用户空间缓冲区,但想通过
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 10 年前。 Improve thi
我正在遵循这个框架 https://forums.xilinx.com/xlnx/attachments/xlnx/ELINUX/10693/1/Linux%20DMA%20from%20User%2
最近,我阅读了很多关于 10gb/s NIC 的网站和书籍,它们的 DMA 以及 linux 内核(10/100 mb/s NIC)处理数据的方式,我遇到了一些问题头脑。 将 10GB/s 的数据流从
我是一名优秀的程序员,十分优秀!