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设计
# 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+0x60, 0x1e6); /*20240908新增加,复位fifo*/
Xil_Out32(QSPI_BASE+0x60, 0x186); /*20240908新增加,复位fifo*/
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模式
逻辑分析仪波形,ok
0b/3b读结果ok,6b的print结果异常(感觉像是dummy错了一位的样子)
eb的print结果也是异常
也就是说,4线模式,虽然接口处的波形是正确的,但是ip内部读到的数据存到ram中的是错的。
运行结果:spi_sel=0,4线xip模式
从结果看:4线xip结果不符合预期。它总是每次连续读2个u32,然后会重复读。地址的跳转没有规律。
补充说明
20240908,在仿真AXI QuadSPI IP+W25Qxx Flash Model的时候,发现了一个bug。原来的程序,在read_data的时候,缺少复位fifo,这是不对。 这个IP,执行任何读写之前,都必须reset fifo,才可以正常工作。
Xil_Out32(QSPI_BASE+0x60, 0x1e6); /*20240908新增加,复位fifo*/
Xil_Out32(QSPI_BASE+0x60, 0x186); /*20240908新增加,复位fifo*/