前言

  • 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 下调用和使用。
    AXI EPC IP 使用详细说明-LMLPHP

    1. EPC 时钟选择 AXI 时钟
    1. EPC 时钟选择外接的外设时钟
    1. AXI 时钟周期,单位皮秒(ps)。(这个选项一般是自动产生的不需要编辑修改)
    1. 外设时钟周期,单位皮秒(ps)
    1. 外设片选数量
    1. 外设基地址。(这个选项一般是在 Address Editor 中产生的不需额外的编辑修改)
    1. 外设地址大小。(这个选项一般是在 Address Editor 中产生的不需额外的编辑修改)
      AXI EPC IP 使用详细说明-LMLPHP
    1. 地址宽度。(这里需要注意,在地址数据总线复用的模式下,地址线宽度和数据线宽度最好设置成一样,否则需要额外的编程代码才能正常的使用)
    1. 数据宽度。
    1. 数据宽度匹配选项,比如 AXI是32位,在读写 8/16 位外设空间时,启动这个功能就能用指针的方式任意读写 8/16位的外设空间。
    1. 数据地址复用选项,可以通过该选项减少 FPGA 的管脚数量。启动地址数据复用,总线就和8086/8088处理器的 AD 总线性质一样。C51单片机的 AD0-7 也是地址数据复用的总线。
    1. 同步模式选项。同步或异步模式的选项。
  • T1-T15 以 SJA1000 芯片的时序为例子,选的参数。波形图片也是从 SJA1000手册中截取的。
    AXI EPC IP 使用详细说明-LMLPHP

    1. FIFO 访问选项。当Enable FIFO Access = 1时,AXI EPC IP 核支持访问 FIFO

AXI EPC IP 使用详细说明-LMLPHP

应用举例

    1. 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


    1. 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

    1. EPC 外接 2片6264 SRAM 例子
  • EPC 外接 2片6264 SRAM 顶层管脚代码(system verilog)
//EPC 接 SRAM 26264 例子
//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

注意事项

    1. AXI EPC 的数据,地址是大端模式,在我的例子里采用的是小端模式,数据线地址线全部需要交叉使用。
      AXI EPC IP 使用详细说明-LMLPHP
    1. AXI EPC < Enable ADDR/DATA Multiplexing > 这个选项使能时,地址宽度和数据宽度最好相等,否则需要一些额外的代码
    1. AXI EPC < Enable Data Width Matching > 这个选项很好用,但是在一些与读写操作会改变寄存器的芯片里要谨慎使用。比如一些中断状态寄存器,读一下该寄存器中断状态会改变。比如一些 RC,WC 这样的寄存器。(RC 读该寄存器会清除某个状态。WC 写该寄存器会清除某个状态)这样的芯片在这里需要一些额外的代码才能正常的使用。

相关连接

  • 可以浏览本博客写的文章《FPGA + SJA1000 实现 <PCIe to CAN> 网卡的设计》 有完整的 PCIE AXI EPC 的代码和工程
09-22 14:51