xdma axi-stream

xdma 回环

vivado 里有官方示例
fpga:pcie rx – axi-stream master – axi-stream slave – pcie tx
流程:电脑启动读取,然后电脑再在超时时间内写入。或者电脑启动写入,然后电脑再在超时时间内读出。只读取或只写入会报超时,所以需要双线程进行
细节:只有电脑启动读取,pcie tx – axi-stream slave 才会使能 ready 信号,然后 pcie rx – axi-stream master 才能向 pcie tx – axi-stream slave 写数据


pcie xdma 配置

xdma axi-stream_第1张图片xdma axi-stream_第2张图片xdma axi-stream_第3张图片xdma axi-stream_第4张图片
xdma axi-stream_第5张图片


verilog hdl

work.v:

module work #(
    parameter C_DATA_WIDTH = 64
) (
    // AXI streaming
    output wire [C_DATA_WIDTH-1:0]   s_axis_c2h_tdata_0,  
    output wire                      s_axis_c2h_tlast_0,
    output wire                      s_axis_c2h_tvalid_0,
    input  wire                      s_axis_c2h_tready_0,
    output wire [C_DATA_WIDTH/8-1:0] s_axis_c2h_tkeep_0,
    input  wire [C_DATA_WIDTH-1:0]   m_axis_h2c_tdata_0,
    input  wire                      m_axis_h2c_tlast_0,
    input  wire                      m_axis_h2c_tvalid_0,
    output wire                      m_axis_h2c_tready_0,
    input  wire [C_DATA_WIDTH/8-1:0] m_axis_h2c_tkeep_0,

    // clk、rst
    input  wire sys_rst_n,
    input  wire user_resetn,
    input  wire user_clk,
    input  wire user_lnk_up,

    // led
    output wire [3:0] leds
);

reg [25:0] user_clk_heartbeat;

assign sys_resetn = sys_rst_n;

// led
assign leds[0] = sys_resetn;
assign leds[1] = user_resetn;
assign leds[2] = user_lnk_up;
assign leds[3] = user_clk_heartbeat[25];

// AXI streaming
assign s_axis_c2h_tdata_0  = m_axis_h2c_tdata_0;
assign s_axis_c2h_tlast_0  = 0;
assign s_axis_c2h_tvalid_0 = m_axis_h2c_tvalid_0;
assign s_axis_c2h_tkeep_0  = m_axis_h2c_tkeep_0; // 如果每次都凑够 64bit 就可以直接等于 8'hff
assign m_axis_h2c_tready_0 = s_axis_c2h_tready_0;

// led blink
always @(posedge user_clk) begin
    if(!sys_resetn) begin
        user_clk_heartbeat <= 26'd0;
    end else begin
        user_clk_heartbeat <= user_clk_heartbeat + 1'b1;
    end
end

endmodule

main.v:

module main #(
    parameter PL_LINK_CAP_MAX_LINK_WIDTH = 2, // 1- X1; 2 - X2; 4 - X4; 8 - X8
    parameter C_DATA_WIDTH               = 64
) (
    // pcie
    output [(PL_LINK_CAP_MAX_LINK_WIDTH - 1) : 0] pci_exp_txp,
    output [(PL_LINK_CAP_MAX_LINK_WIDTH - 1) : 0] pci_exp_txn,
    input  [(PL_LINK_CAP_MAX_LINK_WIDTH - 1) : 0] pci_exp_rxp,
    input  [(PL_LINK_CAP_MAX_LINK_WIDTH - 1) : 0] pci_exp_rxn,

    // clk、rst
    input  sys_clk_p,
    input  sys_clk_n,
    input  sys_rst_n,

    // led
    output [3:0] leds
);

localparam C_NUM_USR_IRQ = 1;

// pcie clk、rst
wire sys_clk;
wire sys_rst_n_c;

IBUFDS_GTE2 refclk_ibuf (.O(sys_clk), .ODIV2(), .I(sys_clk_p), .CEB(1'b0), .IB(sys_clk_n));
IBUF sys_reset_n_ibuf (.O(sys_rst_n_c), .I(sys_rst_n));

// user
wire user_lnk_up;
wire user_clk;
wire user_resetn;

// irq
reg  [C_NUM_USR_IRQ-1:0] usr_irq_req = 0;

// AXI streaming
wire [C_DATA_WIDTH-1:0]	  m_axis_h2c_tdata_0;
wire 			          m_axis_h2c_tlast_0;
wire 			          m_axis_h2c_tvalid_0;
wire 			          m_axis_h2c_tready_0;
wire [C_DATA_WIDTH/8-1:0] m_axis_h2c_tkeep_0;
wire [C_DATA_WIDTH-1:0]   s_axis_c2h_tdata_0; 
wire                      s_axis_c2h_tlast_0;
wire                      s_axis_c2h_tvalid_0;
wire                      s_axis_c2h_tready_0;
wire [C_DATA_WIDTH/8-1:0] s_axis_c2h_tkeep_0; 

xdma_0 xdma_0_i (
    // clk、rst
    .sys_rst_n(sys_rst_n_c),
    .sys_clk  (sys_clk),

    // pcie
    .pci_exp_txn(pci_exp_txn),
    .pci_exp_txp(pci_exp_txp),
    .pci_exp_rxn(pci_exp_rxn),
    .pci_exp_rxp(pci_exp_rxp),

    // AXI streaming
    .s_axis_c2h_tdata_0 (s_axis_c2h_tdata_0),  
    .s_axis_c2h_tlast_0 (s_axis_c2h_tlast_0),
    .s_axis_c2h_tvalid_0(s_axis_c2h_tvalid_0), 
    .s_axis_c2h_tready_0(s_axis_c2h_tready_0),
    .s_axis_c2h_tkeep_0 (s_axis_c2h_tkeep_0),
    .m_axis_h2c_tdata_0 (m_axis_h2c_tdata_0),
    .m_axis_h2c_tlast_0 (m_axis_h2c_tlast_0),
    .m_axis_h2c_tvalid_0(m_axis_h2c_tvalid_0),
    .m_axis_h2c_tready_0(m_axis_h2c_tready_0),
    .m_axis_h2c_tkeep_0 (m_axis_h2c_tkeep_0),

    .axi_aclk   (user_clk),
    .axi_aresetn(user_resetn),

    // led
    .user_lnk_up(user_lnk_up),

    // irq
    .usr_irq_req(usr_irq_req),
    .usr_irq_ack(),
    .msix_enable(),
);

work #(
    .C_DATA_WIDTH(C_DATA_WIDTH)
) work_i (
    // AXI streaming
    .s_axis_c2h_tdata_0 (s_axis_c2h_tdata_0),  
    .s_axis_c2h_tlast_0 (s_axis_c2h_tlast_0),
    .s_axis_c2h_tvalid_0(s_axis_c2h_tvalid_0), 
    .s_axis_c2h_tready_0(s_axis_c2h_tready_0),
    .s_axis_c2h_tkeep_0 (s_axis_c2h_tkeep_0),
    .m_axis_h2c_tdata_0 (m_axis_h2c_tdata_0),
    .m_axis_h2c_tlast_0 (m_axis_h2c_tlast_0),
    .m_axis_h2c_tvalid_0(m_axis_h2c_tvalid_0),
    .m_axis_h2c_tready_0(m_axis_h2c_tready_0),
    .m_axis_h2c_tkeep_0 (m_axis_h2c_tkeep_0),

    // clk、rst
    .user_clk(user_clk),
    .user_resetn(user_resetn),
    .sys_rst_n(sys_rst_n_c),
    .user_lnk_up(user_lnk_up),

    // led
    .leds(leds)
);

endmodule

constr.xdc:
led 高电平亮。正常情况下,板卡上电待 fpga 程序加载完毕后,第四个灯会一直闪烁,亮灭切换间隔大约为 500ms;第一个灯也会亮,等待约3秒钟就会灭然后等待约 500ms 第一、二、三号灯一起长亮

## configure
set_property CFGBVS VCCO                         [current_design]
set_property CONFIG_VOLTAGE 3.3                  [current_design]
set_property CONFIG_MODE SPIx4                   [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50      [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4     [current_design]
set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES  [current_design]
set_property BITSTREAM.GENERAL.COMPRESS TRUE     [current_design]
set_property BITSTREAM.CONFIG.UNUSEDPIN PULLNONE [current_design]

## pcie
# clock
set_property PACKAGE_PIN F6 [get_ports sys_clk_p]

# data
set_property PACKAGE_PIN D9  [get_ports {pci_exp_rxp[0]}]
set_property PACKAGE_PIN B10 [get_ports {pci_exp_rxp[1]}]
set_property PACKAGE_PIN D7  [get_ports {pci_exp_txp[0]}]
set_property PACKAGE_PIN B6  [get_ports {pci_exp_txp[1]}]

# rst
set_property -dict {PACKAGE_PIN N15 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]

## led
set_property -dict {PACKAGE_PIN V9 IOSTANDARD LVCMOS15} [get_ports {leds[0]}]
set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS15} [get_ports {leds[1]}]
set_property -dict {PACKAGE_PIN Y7 IOSTANDARD LVCMOS15} [get_ports {leds[2]}]
set_property -dict {PACKAGE_PIN W7 IOSTANDARD LVCMOS15} [get_ports {leds[3]}]

linux 下 rust 测试 xdma stream 的回环

main.rs:

fn main() {
	use rand::Rng;
	use std::fs::OpenOptions;
	use std::io::{Read, Write};
	
	let (read_tx, read_rx) = mpsc::channel();
	
	thread::spawn(move || {
	    let mut buffer = vec![0u8; 200];
	    let mut file = OpenOptions::new()
	        .read(true)
	        .open("/dev/xdma0_c2h_0")
	        .unwrap();
	    file.read(buffer.as_mut_slice()).unwrap();
	
	    read_tx.send(buffer).unwrap();
	});
	
	thread::spawn(move || {
	    let mut buffer = vec![0u8; 200];
	    for index in 0..(buffer.len() / 2) {
	        let rng: u16 = rand::thread_rng().gen_range(0..=1023);
	        buffer[index * 2] = (rng >> 8) as u8;
	        buffer[index * 2 + 1] = rng as u8;
	    }
	
	    let mut file = OpenOptions::new()
	        .write(true)
	        .open("/dev/xdma0_h2c_0")
	        .unwrap();
	    file.write(buffer.as_slice()).unwrap();
	});
	
	let buffer = read_rx.recv().unwrap();
	let mut data = vec![0u16; 100];
	for index in 0..(buffer.len() / 2) {
	    data[index] = ((buffer[index * 2] as u16) << 8) | (buffer[index * 2 + 1] as u16);
	}
	printfln!("xdma: {}", data);
}

Cargo.toml:

[dependencies]
rand = "*"

你可能感兴趣的:(fpga,fpga,xdma)