(1)什么是EPP?
EPP是IEEE 1284标准(并行口标准)下的一个接口,该标准下还有SPP和ECP,但是EPP结合了两者的优势——速度和简便。
EPP的主要特性有:
1.在一个并行口上提供双相连接。
2.不存在数据溢出,你可以发送1byte或100万byte,只要在PC上使用一个软件循环就行。
EPP支持“地址”和“数据”的传输。
换句话说,PC可以发送4种EPP的传输指令:
1.写地址
2.读地址
3.写数据
4.读数据
我们此处将把
FPGA和EPP接口连接起来。当PC“写地址”(或是“写数据”)的时候,他会发送8bit的数据给FPGA,并指示出这是“地址”或“数据”。FPGA能对这些“地址”或“数据”为所欲为。FPGA可以实现一个寄存器组(包含256个寄存器),或是用“地址”来使LED闪烁,用“数据”来发出声音等。而PC是无法分辨的。
读取也是一样,FPGA会像PC传输任意8bit数据。
(2)软件
EPP的软件支持非常简单。我们接下来看一下。
BIOS
首先进入PC的BIOS设置并开启EPP
并行口地址
从软件角度来看,EPP的传输需要IO的读取和写入。
最常用的EPP地址是0x378。你可以在windows的控制面板中找到。
C写的函数
首先是EPP_init()函数。(初始化)
- #define EPP_port_addr 0x378 // 你的并行口地址
- void EPP_init()
- {
- IO_WRITE(EPP_port_addr+2, 0x04);
- }
很简单吧。
事实上,如果你的编译器不提供IO函数的话,你可能得自己写。
- void IO_WRITE(WORD addr, BYTE data)
- {
- _asm
- {
- mov dx, addr
- mov al, data
- out dx, al
- }
- }
- BYTE IO_READ(WORD addr)
- {
- _asm
- {
- mov dx, addr
- in al, dx
- }
- }
现在我们看到EPP支持了4种传输。我们来为其中的每个都写一个函数。
- void EPP_write_addr(BYTE address)
- {
- IO_WRITE(EPP_port_addr+3, address);
- }
- void EPP_write_data(BYTE data)
- {
- IO_WRITE(EPP_port_addr+4, data);
- }
- BYTE EPP_read_addr()
- {
- return IO_READ(EPP_port_addr+3);
- }
- BYTE EPP_read_data()
- {
- return IO_READ(EPP_port_addr+4);
- }
这就是全部内容了。
EPP软件可以处理所有EPP的协议细节,所以软件上不要花多大的心思。
(3)硬件协议
以下是PC上的DB25打印接口。
其中的2到9引脚为8bit数据的传输通道。在EPP模式下,这个8bit通道是双向的。
其他比较重要的引脚有。
17 地址选通 PC到FPGA 低电平有效 地址传输
14 数据选通 PC到FPGA 低电平有效 数据传输
11 等待 FPGA到PC 低电平有效 响应选通
1 写入 PC到FPGA 低电平有效 0位写入传输,1位读取传输
你会发现一共有2个“选通”信号加上一个“等待”信号。其中的“选通”信号来源于PC,而“等待”信号则是传输进PC的。
其原理是这样的:每次传输中,PC都会插入一种选通,然后FPGA以等待信号响应。
我们选一个选
通信号(一次只有一个有效),然后看看EPP的传输吧。
原理解释:
1.PC想要发起传输。它会插入某个选通信号。如果该传输为写入,那么“写入”信号为低电平,然后驱动8bit通道。不然的话“写入”信号为高电平,而8bit通道悬空。
2.FPGA检测到其中搞得一个选通信号,并以“等待”信号响应,解除有效信号。如果该传输为读取,那么FPGA才开始驱动8bit通道。
3.PC发现等待信号在解除有效信号,所以它会解除选通有效信号。如果传输为写入的话,那么PC会停止驱动8bit通道。
4.FPGA检测到选通信号被解除有效状态,就再度插入“等待信号”。如果传输为读取的话,那么FPGA就停止驱动8bit通道。
这些都是在硬件上实现的;PC软件除了开始传输外不会参与这个过程。
(4)HDL程序
我们来看一下在FPGA中实现EPP有多容易。首先我们创建几个来自并行口的信号。我们使得这些信号都是高电平有效。
- wire EPP_write = ~PP[1];
- wire EPP_addr_strobe = ~PP[17];
- wire EPP_data_strobe = ~PP[14];
- wire [7:0] EPP_datain = PP[9:2];
- // now for the EPP inputs
- wire EPP_wait; assign PP[11] = EPP_wait;
- wire [7:0] EPP_dataout; assign PP[9:2] = EPP_dataout;
如今大部分的FPGA设计都使用自己的时钟。所以我们将自己的时钟命名为“clk”并将选通信号与其同步。
- wire EPP_strobe = EPP_data_strobe | EPP_addr_strobe;
- reg [2:0] EPP_strobe_reg;
- always @(posedge clk) EPP_strobe_reg <= {EPP_strobe_reg[1:0], EPP_strobe};
- wire EPP_strobe_edge1 = (EPP_strobe_reg[2:1]==2'b01);
- wire EPP_strobe_edge2 = (EPP_strobe_reg[2:1]==2'b10);
- assign EPP_wait = EPP_strobe_reg[1];
现在我们可以处理EPP的写入了。我们来讲一些收到的值存入寄存器中。
- reg [7:0] addr_reg, data_reg;
- always @(posedge clk) if(EPP_strobe_edge1 & EPP_write & EPP_addr_strobe) addr_reg <= EPP_datain;
- always @(posedge clk) if(EPP_strobe_edge1 & EPP_write & EPP_data_strobe) data_reg <= EPP_datain;
然后再使用EPP读取,看下寄存器里存储的数据。
- wire EPP_read = ~EPP_write;
- wire [7:0] EPP_data_mux = EPP_addr_strobe ? addr_reg : data_reg;
- assign EPP_dataout = (EPP_read & EPP_wait) ? EPP_data_mux : 8'hZZ;
以上就是FPGA与EPP连接的全部内容了。