前言
- AXI External Peripheral Controller (EPC) ,AXI 外部设备控制器(EPC)。
- 可以通过 AXI 扩展各种计算机外设,支持同步和异步接口。
- 支持地址数据复用/不复用总线。
- 数据总线支持8/16/32位
- 兼容 EMI(External Memory Interface) 外部存储器接口,可通过该接口外接多种外设芯片。
- 有疑问可以联系 QQ:708907433
简介
- Xilinx FPGA 内嵌的 CPU ,可以通过 AXI EPC 在 FPGA 芯片外接多个多种外设芯片,比如 SJA1000 CAN 控制器,DM9000 以太网络控制器,16C550 串口控制器等。
- 可以用 FPGA 做 PCIE to EMI 的桥接芯片,用PCIE 通过 FPGA 内的 AXI EPC 外接多个多种外设芯片,比如 SJA1000 CAN 控制器,DM9000 以太网络控制器,16C550 串口控制器等。
- AXI EPC IP 使用很简单,但是有很多需要注意的地方,都是大坑。
AXI EPC IP 使用介绍
-
AXI EPC IP 只能在 VIVADO 的 Block Design 下调用和使用。
-
- EPC 时钟选择 AXI 时钟
-
- EPC 时钟选择外接的外设时钟
-
- AXI 时钟周期,单位皮秒(ps)。(这个选项一般是自动产生的不需要编辑修改)
-
- 外设时钟周期,单位皮秒(ps)
-
- 外设片选数量
-
- 外设基地址。(这个选项一般是在 Address Editor 中产生的不需额外的编辑修改)
-
- 外设地址大小。(这个选项一般是在 Address Editor 中产生的不需额外的编辑修改)
- 外设地址大小。(这个选项一般是在 Address Editor 中产生的不需额外的编辑修改)
-
- 地址宽度。(这里需要注意,在地址数据总线复用的模式下,地址线宽度和数据线宽度最好设置成一样,否则需要额外的编程代码才能正常的使用)
-
- 数据宽度。
-
- 数据宽度匹配选项,比如 AXI是32位,在读写 8/16 位外设空间时,启动这个功能就能用指针的方式任意读写 8/16位的外设空间。
-
- 数据地址复用选项,可以通过该选项减少 FPGA 的管脚数量。启动地址数据复用,总线就和8086/8088处理器的 AD 总线性质一样。C51单片机的 AD0-7 也是地址数据复用的总线。
-
- 同步模式选项。同步或异步模式的选项。
-
T1-T15 以 SJA1000 芯片的时序为例子,选的参数。波形图片也是从 SJA1000手册中截取的。
-
- FIFO 访问选项。当Enable FIFO Access = 1时,AXI EPC IP 核支持访问 FIFO
应用举例
-
- EPC 外接 SJA1000 例子
- EPC 外接 SJA1000 顶层管脚代码(system verilog)
//EPC 接 SJA1000 例子
//Address Width 8
//Data Bus Width 8
//Enable Data Width Matching 1
//Enable ADDR/DATA Multiplexing 1
//Enable SYNC Mode 0
module fpga_axi_epc_ad8_root //这是顶层代码管脚的 EPC 相关部分
(
//..
inout [7:0] ad,
output ads,
output cs_n,
output wr_n,
output rd_n,
);
genvar n;
logic [7:0] epc_data_i; // 8 位
logic [7:0] epc_data_o;
logic [7:0] epc_data_t;
logic [7:0] epc_addr;
for(n=0;n<8;n++)
begin:for_iobuf_xx
assign ad[n] = epc_data_t[n] == 1 ? 1'bz:epc_data_o[n];
assign epc_data_i[n] = ad[n];
end
cpu_block_design ux //Block Design EPC 接口部分
(
.epc_addr (epc_addr), //output [0:7]
.epc_ads (ads), //output
.epc_be (), //output [0:0]
.epc_burst (), //output
.epc_cs_n (cs_n), //output [0:0]
.epc_data_i (epc_data_i), //input [0:7]
.epc_data_o (epc_data_o), //output [0:7]
.epc_data_t (epc_data_t), //output [0:7]
.epc_rd_n (rd_n), //output
.epc_rdy (1),
.epc_rnw (), //output
.epc_wr_n (wr_n), //output
.epc_clk (1),
.epc_rst (1),
);
endmodule
-
- EPC 外接 6264 SRAM 例子
- EPC 外接 6264 SRAM 顶层管脚代码(system verilog)
//EPC 接 SRAM 6264 例子
//Address Width 16
//Data Bus Width 8
//Enable Data Width Matching 1
//Enable ADDR/DATA Multiplexing 0
//Enable SYNC Mode 0
module fpga_axi_epc_d8_a16_root //这是顶层代码管脚的 EPC 相关部分
(
//..
inout [7:0] d,
output [15:0] a,
output cs_n,
output wr_n,
output rd_n,
);
genvar n;
logic [7:0] epc_data_i; // 8 位
logic [7:0] epc_data_o;
logic [7:0] epc_data_t;
logic [7:0] epc_addr;
for(n=0;n<8;n++)
begin:for_iobuf_xx
assign d[n] = epc_data_t[n] == 1 ? 1'bz:epc_data_o[n];
assign epc_data_i[n] = d[n];
end
cpu_block_design ux //Block Design EPC 接口部分
(
.epc_addr (a), //output [0:15]
.epc_ads (), //output
.epc_be (), //output [0:0]
.epc_burst (), //output
.epc_cs_n (cs_n), //output [0:0]
.epc_data_i (epc_data_i), //input [0:7]
.epc_data_o (epc_data_o), //output [0:7]
.epc_data_t (epc_data_t), //output [0:7]
.epc_rd_n (rd_n), //output
.epc_rdy (1),
.epc_rnw (), //output
.epc_wr_n (wr_n), //output
.epc_clk (1),
.epc_rst (1),
);
endmodule
-
- EPC 外接 2片6264 SRAM 例子
- EPC 外接 2片6264 SRAM 顶层管脚代码(system verilog)
//EPC 接 SRAM 2片 6264 例子
//Address Width 16
//Data Bus Width 16
//Enable Data Width Matching 1
//Enable ADDR/DATA Multiplexing 1
//Enable SYNC Mode 0
module fpga_axi_epc_ad16_root //这是顶层代码管脚的 EPC 相关部分
(
//..
output [15:0] ad,
output ads,
output cs_n,
output wr0_n,
output wr1_n,
output rd_n,
);
genvar n;
logic [15:0] epc_data_i; // 16 位
logic [15:0] epc_data_o;
logic [15:0] epc_data_t;
logic [15:0] epc_addr;
logic [1:0] epc_be;
logic epc_wr_n;
for(n=0;n<16;n++)
begin:for_iobuf_xx
assign ad[n] = epc_data_t[n] == 1 ? 1'bz:epc_data_o[n];
assign epc_data_i[n] = ad[n];
end
assign wr0_n = (~epc_be[0])|epc_wr_n;
assign wr1_n = (~epc_be[1])|epc_wr_n;
cpu_block_design ux //Block Design EPC 接口部分
(
.epc_addr (), //output [0:15]
.epc_ads (ads), //output
.epc_be (epc_be), //output [0:1]
.epc_burst (), //output
.epc_cs_n (cs_n), //output [0:0]
.epc_data_i (epc_data_i), //input [0:15]
.epc_data_o (epc_data_o), //output [0:15]
.epc_data_t (epc_data_t), //output [0:15]
.epc_rd_n (rd_n), //output
.epc_rdy (1),
.epc_rnw (), //output
.epc_wr_n (epc_wr_n), //output
.epc_clk (1),
.epc_rst (1),
);
endmodule
注意事项
-
- AXI EPC 的数据,地址是大端模式,在我的例子里采用的是小端模式,数据线地址线全部需要交叉使用。
- AXI EPC 的数据,地址是大端模式,在我的例子里采用的是小端模式,数据线地址线全部需要交叉使用。
-
- AXI EPC < Enable ADDR/DATA Multiplexing > 这个选项使能时,地址宽度和数据宽度最好相等,否则需要一些额外的代码
-
- AXI EPC < Enable Data Width Matching > 这个选项很好用,但是在一些与读写操作会改变寄存器的芯片里要谨慎使用。比如一些中断状态寄存器,读一下该寄存器中断状态会改变。比如一些 RC,WC 这样的寄存器。(RC 读该寄存器会清除某个状态。WC 写该寄存器会清除某个状态)这样的芯片在这里需要一些额外的代码才能正常的使用。
相关连接
- 可以浏览本博客写的文章《FPGA + SJA1000 实现 <PCIe to CAN> 网卡的设计》 有完整的 PCIE AXI EPC 的代码和工程