项目需求,FPGA的程序部署到ZYNQ上。查了一下发现网上几乎所有的教程都是打包成IP核,这对于我这个多层文件多个IP核很难实现。整体打包始终报错,加上觉得后面修改程序啥的太麻烦,而且PS和PL数据传输比较少,没有时效性要求。就尝试将PL和PS独立出来,方便修改。我觉得这应该是个挺常见的需求不知道为什么搜不到,可能关键字没找对。
再次强调,ZYNQ是个有PL外设的ARM。这就很好办了。首先block design反应了各个模块和ARM 核的关系,生成的wrapper也就是最终的外设部署。那么只要在顶层文件中直接添加PL模块,实现了PS和PL 的并列排布。PS和PL的数据通过AXI总线访问,预留端口,在顶层模块中直接wire 相连即可
程序涉密,所以用个简单的PL程序代替。
PL程序如图。除了心跳灯,就是assign将ps输入的数据回传给ps。
将一个AXI lite的总线打包为IP核
顶层添加输入输出
低层添加
AXI总线改写,用过的都懂
将AXI的IP核添加到block design,并引出输入输出
接下来就生成底层文件,并将PL模块添加到其中
`timescale 1 ps / 1 ps
module ps_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,
led,
clk,
rst_n
);
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;
output[3:0] led;
input clk;
input rst_n;
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 [31:0]pl_to_ps_0;
wire [31:0]ps_to_pl_0;
ps_system ps_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),
.pl_to_ps_0(pl_to_ps_0),
.ps_to_pl_0(ps_to_pl_0));
wire [3:0] led;
wire clk;
wire rst_n;
led_stream pl_system
(
.led(led),
.clk(clk),
.rst_n(rst_n),
.cnt_output_pl2ps(pl_to_ps_0),
最终的效果如图所示
可以看到实现了PS和PL 的并列
裸机 SDK程序如图,写入、加一、读出、串口打印
串口打印,可以看到满足了需求
linux系统代码测试如图:
22 #define ZYNQ_AXI_REG_BASE 0x43C00000
23 #define WRITE_AXI_REG_BASE 0
24 #define READ_AXI_REG_BASE 4
25
26
27 /* 映射后的寄存器虚拟地址指针 */
28 static void __iomem *write_addr;
29 static void __iomem *read_addr;
30
31 static int AXI_wr_rd_init(void)
32 {
33 u32 val = 100;
34 //int ret;
35
36 /* 寄存器地址映射 */
37 write_addr = ioremap(ZYNQ_AXI_REG_BASE + WRITE_AXI_REG_BASE, 4);
38 read_addr = ioremap(ZYNQ_AXI_REG_BASE + READ_AXI_REG_BASE, 4);
39
40 printk("testing……");
41
42 writel(val, write_addr);
43 msleep(1000);
44 val = readl(read_addr);
45
46 printk("%d",val);
47
48 /* 取消寄存器地址映射 */
49 iounmap(write_addr);
50 iounmap(read_addr);
51
52 return 0;
53 }
通过ioremap找到linux中的虚拟地址之后写入,读出