该项目介绍了如何在 pl 中的 hdl 与 fpga 中的处理器上运行的嵌入式 c 之间传输数据的基本结构。
介绍
鉴于机器学习和人工智能等应用的 fpga 设计中硬件加速的兴起,现在是剥开几层“云雾”并讨论 hdl 之间来回传递数据(主要指fpga 的可编程逻辑 (pl) 中运行的代码以及 fpga 中的硬核或软核处理器上运行的相应软件之间传输数据)的基础知识的好时机。
硬件加速可以总结为在硬件(也称为 fpga 的可编程逻辑)中实现某些功能的基本思想,这些功能之前在位于主机 pc 上或在 fpga 上处理器(软核或者硬核)运行的软件。因此,要成为一名高效的设计人员,就必须掌握如何在硬件和软件之间来回传递数据的技巧。
在本例中,使用的是 zynq soc(片上系统)fpga,它具有硬核 arm 处理器。该 arm 核心和外设称为处理系统或 ps。
虽然有几种不同的方法可以完成 pl 和 ps 之间的数据传输,包括编写自己的自定义接口,但我认为最常见的机制是通过直接内存访问 (dma) 传输。这是因为 dma 允许 arm 内核的 cpu 简单地启动自身与 ddr 之间的数据传输,而 cpu 无需等待传输完成后再执行任何其他任务。dma 还允许 cpu 启动外部设备和 ddr 之间的传输。
在此项目中,将通过使用 xilinx dma ip 演示 dma 的功能,该ip可通过 axis 总线将内存映射接口转换为stream接口。将 32 字节写入嵌入式 c 中的内存,然后通过内存映射将其传输到 pl 到流 (mm2s) axis,通过寄存器处理每个值,然后通过流将数据传输回内存dma ip 的内存映射 (s2mm) 端口。
虽然这个示例对于重型硬件加速应用来说过于简单,但当刚接触 fpga 时,这种高速数据传输水平可能会变得非常复杂/难以学习。该项目重点介绍 dma 的使用及其行为。虽然打算让这个项目更多地关注数据处理方面,但在 dma 事务实现中发现了很多小“陷阱”,因此不得不将数据处理重点留给另一个项目。
使用 axi dma 控制 pl 中的 hdl 与 ps 中的 c 代码之间的数据传输有两个主要层:
memory map to stream (mm2s) 和 stream to memory map (s2mm) 通道上 pl 的 hdl 代码中的 axi 流握手信号(dma 的控制通道是使用普通 axi 写入的,但这就是全部由 vivado 自动处理,因此在这里只关注 axi stream接口)。
ps 的 c 代码中寄存器读/写 dma 的顺序。
verilog 中的 axi-stream握手
axi stream接口使用一组简单的握手信号机制,用于嵌入式设计中的数据交换。axi stream接口中有许多可选信号,但与 dma mm2s 和 s2mm 数据交换相关且必需的信号是 tdata、tvalid、tready、tlast 和 tkeep。axi stream中发送数据为主接口,接收数据为从接口。
tdata:数据总线
tvalid:当放置在 tdata 总线上的数据有效时,由主接口置位
tredy:当从机处于准备接收 tdata 总线上的数据的状态时,由从机置位
tlast:由主设备在 tdata 总线上流中最后一个数据包的持续时间内断言,以告诉从设备该数据包之后不会有数据
tkeep:由主设备设置的 tdata 总线上数据包的二次验证,指示数据包是否是流的一部分
axi dma ip 究竟如何实现此握手接口将数据传输出内存 (mm2s) 并传输到内存 (s2mm),这一点非常变化无常,尤其是在 s2mm 方面……
然而,我们首先需要了解的是有关 axi dma 的 s2mm 事务的信息,大部分可以总结为一句话:必须设置 s2mm 事务,并且在尝试向 dma 发送任何数据之前,以适当的顺序写入 dma 中的适当控制寄存器来启动事务,一旦 s2mm 通道看到 tlast 信号,它就会停止事务。
数据传输发生在每个时钟周期的 s2mm 和 mm2s 事务中的 tdata 总线上,其中tready 和 tvalid 均被置位(true)。因此,当负责断言 tvalid 时,在 axi 接口的主端必须小心,当从从机传入的 trety 信号也为 tvalid 断言时,不要让 tvalid 断言超过一个时钟周期。否则,从设备将在同一个数据包计时两次,作为两个单独的数据包。并且因为必须在控制寄存器中指定传输中有多少字节,所以 dma 通道(在本例中为 s2mm)会在看到提供 tlast 信号之前认为交换已结束,因为计数已关闭。
我用 verilog 编写了一个简单的状态机,它实现了一个从 axi stream接口来从 dma 的 mm2s 通道接收数据,通过寄存器传递stream中的每个数据包,然后实现一个主 axi strean接口来将数据流发回到s2mm通道。来自 tdata 总线的数据通过的寄存器旨在充当占位符,用于为硬件加速进行任何自定义数据处理。
从 vivado 中的 ila 中截取了一张屏幕截图,显示使用状态机实现的时序图。顶部是 mm2s 侧,底部是 s2mm 侧。
这是 verilog 状态机的流程图,实际文件附在本文末尾。值得注意的是,流程图中的主/从接口是从 verilog 状态机的角度来看的。
对于 dma ip 的具体设置,因为在直接寄存器模式下使用 dma,所以未选中分散收集选项。然后,将其他所有设置保留为默认设置,并选中允许未对齐传输的选项,我发现在将自定义 axi 流接口写入 dma 时,这给了更多的自由空间。
为了将 verilog 状态机添加到模块设计中,我右键单击模块设计的空白区域,然后选择“添加模块...”选项,该选项将显示 vivado 可以在设计源中找到的所有有效 verilog 模块在bd中使用的文件。
值得注意的是,信号命名约定分别遵循从接口和主接口的“s_axis”和“m_axis”标准。
dma 寄存器读/写控制序列
以下是裸机使用 dma 时更简单的顺序:
1.通过将 1 写入 mm2s(偏移量 0x00)和 s2mm(偏移量 0x30)控制寄存器的位 2 来复位 dma。
2.将 s2mm 通道要写入数据的 ddr 中位置的目标地址写入 s2mm dma 目标地址寄存器(偏移量 0x48)。
3.通过将 1 写入 s2mm 控制寄存器(偏移量 0x30)的位 0 来启动 dma s2mm 通道。
4.通过将 s2mm 通道上要读入内存的总字节数值写入 s2mm 缓冲区长度寄存器(偏移量 0x58),写入 s2mm 通道缓冲区的长度。这将启动 s2mm 传输,以便 dma 准备好从 fpga 逻辑中的设备接收数据流(直到实际馈送数据并且 axi 流总线上的 tvalid 由 fpga 逻辑中的设备断言后,该过程才会真正启动)逻辑)。
5.将 mm2s 通道要读取的数据的 ddr 中的源地址写入 mm2s dma 源地址寄存器(偏移量 0x18)。
6.通过将 1 写入 mm2s 控制寄存器的位 0(偏移量 0x00)来启动 dma mm2s 通道。
7.通过将要发送的总字节数值写入 mm2s 传输长度寄存器(偏移量 0x28),写入 mm2s 通道的传输长度。这将启动从 dma 到 fpga 逻辑中的接收设备的 mm2s 传输。
还记得之前提到过,在 pl 中的设备尝试向 s2mm 通道发送数据之前,必须启动并运行 s2mm 通道吗?嗯,这就是为什么要按顺序执行上述步骤。步骤 2 - 4 配置并启动 s2mm 通道,步骤 5 - 7 配置并启动 mm2s 通道。
在步骤 4 和 5 之间发生一些其他进程是可以的,但步骤 2 - 4 必须在步骤 5 - 7 之前发生。执行步骤 4 后,s2mm axi 流通道将断言其 tready 信号,此时 hdl 代码可以开始向其发送数据。
这也解释了当我第一次开始使用 dma 时,在 sdk/vitis 中的示例 dma 项目中注意到的一些事情。总是认为示例代码似乎是在使用 mm2s - xaxidma_dma_to_device 传输从 ddr 中写入任何内容之前尝试将数据拉入 ddr(通过首先执行 s2mm - xaxidma_device_to_dma 传输)。然而,s2mm 通道必须准备好并等待接收数据才能正常工作并且不会锁定。
在 fpga 设计中,dma 似乎是一种棘手的入门方法,但一旦你弄清楚它就会非常有帮助。
2018中国创新力企业榜单 阿里巴巴斑马智行公司名列前茅
如何设计用于插值和抽取的IIR滤波器
5G无线通信技术开启通信数据信息传输时代的开始
荣耀加冕!小匠物联斩获2023“光明奖”三项大奖
M1处理器有望支持eGPUt显卡扩展
怎么使用DMA在FPGA中的HDL和嵌入式C之间传输数据?
一种多功能输出开关电源
安世半导体荣获双料大奖,引领氮化镓技术前沿
脑机接口的的技术挑战、发展现状与未来研究
苹果魔力鼠标2拆解 有什么亮点呢
中国手机厂商在全球智能手机市场的影响力巨大,谷歌拉拢中国手机厂商
LED背光源的生产工艺
国产Model 3降价20%,特斯拉回应未听说
央行数字货币需要的原因是什么
基于MCU和总线技术实现数字图像监控系统的设计
新基建中的工业互联网,能帮助企业带来什么益处
TCL华星首发17.3吋3K轻薄触控屏
人工智能技术发展迅速:智能电话机器人强势来袭
PDU电源技术的要求
深度测评雪佛兰科鲁兹掀背车1.6T