It was our experience, however, that developing for an EPP card (specifically the FarPoint F/PortPlus card with an SMC FDC37C666GT controller chip) was far from easy. We ran into a number of problems before we got the card to work, and so we present this page in the hope that others don't suffer as much as we did. "Parallel Port Complete" by Jan Axelson is an excellent book on the subject, and you might not need to look any further. It is a very recent publication.
Some quick background on EPP
The handshaking for an EPP transfer is
performed by the hardware, and not by software as with the PS/2 parallel port
protocol. This means that data is transferred in a single I/O cycle. This, of
course, makes development easier and performance much faster.
The FDC37C666GT (as well as the FDC37C665GT) provides four 8-bit EPP ports,
located at offsets +4, +5, +6, and +7 from the parallel port's base address
(these are described in more detail in the technical spec
paper on pages 92-96). An 8-bit I/O write (e.g., using the out
assembler directive or the outportb
function) to any of these four
ports automatically transfers the data to the peripheral in EPP mode (assuming,
of course, that the port was already placed in EPP
mode). An advantage of having four ports is that if a 16- or 32-bit
out
instruction is issued, the two or four bytes will be sent
automatically in sequence to the peripheral. That is, if a 32-bit doubleword is
output to the first of the four EPP ports (using, for example, the
outsd
) assembler directive, then the peripheral will receive the
four bytes of the doubleword, even though only one I/O instruction was issued.
Note that the peripheral cannot receive a single 32-bit value because the
parallel port, even under EPP, is still only 8 bits wide. By using 16- and
32-bit transfers along with string transfer instructions (e.g., rep
outsw
) we can achieve high transfer rates.
There are two type of transfers: 'address' and 'data'. These are both 8-bit transfers, and they can be used interchangeably. The main difference is in the handshaking signals: the control signals for an address transfer are slightly different than for a data transfer. This allows an application to have, in effect, two distinct communication channels with the peripheral - values can be interpreted differently based on whether they are address or data values. In our application, for example, we use address transfers to implement our application protocol. The other difference between data and address transfers is that you cannot do 2- or 4-byte address transfers as you can with data transfers (see above).
Placing the chip into EPP mode (Corrected on March 5, 1997)
The technical spec
paper for the FDC37C666GT provides the details of using the chip in EPP
mode. However, the information in the paper is disorganized and incomplete, at
best. An excellent resource is "Parallel Port Complete" by Jan
Axelson. Page 212 starts the discussion on the SMC FDC37C665GT and FDC37C666GT
chips. Here is a simple code example which demonstrates how we can reliably
place the chip in EPP mode. Note that if you use a chip other than the above
two, this code may not work.
#define ECR_OFFSET 0x402
#define CONTROL_PORT 2
typedef unsigned char Byte;
/* port_addr = 0x278 or 0x378, chip = '666' or '665' */
void begin_EPP( int port_addr, int chip )
{
begin_config_mode( chip );
/*
// control word for configuring
// CR Bits 1, Port address 00 -> disabled
// 01 -> 0x3bc
// 10 -> 0x378
// 11 -> 0x278 (default)
// Bit 2 Port power 1 -> power supplied (default)
// 0 -> low power mode
// Bit 3 Mode 1 -> SPP (default)
// 0 -> Extended modes allowed (CR4-bits 0,1)
// Bit 4 IRQ polarity 1 -> active high, inactive low (default)
// 0 -> active low, inactive high-Z
// (always true in ECP,EPP)
*/
outportb( 0x3f0, 1 ); /* Set CR1 */
if (port_addr == 0x378)
outportb( 0x3f1, 0x96 ); // use 0x378
else
outportb( 0x3f1, 0x97 ); // use 0x278
/*
// CR4 Bits 0,1 Ext modes 10 -> SPP, PS/2 (default)
// 01 -> SPP and EPP
// 10 -> ECP
// 11 -> ECP and EPP
// Bit 6 EPP type 0 -> EPP 1.9 (default)
// 1 -> EPP 1.7
*/
outportb( 0x3f0, 4 ); // use CR4
outportb( 0x3f1, 3 ); // use EPP
/*
// CRA Bits 0-3 ECP FIFO thres -> threshold for ECP service requests
// default 0
*/
/* Use if you need
outportb( 0x3f0, 0xa ); // use CRA
outportb( 0x3f1, 8 ); // threshold for ECP requests
*/
/*
// 0x34 == <0011 0100>
// PS/2 (byte, bidirectional) type (bits 7-5) == 001,
// no interrupts at nError (bit 4) == 1,
// disable DMA (bit 3) == 0,
// disable DMA and service interrupts (bit 2) == 1
// bits 1,0 read only, so don't care
*/
outportb(port_addr + ECR_OFFSET, 0x34 );
/* pulse - nInit (bit 2) low */
outportb(port_addr + CONTROL_PORT, 0x00 );
end_config_mode();
/*
// ECP emulating EPP 0x80 == <1000 0000>
// For EPP mode, set ECR of ECP to mode (bits 7-5) == 100
// Falling edge of nError generates interrupt (bit 4) == 0,
// disable DMA (bit 3) == 0,
// enable service interrupts (bit 2) == 0
// bits 1,0 read only, so don't care
*/
outportb(port_addr + ECR_OFFSET, 0x80 ); /* Set ECR to EPP mode */
/*
// pulse - nInit (bit 2) high; reset the peripheral,
// min pulse width 50 micro-sec
*/
outportb(port_addr + CONTROL_PORT, 0x04 );
}
/*----------------------------------------------------------------------*/
/* These two functions are based on page 117 of the tech spec */
/* and also in "Parallel Port Complete", Page 214 */
void begin_config_mode ( int chip )
{
Byte init_code;
switch(chip)
{
case 666: init_code = 0x44; break;
case 665: init_code = 0x55; break;
default: fprintf(stderr, "Chip %d not supported!!!\n", chip); exit(1);
}
disable();
outportb(0x3f0, init_code);
outportb(0x3f0, init_code);
enable();
}
/*
// Note that there is a typo in Parallel Port Complete, page 214
// it says write to 0x3f1 instead of 0x3f0
*/
void end_config_mode ( void )
{
outportb( 0x3f0, 0xaa );
}
/*----------------------------------------------------------------------*/
This code places the chip into EPP mode. It sets the necessary values in
the configuration registers (pages 117-128 of spec), and in the Extended Control
Register (buried in page 103 of spec).
Transferring data (and addresses)
Once the chip has been
successfully placed into EPP mode, transferring data is trivial:
To write a
byte of data:
outportb( base_addr + 4, data );
To write an address
byte: outportb( base_addr + 3, value );
To read a byte of
data: data = inportb( base_addr + 4 );
To read an address
byte: value = outportb( base_addr + 3 );
After each transfer, you should check the status register to see if an error has occurred (such as a timeout). The status register is described on page 94 os the spec. We found that we could ignore the PAPEREND and nACK bits when checking for errors (they would always indicate error, even though the data had been successfully transmitted).
Status checking and clearing the timeout bit
It is required that the timeout bit in the status register be cleared after every EPP operation. It is the bit 2 in the status register. In the above two chips (SMC 665 and 666) it is cleared by writing 1 (yes, 1 and not 0) to that bit. Writing 0 doesn't make a difference. If the timeout bit is set every EPP operation will fail.
typedef
struct _Status
{
Byte timeout, error, select, paper_end, ack, busy;
} Status;
/* returns 1 when there was some problem with the last operation */
int check_status(int port_addr)
{
Status stat;
// read status and clear timeout bit
read_status(port_addr, &stat);
/* We ignore the 'paper_end' and 'ack' bit */
return (stat.timeout || stat.error || ! stat.select || stat.busy);
}
#define STATUS_PORT 1
// bits in the parallel port's status register
#define STATUS_TIMEOUT 0
#define STATUS_nERROR 3
#define STATUS_SELECT 4
#define STATUS_PAPEREND 5
#define STATUS_nACK 6
#define STATUS_nBUSY 7
#define TEST_BIT( x, b ) (((x) & (1<<(b))) != 0 )
/* Checks and returns each bit of the status register */
void read_status(int port_addr, Status *stat)
{
Byte status;
/* read the status port */
status = inportb(port_addr + STATUS_PORT);
/*
// Then interpret its bits
// The 1 - is for the bits that are inverted from port pin to register
*/
stat->timeout = TEST_BIT( status, STATUS_TIMEOUT );
stat->error = 1 - TEST_BIT( status, STATUS_nERROR );
stat->select = TEST_BIT( status, STATUS_SELECT );
stat->paper_end = TEST_BIT( status, STATUS_PAPEREND );
stat->ack = 1 - TEST_BIT( status, STATUS_nACK );
stat->busy = 1 - TEST_BIT( status, STATUS_nBUSY );
/* We clear the timeout bit by writing 1 to bit 0 */
/* SMC specific , might need to change for others */
if ( stat->timeout )
{
status = status | STATUS_TIMEOUT; // clears by writing 1 on SMC
outportb(port_addr+STATUS_PORT, status);
}
}
Transferring strings of data or address bytes
String transfers are
only slightly more complicated than single-byte transfers. Of course, you can
write bytes in a loop to do this. Here is an example in assembly for writing 30
16-bit values to the EPP data port (for a total of 60 bytes transferred):
{
static char buf[ 60 ]; /* Must be static so that it is appropriately
placed in the data register and not on the stack.
Experienced PC assembly programmers will
know how to circumvent this */
asm
{
mov si, offset buf
mov dx, base_addr /* Base address of parallel port */
add dx, 4 /* 4 is the first EPP port's offset */
cld
mov cx, 30 /* 30 transfers */
rep outsw /* outsw transfers 16-bit values */
}
}
Resetting the EPP port
Resetting the EPP port consists of asserting
the nINIT line then deasserting it. This is accomplished by the following
code:
#define CONTROL_PORT 2
#define CONTROL_nINIT 2
#define SET_BIT( x, b ) ((x) |= (1 << (b)))
#define CLEAR_BIT( x, b ) ((x) &= ~(1 << (b)))
void reset( void )
{
char control;
control = inportb( base_addr + CONTROL_PORT );
CLEAR_BIT( control, CONTROL_nINIT );
outportb( base_addr + CONTROL_PORT, control );
SET_BIT( control, CONTROL_nINIT );
outportb( base_addr + CONTROL_PORT, control );
}
Currently maintained by Pawan Kumar.
Last updated: 03/14/97
file: /Techref/io/parallel/EPP-pk.htm, 15KB, , updated: 2020/3/11 04:47, local time: 2024/11/8 16:02,
18.224.31.14:LOG IN ©2024 PLEASE DON'T RIP! THIS SITE CLOSES OCT 28, 2024 SO LONG AND THANKS FOR ALL THE FISH!
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/Techref/io/parallel/EPP-pk.htm"> EPP</A> |
Did you find what you needed? |
Welcome to massmind.org! |
Ashley Roll has put together a really nice little unit here. Leave off the MAX232 and keep these handy for the few times you need true RS232! |
.