zynq pl 发数据给 ps

zynq ps pl 通信实战

pl端产生的数据信息发送给ps的过程中,踩了不少坑,记录一下;本文几乎没有理论的东西,大部分都是如何在软件上操作,代码是怎么样的,对新手非常友好;因此,大佬可以跳过了;推荐链接: 传送门

一.起因

由于项目需要,pl产生的数据需要传给ps,同时pl端数据产生的模块经常变化;在检索了很多文章后,发下你都是通过将pl端数据产生模块打包成用户ip核,再将ip核在block design中添加进来然后手动或者自动连接线路的方式,完成pl 和 ps之间的互联,结构就像这个样子:
大多数资料的互联方式
图中红色框框代表pl中我们项目中需要产生数据的模块,蓝色框框是axi_lite的接口;红色框框根据时钟自动累加输出16位数据给axi接口。
在实际操作下来之后,就发现对于需要经常变化数据产生方式的项目来说,频繁打包ip核是个很繁琐的事情,比如上午我需要每一个时钟数据增加一次,下午我每10个时钟数据增加一次。。。就要经历这些苦逼的流程:

  • 写pl端模块
  • 打包模块IP核
  • 修改模板axi接口
  • 在项目中新建block design互联模块和接口

修改:

  • 修改pl的代码
  • 打包IP核(打包的时候会把之前的block design打包进去嘛?有待考证)
  • 重新互联

所以为了避免反复打包ip,我想到下面这种互联方式,虽然换汤不换药,但是希望能减少操作步骤。

二.不打包IP互联

思想就是把arm的软核以及axi接口封装成一个黑盒子,使用的时候就例化给黑盒子的wrapper.v(就像调用用户编写的的模块一样),效果如图:(请忽视clk和rst … )
【图片待定!】

1.编写PL数据产生模块

本模块为了方便理解,就尽可能的简单,完成一个时钟计数的功能,为了arm能不漏数据的观测到累加的过程,特意给计数降速,来500个时钟再给计数+1,具体代码如下:
所处位置

`timescale 1ns / 1ps

module tx_data (
    input clk,
    input rst,
    output  reg [15:0] data_out
    );
    parameter  integer times_of_clk = 500;
    reg [15:0] data_ache;
    
    always@(posedge clk or posedge rst)begin
        if(rst == 1'b1)begin
            data_out <= 16'b0;
            data_ache <= 16'b0;
        end 
        else if(data_ache == times_of_clk) begin
            data_ache <= 16'b0;
            data_out <= data_out + 1'b1;
        end
        else begin
            data_ache <= data_ache + 1'b1;
        end
    end
endmodule

2. 修改axi接口模板

上图吧:
1.第一步
next完了就是这个
22
起个名字next,然后默认参数就能点击完成了:
在这里插入图片描述

有问道next steps的,我习惯选择 edit ip,立马就能改代码了;
在新弹出来的临时工程里面,找准位置添加代码:

input wire [15:0] data_in,

在这里插入图片描述

	.data_in(data_in),

在这里插入图片描述

里面套的那个.v 文件也要增加input,名字我都取得一样的,就不再粘贴一遍了
在这里插入图片描述
我们打算利用slv_reg0作为ps 和pl通信的缓冲区,因此屏蔽掉模板中slv_reg0被赋值的操作代码,添加上我们的赋值操作:

    //slv_reg0 <= slv_reg0;
    slv_reg0 <= {16'b0,data_in};

在这里插入图片描述

这个模板里面的功能是,在axi slave接收数据(也就是axi master 写数据,这个例程用不到)的时候,把对应的数据放到地址对应的寄存器slv_reg0 ~ slv_reg3中,我们在default代码段替换了slv_reg0 赋值逻辑,就可以一直将data_in的数据更新到寄存器中;
在这里插入图片描述

修改好代码,把packaging steps里面的每一项都按照提示点一下,变成绿色对勾,点击re-package ip 完成AXI接口的修改工作,提示关闭工程之后,就可以在ip catelog里面找到它了。

3.block design

按照自己的芯片情况添加好软核
在这里插入图片描述
添加自定义的AXI接口,搜一下刚才自己定义的名字
在这里插入图片描述
自动连接:
在这里插入图片描述
效果:
在这里插入图片描述
把datain接口make external
在这里插入图片描述
马上就好了!
在这里插入图片描述

在这里插入图片描述
给.bd文件套一层wrapper.v,如图操作:
在这里插入图片描述
观察一下生成的wrapper内容:
在这里插入图片描述
这个data_in_0就是axi伸出来的接口,接下来我们把 这个wrapper.v和 数据生产模块,用同一个top.v文件包含起来;

4.连接wrapper.v 和 tx_data.v

  • 新建一个top.v的空文件;
  • 复制wrapper.v文件中除了 data_in_0 之外的所有接口,名字也保持一致;
  • 用top文件包含wrapper和tx_data模块

在这里插入图片描述

代码重复地方相当多,有兴趣可以对比观察:
wrapper.v 文件详情:

`timescale 1 ps / 1 ps
// wrapper.v 文件详情:
module tx_data_system_wrapper
   (DDR_addr,
    DDR_ba,
    DDR_cas_n,
    DDR_ck_n,
    DDR_ck_p,
    DDR_cke,
    DDR_cs_n,
    DDR_dm,
    DDR_dq,
    DDR_dqs_n,
    DDR_dqs_p,
    DDR_odt,
    DDR_ras_n,
    DDR_reset_n,
    DDR_we_n,
    FIXED_IO_ddr_vrn,
    FIXED_IO_ddr_vrp,
    FIXED_IO_mio,
    FIXED_IO_ps_clk,
    FIXED_IO_ps_porb,
    FIXED_IO_ps_srstb,
    data_in_0);
  inout [14:0]DDR_addr;
  inout [2:0]DDR_ba;
  inout DDR_cas_n;
  inout DDR_ck_n;
  inout DDR_ck_p;
  inout DDR_cke;
  inout DDR_cs_n;
  inout [3:0]DDR_dm;
  inout [31:0]DDR_dq;
  inout [3:0]DDR_dqs_n;
  inout [3:0]DDR_dqs_p;
  inout DDR_odt;
  inout DDR_ras_n;
  inout DDR_reset_n;
  inout DDR_we_n;
  inout FIXED_IO_ddr_vrn;
  inout FIXED_IO_ddr_vrp;
  inout [53:0]FIXED_IO_mio;
  inout FIXED_IO_ps_clk;
  inout FIXED_IO_ps_porb;
  inout FIXED_IO_ps_srstb;
  input [15:0]data_in_0;

  wire [14:0]DDR_addr;
  wire [2:0]DDR_ba;
  wire DDR_cas_n;
  wire DDR_ck_n;
  wire DDR_ck_p;
  wire DDR_cke;
  wire DDR_cs_n;
  wire [3:0]DDR_dm;
  wire [31:0]DDR_dq;
  wire [3:0]DDR_dqs_n;
  wire [3:0]DDR_dqs_p;
  wire DDR_odt;
  wire DDR_ras_n;
  wire DDR_reset_n;
  wire DDR_we_n;
  wire FIXED_IO_ddr_vrn;
  wire FIXED_IO_ddr_vrp;
  wire [53:0]FIXED_IO_mio;
  wire FIXED_IO_ps_clk;
  wire FIXED_IO_ps_porb;
  wire FIXED_IO_ps_srstb;
  wire [15:0]data_in_0;

  tx_data_system tx_data_system_i
       (.DDR_addr(DDR_addr),
        .DDR_ba(DDR_ba),
        .DDR_cas_n(DDR_cas_n),
        .DDR_ck_n(DDR_ck_n),
        .DDR_ck_p(DDR_ck_p),
        .DDR_cke(DDR_cke),
        .DDR_cs_n(DDR_cs_n),
        .DDR_dm(DDR_dm),
        .DDR_dq(DDR_dq),
        .DDR_dqs_n(DDR_dqs_n),
        .DDR_dqs_p(DDR_dqs_p),
        .DDR_odt(DDR_odt),
        .DDR_ras_n(DDR_ras_n),
        .DDR_reset_n(DDR_reset_n),
        .DDR_we_n(DDR_we_n),
        .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
        .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
        .FIXED_IO_mio(FIXED_IO_mio),
        .FIXED_IO_ps_clk(FIXED_IO_ps_clk),
        .FIXED_IO_ps_porb(FIXED_IO_ps_porb),
        .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
        .data_in_0(data_in_0));
endmodule

top.v文件详情:

`timescale 1ns / 1ps
// top.v文件详情:
module top   (DDR_addr,
    DDR_ba,
    DDR_cas_n,
    DDR_ck_n,
    DDR_ck_p,
    DDR_cke,
    DDR_cs_n,
    DDR_dm,
    DDR_dq,
    DDR_dqs_n,
    DDR_dqs_p,
    DDR_odt,
    DDR_ras_n,
    DDR_reset_n,
    DDR_we_n,
    FIXED_IO_ddr_vrn,
    FIXED_IO_ddr_vrp,
    FIXED_IO_mio,
    FIXED_IO_ps_clk,
    FIXED_IO_ps_porb,
    FIXED_IO_ps_srstb
    //data_in_0
    );
  inout [14:0]DDR_addr;
  inout [2:0]DDR_ba;
  inout DDR_cas_n;
  inout DDR_ck_n;
  inout DDR_ck_p;
  inout DDR_cke;
  inout DDR_cs_n;
  inout [3:0]DDR_dm;
  inout [31:0]DDR_dq;
  inout [3:0]DDR_dqs_n;
  inout [3:0]DDR_dqs_p;
  inout DDR_odt;
  inout DDR_ras_n;
  inout DDR_reset_n;
  inout DDR_we_n;
  inout FIXED_IO_ddr_vrn;
  inout FIXED_IO_ddr_vrp;
  inout [53:0]FIXED_IO_mio;
  inout FIXED_IO_ps_clk;
  inout FIXED_IO_ps_porb;
  inout FIXED_IO_ps_srstb;
//  input [15:0]data_in_0;

  wire [14:0]DDR_addr;
  wire [2:0]DDR_ba;
  wire DDR_cas_n;
  wire DDR_ck_n;
  wire DDR_ck_p;
  wire DDR_cke;
  wire DDR_cs_n;
  wire [3:0]DDR_dm;
  wire [31:0]DDR_dq;
  wire [3:0]DDR_dqs_n;
  wire [3:0]DDR_dqs_p;
  wire DDR_odt;
  wire DDR_ras_n;
  wire DDR_reset_n;
  wire DDR_we_n;
  wire FIXED_IO_ddr_vrn;
  wire FIXED_IO_ddr_vrp;
  wire [53:0]FIXED_IO_mio;
  wire FIXED_IO_ps_clk;
  wire FIXED_IO_ps_porb;
  wire FIXED_IO_ps_srstb;
  
  wire [15:0]data_in_0;

  tx_data dyqTx(
    .clk(),
    .rst(),
    .data_out(data_in_0)
  );
  
  tx_data_system_wrapper yqduan
       (.DDR_addr(DDR_addr),
        .DDR_ba(DDR_ba),
        .DDR_cas_n(DDR_cas_n),
        .DDR_ck_n(DDR_ck_n),
        .DDR_ck_p(DDR_ck_p),
        .DDR_cke(DDR_cke),
        .DDR_cs_n(DDR_cs_n),
        .DDR_dm(DDR_dm),
        .DDR_dq(DDR_dq),
        .DDR_dqs_n(DDR_dqs_n),
        .DDR_dqs_p(DDR_dqs_p),
        .DDR_odt(DDR_odt),
        .DDR_ras_n(DDR_ras_n),
        .DDR_reset_n(DDR_reset_n),
        .DDR_we_n(DDR_we_n),
        .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
        .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
        .FIXED_IO_mio(FIXED_IO_mio),
        .FIXED_IO_ps_clk(FIXED_IO_ps_clk),
        .FIXED_IO_ps_porb(FIXED_IO_ps_porb),
        .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
        .data_in_0(data_in_0));
endmodule

完成之后文件的包含情况如图所示:
在这里插入图片描述

结尾

这个工程是个半成品,可以看出来 tx_data模块的rst 和 clk都留空了,这个可以直接用wrapper的时钟还有reset,但是wrapper软核需要的时钟是差分信号,因此使用的过程中还需要借助 clock相关的ip核;
因为再top文件里面复制了wrapper的接口,名字保持一致,所以不用担心软核需要的约束文件的问题(软核的的始终,复位,ddr);

终于不用再打包IP核了!

  • 10
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: Zynq PL-PS DMA是指Xilinx开Zynq系列可编程逻辑和处理系统之间的数据传输机制。Zynq是一种集成了ARM处理系统和可编程逻辑(PL)的SoC(系统级片上系统)芯片。 在Zynq芯片中,处理系统(PS)是由ARM Cortex-A9处理器组成的,用于运行操作系统和处理高级任务,而可编程逻辑(PL)是由可配置的逻辑单元组成的,用于实现硬件加速和高性能计算。而PL-PS DMA是用于在两者之间进行高速数据传输的重要组件。 DMA(Direct Memory Access)是一种数据传输技术,允许数据在内存和外设之间直接进行传输,而不需要CPU的干预。在Zynq PL-PS DMA中,DMA控制器位于PS中,用于管理数据PLPS之间的传输。 Zynq PL-PS DMA具有以下特点:高性能、低延迟、高带宽。通过使用DMA,PL可以直接从内存中读取数据,不需要CPU的介入,从而提高了数据传输效率和系统性能。 在使用Zynq PL-PS DMA时,首先需要在PLPS之间建立合适的数据通道。然后,通过编程配置DMA控制器的寄存器,设置数据传输的起始地址、传输长度、传输方向等参数。最后,启动DMA传输过程,并通过中断或轮询方式检查传输状态,以确保数据正确传输。 总之,Zynq PL-PS DMA是一种用于实现Zynq系列芯片中可编程逻辑和处理系统之间高速数据传输的技术,通过提供高性能、低延迟和高带宽的数据传输通道,提高了系统的数据传输效率和整体性能。 ### 回答2: Zynq PL PS DMA是指Zynq系列中的可编程逻辑(PL),处理系统(PS)和直接内存访问(DMA)的一种配置。 Zynq系列芯片是赛灵思公司针对嵌入式系统设计开的产品。它将传统的处理器系统和可编程逻辑(FPGA)集成到一个芯片中,为嵌入式系统设计带来更高的灵活性和性能。 PL是可编程的逻辑部分,其中包含了可编程逻辑电路,如FPGAPL可以用于实现各种不同的功能,例如数字信号处理、图像处理、乘法器等。PL可以被重新配置和优化,以满足不同应用的需求。 PS是指处理系统,它是Zynq芯片中的ARM Cortex-A9核心。PS负责运行嵌入式操作系统(如Linux),管理系统的整体运行和资源分配。PS还可以执行一些实时任务,如控制外部设备等。 DMA是指直接内存访问。DMA可以在处理器不参与的情况下,通过直接从外部设备读取或写入数据到内存中,实现高速的数据传输。DMA可以显著提高数据传输的效率,减少了处理器对数据传输的负担。 Zynq PL PS DMA的配置可以充分Zynq芯片的优势。PL的灵活性可以满足各种不同的应用需求,而PS的处理能力可以支持操作系统的运行和系统管理。DMA的使用可以加快数据传输速度,提高系统的响应速度。 总之,Zynq PL PS DMA的配置充分利用了可编程逻辑、处理系统和直接内存访问的优势,为嵌入式系统设计提供了更高的灵活性、性能和效率。 ### 回答3: Zynq是赛灵思公司(Xilinx)推出的一种嵌入式平台,它将硬件逻辑(PL)与处理系统(PS)集成在一个芯片上。PLFPGA实现的可编程逻辑部分,而PS则是ARM处理器系统。 DMA(Direct Memory Access)是一种数据传输方式,允许外部设备直接访问系统内存,无需CPU的干预。在Zynq平台中,PLPS都可以使用DMA进行数据传输。 在PL中使用DMA,我们可以通过定制的硬件逻辑实现高速、低延迟的数据传输。DMA可以从外部设备接收数据,将其存储在PL的内存中,并通过总线接口将数据传输到PS的内存中。这种方式可以减少数据传输的CPU开销,提高系统的性能。 在PS中使用DMA,可以实现高效的数据传输与处理。例如,通过使用DMA,可以将大数据块从外部设备传输到PS的内存中,然后再由CPU进行处理。这样可以提高数据处理的效率,减少CPU的负担。 总之,Zynq平台中的PLPS均可使用DMA进行数据传输,通过利用DMA可以提高数据传输的效率,降低系统的延迟,从而提升整体性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值