AXI QSPI Combine寄存器调试w25q64 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki

说明

  • 例程:microblaze_cdma_qspi_combine.rar
  • 我们自己创建了一个axi_qspi_combine的ip,封装了2个AXI QUADSPI IP,其中一个是4线normal模式,1个是4线xip模式,通过一个spi_sel pin来选择。这样子,在一个实验中,同时可以做normal的读写/烧录实验,又可以做xip运行实验。
  • 存在的问题,将AXI QUADSPI封装到底层后,设计的时候调用axi_qspi_combine这个ip,系统不会发现AXI QUADSPI,它把axi_qspi_combine当纯逻辑处理了,因此不会为它生成.c/.h文件以及相应的寄存器配置文件。这有点不方便使用。所以我们只能用寄存器手搓的方法来驱动。
  • 测了这么久,看起来这个ip只能在1线或者2线模式下正常工作(普通模式或者xip模式)。在4线模式下比较异常(要么接口异常,要么print数据异常,本质都是ip驱动异常)。

ip封装方法

  • 封装过程的核心是创建axi_qspi_combine.v的verilog代码,将2个ip核集成起来。这里直接给出结果,方便以后使用:
  • 封装这2个ip,很简单,但比较繁琐,使用vim操作会比较方便

`timescale 1 ns / 1 ps


module axi_quad_spi_combine
   (s0_ext_spi_clk,
    s0_ip2intc_irpt,
    s0_axi4_aclk,
    s0_axi4_aresetn,
    s0_axi4_awid,
    s0_axi4_awaddr,
    s0_axi4_awlen,
    s0_axi4_awsize,
    s0_axi4_awburst,
    s0_axi4_awlock,
    s0_axi4_awcache,
    s0_axi4_awprot,
    s0_axi4_awvalid,
    s0_axi4_awready,
    s0_axi4_wdata,
    s0_axi4_wstrb,
    s0_axi4_wlast,
    s0_axi4_wvalid,
    s0_axi4_wready,
    s0_axi4_bid,
    s0_axi4_bresp,
    s0_axi4_bvalid,
    s0_axi4_bready,
    s0_axi4_arid,
    s0_axi4_araddr,
    s0_axi4_arlen,
    s0_axi4_arsize,
    s0_axi4_arburst,
    s0_axi4_arlock,
    s0_axi4_arcache,
    s0_axi4_arprot,
    s0_axi4_arvalid,
    s0_axi4_arready,
    s0_axi4_rid,
    s0_axi4_rdata,
    s0_axi4_rresp,
    s0_axi4_rlast,
    s0_axi4_rvalid,
    s0_axi4_rready,
    
    s1_ext_spi_clk,
    s1_axi_aclk,
    s1_axi_aresetn,
    s1_axi4_aclk,
    s1_axi4_aresetn,
    s1_axi_awaddr,
    s1_axi_awvalid,
    s1_axi_awready,
    s1_axi_wdata,
    s1_axi_wstrb,
    s1_axi_wvalid,
    s1_axi_wready,
    s1_axi_bresp,
    s1_axi_bvalid,
    s1_axi_bready,
    s1_axi_araddr,
    s1_axi_arvalid,
    s1_axi_arready,
    s1_axi_rdata,
    s1_axi_rresp,
    s1_axi_rvalid,
    s1_axi_rready,

    s1_axi4_awid,
    s1_axi4_awaddr,
    s1_axi4_awlen,
    s1_axi4_awsize,
    s1_axi4_awburst,
    s1_axi4_awlock,
    s1_axi4_awcache,
    s1_axi4_awprot,
    s1_axi4_awvalid,
    s1_axi4_awready,
    s1_axi4_wdata,
    s1_axi4_wstrb,
    s1_axi4_wlast,
    s1_axi4_wvalid,
    s1_axi4_wready,
    s1_axi4_bid,
    s1_axi4_bresp,
    s1_axi4_bvalid,
    s1_axi4_bready,
    s1_axi4_arid,
    s1_axi4_araddr,
    s1_axi4_arlen,
    s1_axi4_arsize,
    s1_axi4_arburst,
    s1_axi4_arlock,
    s1_axi4_arcache,
    s1_axi4_arprot,
    s1_axi4_arvalid,
    s1_axi4_arready,
    s1_axi4_rid,
    s1_axi4_rdata,
    s1_axi4_rresp,
    s1_axi4_rlast,
    s1_axi4_rvalid,
    s1_axi4_rready,
    s1_ip2intc_irpt,   

    io0_i,
    io0_o,
    io0_t,
    io1_i,
    io1_o,
    io1_t,
    io2_i,
    io2_o,
    io2_t,
    io3_i,
    io3_o,
    io3_t,
    sck_i,
    sck_o,
    sck_t,
    ss_i,
    ss_o,
    ss_t,

    spi_sel
    );

  input s0_ext_spi_clk;
  input s0_axi4_aclk;
  input s0_axi4_aresetn;
  input [3:0]s0_axi4_awid;
  input [23:0]s0_axi4_awaddr;
  input [7:0]s0_axi4_awlen;
  input [2:0]s0_axi4_awsize;
  input [1:0]s0_axi4_awburst;
  input s0_axi4_awlock;
  input [3:0]s0_axi4_awcache;
  input [2:0]s0_axi4_awprot;
  input s0_axi4_awvalid;
  output s0_axi4_awready;
  input [31:0]s0_axi4_wdata;
  input [3:0]s0_axi4_wstrb;
  input s0_axi4_wlast;
  input s0_axi4_wvalid;
  output s0_axi4_wready;
  output [3:0]s0_axi4_bid;
  output [1:0]s0_axi4_bresp;
  output s0_axi4_bvalid;
  input s0_axi4_bready;
  input [3:0]s0_axi4_arid;
  input [23:0]s0_axi4_araddr;
  input [7:0]s0_axi4_arlen;
  input [2:0]s0_axi4_arsize;
  input [1:0]s0_axi4_arburst;
  input s0_axi4_arlock;
  input [3:0]s0_axi4_arcache;
  input [2:0]s0_axi4_arprot;
  input s0_axi4_arvalid;
  output s0_axi4_arready;
  output [3:0]s0_axi4_rid;
  output [31:0]s0_axi4_rdata;
  output [1:0]s0_axi4_rresp;
  output s0_axi4_rlast;
  output s0_axi4_rvalid;
  input s0_axi4_rready;

  wire       s0_io0_i;
  wire       s0_io0_o;
  wire       s0_io0_t;
  wire       s0_io1_i;
  wire       s0_io1_o;
  wire       s0_io1_t;
  wire       s0_io2_i;
  wire       s0_io2_o;
  wire       s0_io2_t;
  wire       s0_io3_i;
  wire       s0_io3_o;
  wire       s0_io3_t;
  wire       s0_sck_i;
  wire       s0_sck_o;
  wire       s0_sck_t;
  wire       s0_ss_i;
  wire       s0_ss_o;
  wire       s0_ss_t;
  output       s0_ip2intc_irpt;
  
  input s1_ext_spi_clk;
  input s1_axi_aclk;
  input s1_axi_aresetn;
  input s1_axi4_aclk;
  input s1_axi4_aresetn;
  input [6:0]s1_axi_awaddr;
  input s1_axi_awvalid;
  output s1_axi_awready;
  input [31:0]s1_axi_wdata;
  input [3:0]s1_axi_wstrb;
  input s1_axi_wvalid;
  output s1_axi_wready;
  output [1:0]s1_axi_bresp;
  output s1_axi_bvalid;
  input s1_axi_bready;
  input [6:0]s1_axi_araddr;
  input s1_axi_arvalid;
  output s1_axi_arready;
  output [31:0]s1_axi_rdata;
  output [1:0]s1_axi_rresp;
  output s1_axi_rvalid;
  input s1_axi_rready;
  input [3:0]s1_axi4_awid;
  input [23:0]s1_axi4_awaddr;
  input [7:0]s1_axi4_awlen;
  input [2:0]s1_axi4_awsize;
  input [1:0]s1_axi4_awburst;
  input s1_axi4_awlock;
  input [3:0]s1_axi4_awcache;
  input [2:0]s1_axi4_awprot;
  input s1_axi4_awvalid;
  output s1_axi4_awready;
  input [31:0]s1_axi4_wdata;
  input [3:0]s1_axi4_wstrb;
  input s1_axi4_wlast;
  input s1_axi4_wvalid;
  output s1_axi4_wready;
  output [3:0]s1_axi4_bid;
  output [1:0]s1_axi4_bresp;
  output s1_axi4_bvalid;
  input s1_axi4_bready;
  input [3:0]s1_axi4_arid;
  input [23:0]s1_axi4_araddr;
  input [7:0]s1_axi4_arlen;
  input [2:0]s1_axi4_arsize;
  input [1:0]s1_axi4_arburst;
  input s1_axi4_arlock;
  input [3:0]s1_axi4_arcache;
  input [2:0]s1_axi4_arprot;
  input s1_axi4_arvalid;
  output s1_axi4_arready;
  output [3:0]s1_axi4_rid;
  output [31:0]s1_axi4_rdata;
  output [1:0]s1_axi4_rresp;
  output s1_axi4_rlast;
  output s1_axi4_rvalid;
  input s1_axi4_rready;

  wire       s1_io0_i;
  wire       s1_io0_o;
  wire       s1_io0_t;
  wire       s1_io1_i;
  wire       s1_io1_o;
  wire       s1_io1_t;
  wire       s1_io2_i;
  wire       s1_io2_o;
  wire       s1_io2_t;
  wire       s1_io3_i;
  wire       s1_io3_o;
  wire       s1_io3_t;
  wire       s1_sck_i;
  wire       s1_sck_o;
  wire       s1_sck_t;
  wire       s1_ss_i;
  wire       s1_ss_o;
  wire       s1_ss_t;
  output       s1_ip2intc_irpt;

  input io0_i;
  output io0_o;
  output io0_t;
  input io1_i;
  output io1_o;
  output io1_t;
  input io2_i;
  output io2_o;
  output io2_t;
  input io3_i;
  output io3_o;
  output io3_t;
  input sck_i;
  output sck_o;
  output sck_t;
  input [0:0]ss_i;
  output [0:0]ss_o;
  output ss_t;

  input spi_sel;
  assign io0_o=(spi_sel)? s0_io0_o: s1_io0_o;
  assign io0_t=(spi_sel)? s0_io0_t: s1_io0_t;
  assign s0_io0_i=(spi_sel==1)? io0_i: 1'b0;
  assign s1_io0_i=(spi_sel==0)? io0_i: 1'b0;

  assign io1_o=(spi_sel)? s0_io1_o: s1_io1_o;
  assign io1_t=(spi_sel)? s0_io1_t: s1_io1_t;
  assign s0_io1_i=(spi_sel==1)? io1_i: 1'b0;
  assign s1_io1_i=(spi_sel==0)? io1_i: 1'b0;

  assign io2_o=(spi_sel)? s0_io2_o: s1_io2_o;
  assign io2_t=(spi_sel)? s0_io2_t: s1_io2_t;
  assign s0_io2_i=(spi_sel==1)? io2_i: 1'b0;
  assign s1_io2_i=(spi_sel==0)? io2_i: 1'b0;

  assign io3_o=(spi_sel)? s0_io3_o: s1_io3_o;
  assign io3_t=(spi_sel)? s0_io3_t: s1_io3_t;
  assign s0_io3_i=(spi_sel==1)? io3_i: 1'b0;
  assign s1_io3_i=(spi_sel==0)? io3_i: 1'b0;

  assign sck_o=(spi_sel)? s0_sck_o: s1_sck_o;
  assign sck_t=(spi_sel)? s0_sck_t: s1_sck_t;
  assign s0_sck_i=(spi_sel==1)? sck_i: 1'b0;
  assign s1_sck_i=(spi_sel==0)? sck_i: 1'b0;

  assign ss_o=(spi_sel)? s0_ss_o: s1_ss_o;
  assign ss_t=(spi_sel)? s0_ss_t: s1_ss_t;
  assign s0_ss_i=(spi_sel==1)? ss_i: 1'b0;
  assign s1_ss_i=(spi_sel==0)? ss_i: 1'b0;


    
 axi_quad_spi_0 your_instance_name1 (
  .ext_spi_clk(s0_ext_spi_clk),        // input wire ext_spi_clk
  .s_axi4_aclk(s0_axi4_aclk),        // input wire s_axi4_aclk
  .s_axi4_aresetn(s0_axi4_aresetn),  // input wire s_axi4_aresetn
  .s_axi4_awid(s0_axi4_awid),        // input wire [3 : 0] s_axi4_awid
  .s_axi4_awaddr(s0_axi4_awaddr),    // input wire [23 : 0] s_axi4_awaddr
  .s_axi4_awlen(s0_axi4_awlen),      // input wire [7 : 0] s_axi4_awlen
  .s_axi4_awsize(s0_axi4_awsize),    // input wire [2 : 0] s_axi4_awsize
  .s_axi4_awburst(s0_axi4_awburst),  // input wire [1 : 0] s_axi4_awburst
  .s_axi4_awlock(s0_axi4_awlock),    // input wire s_axi4_awlock
  .s_axi4_awcache(s0_axi4_awcache),  // input wire [3 : 0] s_axi4_awcache
  .s_axi4_awprot(s0_axi4_awprot),    // input wire [2 : 0] s_axi4_awprot
  .s_axi4_awvalid(s0_axi4_awvalid),  // input wire s_axi4_awvalid
  .s_axi4_awready(s0_axi4_awready),  // output wire s_axi4_awready
  .s_axi4_wdata(s0_axi4_wdata),      // input wire [31 : 0] s_axi4_wdata
  .s_axi4_wstrb(s0_axi4_wstrb),      // input wire [3 : 0] s_axi4_wstrb
  .s_axi4_wlast(s0_axi4_wlast),      // input wire s_axi4_wlast
  .s_axi4_wvalid(s0_axi4_wvalid),    // input wire s_axi4_wvalid
  .s_axi4_wready(s0_axi4_wready),    // output wire s_axi4_wready
  .s_axi4_bid(s0_axi4_bid),          // output wire [3 : 0] s_axi4_bid
  .s_axi4_bresp(s0_axi4_bresp),      // output wire [1 : 0] s_axi4_bresp
  .s_axi4_bvalid(s0_axi4_bvalid),    // output wire s_axi4_bvalid
  .s_axi4_bready(s0_axi4_bready),    // input wire s_axi4_bready
  .s_axi4_arid(s0_axi4_arid),        // input wire [3 : 0] s_axi4_arid
  .s_axi4_araddr(s0_axi4_araddr),    // input wire [23 : 0] s_axi4_araddr
  .s_axi4_arlen(s0_axi4_arlen),      // input wire [7 : 0] s_axi4_arlen
  .s_axi4_arsize(s0_axi4_arsize),    // input wire [2 : 0] s_axi4_arsize
  .s_axi4_arburst(s0_axi4_arburst),  // input wire [1 : 0] s_axi4_arburst
  .s_axi4_arlock(s0_axi4_arlock),    // input wire s_axi4_arlock
  .s_axi4_arcache(s0_axi4_arcache),  // input wire [3 : 0] s_axi4_arcache
  .s_axi4_arprot(s0_axi4_arprot),    // input wire [2 : 0] s_axi4_arprot
  .s_axi4_arvalid(s0_axi4_arvalid),  // input wire s_axi4_arvalid
  .s_axi4_arready(s0_axi4_arready),  // output wire s_axi4_arready
  .s_axi4_rid(s0_axi4_rid),          // output wire [3 : 0] s_axi4_rid
  .s_axi4_rdata(s0_axi4_rdata),      // output wire [31 : 0] s_axi4_rdata
  .s_axi4_rresp(s0_axi4_rresp),      // output wire [1 : 0] s_axi4_rresp
  .s_axi4_rlast(s0_axi4_rlast),      // output wire s_axi4_rlast
  .s_axi4_rvalid(s0_axi4_rvalid),    // output wire s_axi4_rvalid
  .s_axi4_rready(s0_axi4_rready),    // input wire s_axi4_rready
  .io0_i(s0_io0_i),                    // input wire io0_i
  .io0_o(s0_io0_o),                    // output wire io0_o
  .io0_t(s0_io0_t),                    // output wire io0_t
  .io1_i(s0_io1_i),                    // input wire io1_i
  .io1_o(s0_io1_o),                    // output wire io1_o
  .io1_t(s0_io1_t),                    // output wire io1_t
  .io2_i(s0_io2_i),                    // input wire io2_i
  .io2_o(s0_io2_o),                    // output wire io2_o
  .io2_t(s0_io2_t),                    // output wire io2_t
  .io3_i(s0_io3_i),                    // input wire io3_i
  .io3_o(s0_io3_o),                    // output wire io3_o
  .io3_t(s0_io3_t),                    // output wire io3_t
  .sck_i(s0_sck_i),                    // input wire sck_i
  .sck_o(s0_sck_o),                    // output wire sck_o
  .sck_t(s0_sck_t),                    // output wire sck_t
  .ss_i(s0_ss_i),                      // input wire [0 : 0] ss_i
  .ss_o(s0_ss_o),                      // output wire [0 : 0] ss_o
  .ss_t(s0_ss_t),                      // output wire ss_t
  .ip2intc_irpt(s0_ip2intc_irpt)      // output wire ip2intc_irpt
);


axi_quad_spi_1 your_instance_name2 (
  .ext_spi_clk(s1_ext_spi_clk),        // input wire ext_spi_clk
  .s_axi_aclk(s1_axi_aclk),          // input wire s_axi_aclk
  .s_axi_aresetn(s1_axi_aresetn),    // input wire s_axi_aresetn
  .s_axi4_aclk(s1_axi4_aclk),        // input wire s_axi4_aclk
  .s_axi4_aresetn(s1_axi4_aresetn),  // input wire s_axi4_aresetn
  .s_axi_awaddr(s1_axi_awaddr),      // input wire [6 : 0] s_axi_awaddr
  .s_axi_awvalid(s1_axi_awvalid),    // input wire s_axi_awvalid
  .s_axi_awready(s1_axi_awready),    // output wire s_axi_awready
  .s_axi_wdata(s1_axi_wdata),        // input wire [31 : 0] s_axi_wdata
  .s_axi_wstrb(s1_axi_wstrb),        // input wire [3 : 0] s_axi_wstrb
  .s_axi_wvalid(s1_axi_wvalid),      // input wire s_axi_wvalid
  .s_axi_wready(s1_axi_wready),      // output wire s_axi_wready
  .s_axi_bresp(s1_axi_bresp),        // output wire [1 : 0] s_axi_bresp
  .s_axi_bvalid(s1_axi_bvalid),      // output wire s_axi_bvalid
  .s_axi_bready(s1_axi_bready),      // input wire s_axi_bready
  .s_axi_araddr(s1_axi_araddr),      // input wire [6 : 0] s_axi_araddr
  .s_axi_arvalid(s1_axi_arvalid),    // input wire s_axi_arvalid
  .s_axi_arready(s1_axi_arready),    // output wire s_axi_arready
  .s_axi_rdata(s1_axi_rdata),        // output wire [31 : 0] s_axi_rdata
  .s_axi_rresp(s1_axi_rresp),        // output wire [1 : 0] s_axi_rresp
  .s_axi_rvalid(s1_axi_rvalid),      // output wire s_axi_rvalid
  .s_axi_rready(s1_axi_rready),      // input wire s_axi_rready
  .s_axi4_awid(s1_axi4_awid),        // input wire [3 : 0] s_axi4_awid
  .s_axi4_awaddr(s1_axi4_awaddr),    // input wire [23 : 0] s_axi4_awaddr
  .s_axi4_awlen(s1_axi4_awlen),      // input wire [7 : 0] s_axi4_awlen
  .s_axi4_awsize(s1_axi4_awsize),    // input wire [2 : 0] s_axi4_awsize
  .s_axi4_awburst(s1_axi4_awburst),  // input wire [1 : 0] s_axi4_awburst
  .s_axi4_awlock(s1_axi4_awlock),    // input wire s_axi4_awlock
  .s_axi4_awcache(s1_axi4_awcache),  // input wire [3 : 0] s_axi4_awcache
  .s_axi4_awprot(s1_axi4_awprot),    // input wire [2 : 0] s_axi4_awprot
  .s_axi4_awvalid(s1_axi4_awvalid),  // input wire s_axi4_awvalid
  .s_axi4_awready(s1_axi4_awready),  // output wire s_axi4_awready
  .s_axi4_wdata(s1_axi4_wdata),      // input wire [31 : 0] s_axi4_wdata
  .s_axi4_wstrb(s1_axi4_wstrb),      // input wire [3 : 0] s_axi4_wstrb
  .s_axi4_wlast(s1_axi4_wlast),      // input wire s_axi4_wlast
  .s_axi4_wvalid(s1_axi4_wvalid),    // input wire s_axi4_wvalid
  .s_axi4_wready(s1_axi4_wready),    // output wire s_axi4_wready
  .s_axi4_bid(s1_axi4_bid),          // output wire [3 : 0] s_axi4_bid
  .s_axi4_bresp(s1_axi4_bresp),      // output wire [1 : 0] s_axi4_bresp
  .s_axi4_bvalid(s1_axi4_bvalid),    // output wire s_axi4_bvalid
  .s_axi4_bready(s1_axi4_bready),    // input wire s_axi4_bready
  .s_axi4_arid(s1_axi4_arid),        // input wire [3 : 0] s_axi4_arid
  .s_axi4_araddr(s1_axi4_araddr),    // input wire [23 : 0] s_axi4_araddr
  .s_axi4_arlen(s1_axi4_arlen),      // input wire [7 : 0] s_axi4_arlen
  .s_axi4_arsize(s1_axi4_arsize),    // input wire [2 : 0] s_axi4_arsize
  .s_axi4_arburst(s1_axi4_arburst),  // input wire [1 : 0] s_axi4_arburst
  .s_axi4_arlock(s1_axi4_arlock),    // input wire s_axi4_arlock
  .s_axi4_arcache(s1_axi4_arcache),  // input wire [3 : 0] s_axi4_arcache
  .s_axi4_arprot(s1_axi4_arprot),    // input wire [2 : 0] s_axi4_arprot
  .s_axi4_arvalid(s1_axi4_arvalid),  // input wire s_axi4_arvalid
  .s_axi4_arready(s1_axi4_arready),  // output wire s_axi4_arready
  .s_axi4_rid(s1_axi4_rid),          // output wire [3 : 0] s_axi4_rid
  .s_axi4_rdata(s1_axi4_rdata),      // output wire [31 : 0] s_axi4_rdata
  .s_axi4_rresp(s1_axi4_rresp),      // output wire [1 : 0] s_axi4_rresp
  .s_axi4_rlast(s1_axi4_rlast),      // output wire s_axi4_rlast
  .s_axi4_rvalid(s1_axi4_rvalid),    // output wire s_axi4_rvalid
  .s_axi4_rready(s1_axi4_rready),    // input wire s_axi4_rready
  .io0_i(s1_io0_i),                    // input wire io0_i
  .io0_o(s1_io0_o),                    // output wire io0_o
  .io0_t(s1_io0_t),                    // output wire io0_t
  .io1_i(s1_io1_i),                    // input wire io1_i
  .io1_o(s1_io1_o),                    // output wire io1_o
  .io1_t(s1_io1_t),                    // output wire io1_t
  .io2_i(s1_io2_i),                    // input wire io2_i
  .io2_o(s1_io2_o),                    // output wire io2_o
  .io2_t(s1_io2_t),                    // output wire io2_t
  .io3_i(s1_io3_i),                    // input wire io3_i
  .io3_o(s1_io3_o),                    // output wire io3_o
  .io3_t(s1_io3_t),                    // output wire io3_t
  .sck_i(s1_sck_i),                    // input wire sck_i
  .sck_o(s1_sck_o),                    // output wire sck_o
  .sck_t(s1_sck_t),                    // output wire sck_t
  .ss_i(s1_ss_i),                      // input wire [0 : 0] ss_i
  .ss_o(s1_ss_o),                      // output wire [0 : 0] ss_o
  .ss_t(s1_ss_t),                      // output wire ss_t
  .ip2intc_irpt(s1_ip2intc_irpt)      // output wire ip2intc_irpt
);   
    
endmodule

bd设计

image image

# qspi_flash, v3_board, d1-6
set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS33} [get_ports SPI_PL_ss_io]
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports SPI_PL_sck_io]
set_property -dict {PACKAGE_PIN G15 IOSTANDARD LVCMOS33} [get_ports SPI_PL_io0_io]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports SPI_PL_io1_io]
set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports SPI_PL_io2_io]
set_property -dict {PACKAGE_PIN N15 IOSTANDARD LVCMOS33} [get_ports SPI_PL_io3_io]

#axi_uart, d7-8
#set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS33} [get_ports UART_PL_txd]
#set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS33} [get_ports UART_PL_rxd]

#axi_gpio, d9--18
#set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports {GPIO_PL_tri_io[7]}]
#set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports {GPIO_PL_tri_io[6]}]
#set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {GPIO_PL_tri_io[5]}]
#set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {GPIO_PL_tri_io[4]}]
#set_property -dict {PACKAGE_PIN T17 IOSTANDARD LVCMOS33} [get_ports {GPIO_PL_tri_io[3]}]
#set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports {GPIO_PL_tri_io[2]}]
#set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {GPIO_PL_tri_io[1]}]
#set_property -dict {PACKAGE_PIN U17 IOSTANDARD LVCMOS33} [get_ports {GPIO_PL_tri_io[0]}]

#spi_sel, d35/key0/sw
set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports spi_sel]

#其余不用的输入/输出可以不分配引脚,并避免报错
#set_property IOSTANDARD LVCMOS33 [get_ports *]
#set_property SEVERITY {Warning} [get_drc_checks NSTD-1]
#set_property SEVERITY {Warning} [get_drc_checks RTSTAT-1]
#set_property SEVERITY {Warning} [get_drc_checks UCIO-1]

set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports Clk]
create_clock -period 20.000 -name sys_clk [get_ports Clk]

set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports rst_n]

c代码设计


#include "ACZ702_Lib/COMMON.h"

//xsct% mrd 0x4100001C 1
//4100001C:   00000000
//
//xsct% mrd 0x41000020 1
//41000020:   00000400
//
//xsct% mrd 0x41000028 1
//41000028:   0000202B
//
//xsct% mrd 0x41000040 1
//Memory read error at 0x41000040. Blocked address 0x41000040. Cannot read write-only register
//xsct% mrd 0x41000060 1
//41000060:   00000106
//
//xsct% mrd 0x41000064 1
//41000064:   00000025
//
//xsct% mrd 0x41000068 1
//Memory read error at 0x41000068. Blocked address 0x41000068. Cannot read write-only register
//xsct% mrd 0x4100006C 1
//Memory read error at 0x4100006C. Memory read aborted. External abort
//xsct% mrd 0x41000070 1
//41000070:   00000001
//
//xsct% mrd 0x41000074 1
//41000074:   00000000

#define PS_KEY 15
#define PS_LED 11
int main_ps_io(void)
{
    uint8_t State;   //存放按键(MIO47)的电平状态,0为低电平,1为高电平

    PS_GPIO_Init(); //初始化PS端MIO和EMIO
    PS_GPIO_SetMode(PS_LED, OUTPUT, 0);
    //设置PL_LED(EMIO0)为输出并且初始为低电平
    PS_GPIO_SetMode(PS_KEY, INPUT, 0); //设置PS_KEY(MIO47)方向为输入
}


u8 txBuffer[4096];
u8 rxBuffer[4096];

//void pulling_sr()
//{
//	u32 ticks=0;
//	while(ticks++<30){
//		txBuffer[0]=0x05;
//		txBuffer[1]=0x00;
//		AXI_SPI_Transfer(&AXI_SPI0, 0, rxBuffer, txBuffer, 2);
//		u8 sr0=rxBuffer[1];
//
//		txBuffer[0]=0x35;
//		txBuffer[1]=0x00;
//		AXI_SPI_Transfer(&AXI_SPI0, 0, rxBuffer, txBuffer, 2);
//		u8 sr1=rxBuffer[1];
//
//		//u32 sr=(sr2<<15)+(sr1<<8)+sr0;
//		xil_printf("%x,%x\r\n",sr0,sr1);
//	}
//}
//
//void test_flash2()
//{
//	//s0: read sr
//	//pulling_sr();
//
//	//s2: sector erase(sector_size=4kB)
//	txBuffer[0]=0x06;
//	AXI_SPI_Transfer(&AXI_SPI0, 0, rxBuffer, txBuffer, 1);
//
//	txBuffer[0]=0x20;
//	txBuffer[1]=0x00;
//	txBuffer[2]=0x00;
//	txBuffer[3]=0x00;
//	AXI_SPI_Transfer(&AXI_SPI0, 0, rxBuffer, txBuffer, 4);
//	//pulling_sr();
//	usleep(100*1000);
//
//	//s3: page program(page_size=256B)
//    for(int i=0; i<8; i++){
//		txBuffer[0]=0x06;
//		AXI_SPI_Transfer(&AXI_SPI0, 0, rxBuffer, txBuffer, 1);
//
//		u32 addr=0x000000+i*128;
//		txBuffer[0]=0x02;
//		txBuffer[1]=(addr>>16)&0xff;
//		txBuffer[2]=(addr>>8)&0xff;
//		txBuffer[3]=(addr>>0)&0xff;
//
//		for(int i=0; i<128; i++){
//			txBuffer[4+i]=4+i;
//		}
//		AXI_SPI_Transfer(&AXI_SPI0, 0, rxBuffer, txBuffer, 4+128);
//		usleep(100*1000);
//    }
//
//	//s4: spi/dspi/qspi read
//	txBuffer[0]=0x0b;
//	txBuffer[1]=0x00;
//	txBuffer[2]=0x00;
//	txBuffer[3]=0x00;
//	AXI_SPI_Transfer(&AXI_SPI0, 0, rxBuffer, txBuffer, 1024);
//	usleep(100*1000);
//	for(int i=0; i<32; i++) xil_printf("%d\r\n", rxBuffer[i]);
//	xil_printf("*******************\r\n");
//
//	txBuffer[0]=0x3b;
//	txBuffer[1]=0x00;
//	txBuffer[2]=0x00;
//	txBuffer[3]=0x00;
//	AXI_SPI_Transfer(&AXI_SPI0, 0, rxBuffer, txBuffer, 1024);
//	usleep(100*1000);
//	for(int i=0; i<32; i++) xil_printf("%d\r\n", rxBuffer[i]);
//	xil_printf("*******************\r\n");
//
//	txBuffer[0]=0x6b;
//	txBuffer[1]=0x00;
//	txBuffer[2]=0x00;
//	txBuffer[3]=0x00;
//	AXI_SPI_Transfer(&AXI_SPI0, 0, rxBuffer, txBuffer, 1024);
//	usleep(100*1000);
//	for(int i=0; i<32; i++) xil_printf("%d\r\n", rxBuffer[i]);
//	xil_printf("*******************\r\n");
//}


/*************************************************************************************/

#define QSPI_BASE 0x40000000
void config_spi()
{
	Xil_Out32(QSPI_BASE+0x40, 0xa);        //soft_rst
	Xil_Out32(QSPI_BASE+0x28, 0x3fff);     //global_ie
	Xil_Out32(QSPI_BASE+0x1c, 0x80000000); //ie
}

void polling_tx_fifo_is_empty()
{
	u32 status=0;
	do{
		status=Xil_In32(QSPI_BASE+0x64);
	}
	while(!(status&0b100));
}

void start_spi()
{
	Xil_Out32(QSPI_BASE+0x70, 0x00);  //选择0通道cs
	Xil_Out32(QSPI_BASE+0x60, 0x86);  //使能master,开始发数据
	polling_tx_fifo_is_empty();
	Xil_Out32(QSPI_BASE+0x70, 0x01);  //选择0通道cs的cs拉高
	Xil_Out32(QSPI_BASE+0x60, 0x186); //禁用master
}

void start_spi_by_cs_mode(u32 cs_mode)
{
	if(cs_mode==0){/*normal*/
		Xil_Out32(QSPI_BASE+0x70, 0x00);  //选择0通道cs
		Xil_Out32(QSPI_BASE+0x60, 0x86);  //使能master,开始发数据
		polling_tx_fifo_is_empty();
		Xil_Out32(QSPI_BASE+0x70, 0x01);  //选择0通道cs的cs拉高
		Xil_Out32(QSPI_BASE+0x60, 0x186); //禁用master
	}
	else if(cs_mode==1){/*start_xfer set cs=0*/
		Xil_Out32(QSPI_BASE+0x70, 0x00);  //选择0通道cs
		Xil_Out32(QSPI_BASE+0x60, 0x86);  //使能master,开始发数据
		polling_tx_fifo_is_empty();
		Xil_Out32(QSPI_BASE+0x60, 0x186); //禁用master
	}
	else{/*stop_xfer set cs=1*/
		Xil_Out32(QSPI_BASE+0x60, 0x86);  //使能master,开始发数据
		polling_tx_fifo_is_empty();
		Xil_Out32(QSPI_BASE+0x70, 0x01);  //选择0通道cs的cs拉高
		Xil_Out32(QSPI_BASE+0x60, 0x186); //禁用master
	}
}

void read_data(u32 num)
{
	for(int i=0; i<num; i++){
		u8 v=Xil_In32(QSPI_BASE+0x6c);
		printf("%d: %x\n",i,v);
	}
}

void read_cmd(u8 cmd, u32 num)
{
	config_spi();

	Xil_Out32(QSPI_BASE+0x60, 0x1e6);  //复位tx,rx fifo
	Xil_Out32(QSPI_BASE+0x60, 0x186);  //释放tx,rx fifo
	Xil_Out32(QSPI_BASE+0x68, cmd);
	for(int i=0; i<num-1; i++){
		Xil_Out32(QSPI_BASE+0x68, 0x00);
	}

	start_spi();
	read_data(num);
}

void read_id()
{
	read_cmd(0x9f,8);
}

void read_status()
{
	read_cmd(0x05,2);
	read_cmd(0x35,2);    //QE bit is default=1
	//read_cmd(0x15,2);  //cmd15 do not support
}

void write_data(u8 cmd, u8 *pdata, u32 length)
{/* length<=256-1*/
	Xil_Out32(QSPI_BASE+0x60, 0x1e6);
	Xil_Out32(QSPI_BASE+0x60, 0x186);
	Xil_Out32(QSPI_BASE+0x68, cmd);
	for(int i=0; i<length; i++){
		Xil_Out32(QSPI_BASE+0x68, *pdata++);
	}

	start_spi();
}

volatile u8 status;
void polling_qspi_busy()
{
	do{
		config_spi();

		Xil_Out32(QSPI_BASE+0x60, 0x1e6);
		Xil_Out32(QSPI_BASE+0x60, 0x186);
		Xil_Out32(QSPI_BASE+0x68, 0x05);
		Xil_Out32(QSPI_BASE+0x68, 0x00);

		start_spi();
		status=Xil_In32(QSPI_BASE+0x6c);  //first data drop
		status=Xil_In32(QSPI_BASE+0x6c);
	}
	while(status==0x03);
}


void wren()
{
	write_data(0x06, NULL, 0);
}

void se(u8 sector_num)
{
	wren();

	u8 tbuffer[3]={sector_num, 0x00, 0x00};
	write_data(0x20, &tbuffer[0],3);
}

void be()
{
	wren();
	write_data(0xc7, NULL,0);
}

void pp(u8 cmd, u32 address, u8 *pdata, u32 length)
{/* length<=256-4*/
	wren();
	Xil_Out32(QSPI_BASE+0x68, cmd);
	Xil_Out32(QSPI_BASE+0x68, (address>>16)&0xff);
	Xil_Out32(QSPI_BASE+0x68, (address>>8)&0xff);
	Xil_Out32(QSPI_BASE+0x68, address&0xff);
	for(int i=0; i<length; i++){
		Xil_Out32(QSPI_BASE+0x68, *pdata++);
	}

	start_spi();
}

void read(u8 cmd, u32 address, u8 *pdata, u32 length)
{/* length<=256*/
	Xil_Out32(QSPI_BASE+0x68, cmd);
	Xil_Out32(QSPI_BASE+0x68, (address>>16)&0xff);
	Xil_Out32(QSPI_BASE+0x68, (address>>8)&0xff);
	Xil_Out32(QSPI_BASE+0x68, address&0xff);
	for(int i=0; i<length-4; i++){
		Xil_Out32(QSPI_BASE+0x68, 0x00);
	}

	start_spi();
	printf("************cmd=%x****************\n",cmd);
	read_data(length);
}


void pp_try_long(u8 cmd, u32 address, u8 *pdata, u32 length)
{
/* 这个程序表明,AXI QUAD SPI这个IP的CS是完全由软件管理的,可以非常灵活的拉高或者拉低
 * 这样可以实现,一个很长的Packet。这个是在API函数中没有实现的功能。必须用寄存器手搓。
 */
	wren();
	Xil_Out32(QSPI_BASE+0x68, cmd);
	Xil_Out32(QSPI_BASE+0x68, (address>>16)&0xff);
	Xil_Out32(QSPI_BASE+0x68, (address>>8)&0xff);
	Xil_Out32(QSPI_BASE+0x68, address&0xff);

	u32 remain=length;
	while(remain>=128){
		for(int i=0; i<128; i++){
			Xil_Out32(QSPI_BASE+0x68, *pdata++);
		}
		if(remain==128){
			start_spi_by_cs_mode(2);
		}
		else{
			start_spi_by_cs_mode(1);
		}
		remain-=128;
	}

	if(remain){
		for(int i=0; i<remain; i++){
			Xil_Out32(QSPI_BASE+0x68, *pdata++);
		}
		start_spi_by_cs_mode(2);
	}

//	Xil_Out32(QSPI_BASE+0x70, 0x00);  //选择0通道cs
//	Xil_Out32(QSPI_BASE+0x60, 0x86);  //使能master,开始发数据
//	polling_tx_fifo_is_empty();
////	Xil_Out32(QSPI_BASE+0x70, 0x01);  //选择0通道cs的cs拉高
//	Xil_Out32(QSPI_BASE+0x60, 0x186); //禁用master
//
//
//	for(int i=0; i<length; i++){
//		Xil_Out32(QSPI_BASE+0x68, *pdata++);
//	}
//
////	Xil_Out32(QSPI_BASE+0x70, 0x00);  //选择0通道cs
//	Xil_Out32(QSPI_BASE+0x60, 0x86);  //使能master,开始发数据
//	polling_tx_fifo_is_empty();
////	Xil_Out32(QSPI_BASE+0x70, 0x01);  //选择0通道cs的cs拉高
//	Xil_Out32(QSPI_BASE+0x60, 0x186); //禁用master
//
//	for(int i=0; i<length; i++){
//		Xil_Out32(QSPI_BASE+0x68, *pdata++);
//	}
//
////	Xil_Out32(QSPI_BASE+0x70, 0x00);  //选择0通道cs
//	Xil_Out32(QSPI_BASE+0x60, 0x86);  //使能master,开始发数据
//	polling_tx_fifo_is_empty();
////	Xil_Out32(QSPI_BASE+0x70, 0x01);  //选择0通道cs的cs拉高
//	Xil_Out32(QSPI_BASE+0x60, 0x186); //禁用master

}



#define CDMA_BASE 0x7E200000
#define QSPI_XIP_BASE 0x41000000

//typedef u8 (*buffer8_type)[128];
//typedef u32 (*buffer32_type)[128];
//buffer8_type buffer8=(buffer8_type)0x11000000;
//buffer32_type buffer32=(buffer32_type)0x12000000;
//buffer8_type buffer8=(buffer8_type)0x44000000;
//buffer32_type buffer32=(buffer32_type)0x44002000;

#define BUFFER_BYTESIZE 128
volatile static u8 buffer8[BUFFER_BYTESIZE] __attribute__ ((aligned (64)));
volatile static u32 buffer32[BUFFER_BYTESIZE] __attribute__ ((aligned (64)));

void wait_for_idle()
{
	u32 tmp;
	while(1){
		tmp=Xil_In32(CDMA_BASE+04);
		if(((tmp>>1)&0x1) == 1){
			break;
		}
	}
}

void xip_for_read_test()
{
//	for(int i=0; i<128; i++){
//		buffer8[i]=Xil_In8(QSPI_XIP_BASE+i);
//	}
//	for(int i=0; i<128; i++){
//		xil_printf("%02x\r\n",buffer8[i]);
//	}

	for(int i=0; i<128; i++){
		buffer32[i]=Xil_In32(QSPI_XIP_BASE+4*i);
	}

	for(int i=0; i<128; i++){
		xil_printf("%04x\r\n",buffer32[i]);
	}
}

//void xip_dma_read_test()
//{
//	//Xil_Out32(CDMA_BASE+0x00, 0x00000020);  //key_hole_wr=1
//	Xil_Out32(CDMA_BASE+0x18, QSPI_XIP_BASE+0x0c0000);  //src_addr
//	Xil_Out32(CDMA_BASE+0x20, (u32)buffer8);  //dest_addr
//	Xil_Out32(CDMA_BASE+0x28, 128);         //burst_length
//	wait_for_idle();
//
//	Xil_DCacheInvalidateRange((u32)buffer8, 128);
//	for(int i=0; i<128; i++){
//		printf("%d\r\n",*buffer8[i]);
//	}
//}

int main(void)
{

	//初始化通用中断控制器
	ScuGic_Init();
	main_ps_io();
	Xil_DCacheDisable();

	//初始化AXI_SPI0,设为主机模式
	//AXI_SPI_Init(&AXI_SPI0, 0, XSP_MASTER_OPTION);

	//初始化私有定时器中断,定时间隔100ms
	ScuTimer_Int_Init(100000);


//	while(0) {
//		if(PS_GPIO_GetPort(PS_KEY)==0){
//			usleep(100*1000);
//			if(PS_GPIO_GetPort(PS_KEY)==0){
//				test_flash2();
//			}
//		}
//	}

	while(1) {
		if(PS_GPIO_GetPort(PS_KEY)==0){
			usleep(100*1000);
			if(PS_GPIO_GetPort(PS_KEY)==0){
				read_id(8);     //ok
				read_status();  //ok

				se(0);   //ok
				//read_status();
				//polling_qspi_busy();   //ok,33ms
				usleep(1000*1000);
//
				u8 tbuffer[512];
				for(int i=0; i<512; i++){
					tbuffer[i]=i;
				}

				pp(0x02,0x000000,&tbuffer[0],250);
				usleep(100*1000);
				//polling_qspi_busy();  //ok,172us
				//read_status();


				//while(PS_GPIO_GetPort(PS_KEY)==1);
				usleep(500*1000);
				read(0x03,0x000000, NULL, 256);  //第一遍读,没有输出,作废。好像是这个ip的问题,需要这么做。
				read(0x03,0x000000, NULL, 256);  //第二遍读,ok,1wire
//
//				while(PS_GPIO_GetPort(PS_KEY)==1);
				usleep(500*1000);
				read(0x0b,0x000000, NULL, 256);  //ok,1wire


				//while(PS_GPIO_GetPort(PS_KEY)==1);
				usleep(500*1000);
				read(0x3b,0x000000, NULL, 256);  //ok,2wire
//
//				while(PS_GPIO_GetPort(PS_KEY)==1);
				usleep(500*1000);
				read(0x6b,0x000000, NULL, 256);  //4wire

				//while(PS_GPIO_GetPort(PS_KEY)==1);
				usleep(500*1000);
				read(0xeb,0x000000, NULL, 256);  //4wire



//				while(PS_GPIO_GetPort(PS_KEY)==1);
//				usleep(500*1000);
//				se(0);
//				usleep(500*1000);
//				pp_try_long(0x32,0x001000,&tbuffer[0],512);  //cs由软件管理,可以发多个数据后再拉cs
//
//				while(PS_GPIO_GetPort(PS_KEY)==1);
//				usleep(500*1000);
//				read(0x03,0x001000, NULL, 256);  //ok,1wire
//
//				while(PS_GPIO_GetPort(PS_KEY)==1);
//				usleep(500*1000);
//				read(0x03,0x001100, NULL, 256);  //ok,1wire
			}
		}
	}


	while(0) {
		if(PS_GPIO_GetPort(PS_KEY)==0){
			usleep(100*1000);
			if(PS_GPIO_GetPort(PS_KEY)==0){
				xip_for_read_test();
//				usleep(1000);
//				xip_dma_read_test();
			}
		}
	}

	return 0;
}

运行结果:spi_sel=1,4线normal模式

image 逻辑分析仪波形,ok

image 0b/3b读结果ok,6b的print结果异常(感觉像是dummy错了一位的样子)

image eb的print结果也是异常

也就是说,4线模式,虽然接口处的波形是正确的,但是ip内部读到的数据存到ram中的是错的。

运行结果:spi_sel=0,4线xip模式

image
image
image
image

从结果看:4线xip结果不符合预期。它总是每次连续读2个u32,然后会重复读。地址的跳转没有规律。