赞
踩
一、目标
在米尔科技的z-turn板上,采用AXI DMA 实现zynq的PS与PL数据交互。
二、分析
①PS数据传PL
驱动中的测试程序中给出一堆数据,通过DMA传输到AXI4-Stream Data FIFO ,PL端从DATA FIFO中把数据读出来。
②PL数据传PS
将PS传入PL的数据回传,在PS端显示出数据,最后将数据乘2再送入DMA。
③PL端代码思路
1)读数据
在加上DATA FIFO的情况下,PL从DATA FIFO中读取数据。将DATA -FIFO的M_AXIS端引出,得到下面的信号。
信号名称 | 作用 | 方向 |
---|---|---|
m_axis_tvalid | 主机向从机发数据的信号声明,置1表示主机有数据要发向从机。 | 输出 |
m_axis_tready | 主机判断从机是否准备好接收数据,当为1时表示从机准备好接收数据。 | 输入 |
m_axis_tdata | 主机将要发送的数据。 | 输出 |
m_axis_tkeep | 主机发送数据时需拉高。 | 输出 |
m_axis_tlast | 表示主机发送是否是最后一个数据,置1时表示主机正在发送最后一个数据。 | 输出 |
从上表可以看出,DATA FIFO接收完数据后,想要从FIFO中读取数据,靠的就是上面5根线,FIFO作主机,PL端作从机。所以FIFO会自动将m_axis_tvalid置1,表明可以从主机中读取数据。PL只需要给出回应m_axis_tready置1,便可以在时钟上升沿来临时读取数据。
同时,AXI-DMA将PS数据传输完成后有完成标志mm2s_introut置1。通过这个标准来确定是否从FIFO中读取数据。所以这个信号用于PL中断的触发信号。
2)写数据
将PL读取出来的数据进行乘2,再传入PS,PS再将数据打印出来。PL端接的是AXI-DMA的S_AXIS_S2MM端口。其信号如下:
信号名称 | 作用 | 方向 |
---|---|---|
s_axis_s2mm_tdata | 从机接收数据线 | 输入 |
s_axis_s2mm_tkeep | 数据有效信号线 | 输入 |
s_axis_s2mm_tlast | 是否最后一个数据 | 输入 |
s_axis_s2mm_tready | 从机准备是否准备好接收数据 | 输出 |
s_axis_s2mm_tvalid | 主机是否有数据发向从机 | 输入 |
从信号列表可以看出,此时DMA端口是作从机,PL端口作主机向DMA端口发送数据。PL端想发送数据,通过s_axis_s2mm_tvalid表明有数据发往从机。等待从机响应s_axis_s2mm_tready信号,响应过后便可以发送数据。发送数据时需要将s_axis_s2mm_tkeep拉高,同时当传到最后一个数据时,需要将s_axis_s2mm_tlast置1。
3)整体架构
局部放大图:
三、代码实现
①pl_read.v
module pl_read( clk, rst, m_axis_tvalid, m_axis_tdata, m_axis_tkeep, m_axis_tlast, m_axis_tready, m_ready, m_data, m_datavalid, m_datalast ); input clk; input rst; input m_axis_tvalid; input [31:0]m_axis_tdata; input [3:0]m_axis_tkeep; input m_axis_tlast; output m_axis_tready; input m_ready; output [31:0]m_data; output m_datavalid; output m_datalast; reg m_axis_tready; reg [31:0]m_data; reg m_datavalid; reg m_datalast; always@(posedge clk or negedge rst) begin if(!rst) begin m_axis_tready <= 0; m_data <= 0; m_datavalid <= 0; m_datalast <= 0; end else begin if(m_ready==1) begin m_axis_tready <= 1; if(m_axis_tvalid==1&&m_axis_tkeep==4'b1111) begin m_data <= m_axis_tdata; m_datavalid <= 1; if(m_axis_tlast==1) m_datalast <= 1; else m_datalast <= 0; end else begin m_data <= m_data; m_datavalid <= 0; m_datalast <= 0; end end else begin m_axis_tready <= 0; m_data <= m_data; m_datavalid <= 0; m_datalast <= 0; end end end endmodule
②pl_write.v
module pl_write( clk, rst, s_data, s_datavalid, s_datalast, s_ready, s_axis_tdata, s_axis_tkeep, s_axis_tlast, s_axis_tready, s_axis_tvalid ); input clk; input rst; input[31:0] s_data;//data stream input s_datalast;//data last flag input s_datavalid;//input data valid flag output s_ready;//数据可以写入标志 input s_axis_tready; output[31:0] s_axis_tdata; output[3:0]s_axis_tkeep; output s_axis_tlast; output s_axis_tvalid; reg [31:0] s_axis_tdata; reg [3:0]s_axis_tkeep; reg s_axis_tlast; reg s_axis_tvalid; reg s_ready; always@(posedge clk or negedge rst) begin if(!rst) begin s_axis_tkeep <= 4'b0000; s_axis_tvalid <= 0; s_axis_tdata <= 0; s_axis_tlast<=0; s_ready <= 0; end else begin if(s_axis_tready==1) begin if(s_datavalid==1) begin s_axis_tvalid <= 1; s_axis_tkeep <= 4'b1111; s_axis_tdata <= s_data; if(s_datalast)s_axis_tlast <= 1; else s_axis_tlast <= 0; end else begin s_axis_tvalid <= 0; s_axis_tkeep <= 4'b0000; s_axis_tdata <= s_axis_tdata; s_axis_tlast<=0; end s_ready <= 1; end else begin s_axis_tkeep <= 4'b0000; s_axis_tvalid <= 0; s_axis_tdata <= s_axis_tdata; s_axis_tlast<=0; s_ready <= 0; end end end endmodule
③top.v
module top( ); wire clk; wire rst; wire m_axis_tvalid; wire [31:0]m_axis_tdata; wire [3:0]m_axis_tkeep; wire m_axis_tlast; wire m_axis_tready; wire m_ready; wire [31:0]m_data; wire m_datavalid; wire m_datalast; wire s_axis_tready; wire[31:0] s_axis_tdata; wire[3:0]s_axis_tkeep; wire s_axis_tlast; wire s_axis_tvalid; pl_write u1( .clk(clk), .rst(rst), .s_data(m_data), .s_datalast(m_datalast), .s_datavalid(m_datavalid), .s_ready(m_ready), .s_axis_tready(s_axis_tready), .s_axis_tdata(s_axis_tdata), .s_axis_tkeep(s_axis_tkeep), .s_axis_tlast(s_axis_tlast), .s_axis_tvalid(s_axis_tvalid) ); pl_read u2( .clk(clk), .rst(rst), .m_data(m_data), .m_datalast(m_datalast), .m_datavalid(m_datavalid), .m_ready(m_ready), .m_axis_tready(m_axis_tready), .m_axis_tdata(m_axis_tdata), .m_axis_tkeep(m_axis_tkeep), .m_axis_tlast(m_axis_tlast), .m_axis_tvalid(m_axis_tvalid) ); system_wrapper u3( .FCLK_CLK0(clk), .peripheral_aresetn(rst), .s_axis_aclk(clk), .s_axis_aclk_1(clk), .s_axis_aresetn(rst), .s_axis_aresetn_1(rst), .s_axis_tready(s_axis_tready), .s_axis_tdata(s_axis_tdata), .s_axis_tkeep(s_axis_tkeep), .s_axis_tlast(s_axis_tlast), .s_axis_tvalid(s_axis_tvalid), .m_axis_tready(m_axis_tready), .m_axis_tdata(m_axis_tdata), .m_axis_tkeep(m_axis_tkeep), .m_axis_tlast(m_axis_tlast), .m_axis_tvalid(m_axis_tvalid) ); endmodule
④dma驱动代码
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/device.h> #include <asm/io.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/miscdevice.h> #include <linux/ioport.h> #include <linux/of.h> #include <linux/uaccess.h> #include <linux/interrupt.h> #include <asm/irq.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <linux/dma-mapping.h> /** *DMA驱动程序 * * * * * * *` * * **/ //DMA 基地址 #define DMA_S2MM_ADDR 0X40400000 #define DMA_MM2S_ADDR 0X40410000 //DMA MM2S控制寄存器 volatile unsigned int * mm2s_cr; #define MM2S_DMACR 0X00000000 //DMA MM2S状态控制寄存器 volatile unsigned int * mm2s_sr; #define MM2S_DMASR 0X00000004 //DMA MM2S源地址低32位 volatile
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。