ENC28J60 Ethernet
The FPGC has 10 Mbit Ethernet provided by a Microchip ENC28J60
controller. The chip integrates a MAC, a 10BASE-T PHY, and an
8 KiB packet buffer behind a single SPI port; from the FPGA's point
of view it is just another SPI peripheral on SPI4. The magnetics
and RJ-45 jack on the PCB connect directly to the chip's TPIN/TPOUT
differential pairs.
The driver running on the FPGC is a thin layer that pushes raw Ethernet frames in and out of the on-chip buffer; everything above the link layer (FNP, ARP, …) is handled by software.
Bus shape
| Pin | Role |
|---|---|
CS |
chip select (active low) |
CLK |
serial clock |
SI |
host → chip (MOSI) |
SO |
chip → host (MISO) |
INT |
open-drain interrupt to host |
RST |
active-low reset |
WOL |
wake-on-LAN (unused) |
CLKOUT |
programmable clock output (unused) |
The chip needs a 25 MHz crystal of its own (separate from the FPGA clock domain) for the PHY. The SPI clock is independent of that and runs at the same divider as the rest of the FPGA's slow-side SPI peripherals — well below the chip's 20 MHz SPI maximum.
INT is wired to the FPGA's interrupt controller and surfaces as a
dedicated CPU interrupt line. The driver enables only the
packet-pending interrupt; everything else (link change, TX
done, errors) is polled when needed.
Memory model
The ENC28J60 has 8 KiB of internal SRAM that is shared between the RX and TX paths. Software partitions it with a pair of pointers:
- RX buffer — a circular region delimited by
ERXSTandERXND. The chip writes incoming frames here and advances its own write pointer. The host reads frames out by streaming from the chip's read pointer and then advancing it. - TX buffer — the rest of the SRAM, used as a scratch pad for outgoing frames. The host loads a frame, writes the start and end pointers, and tells the chip to transmit.
Each received frame is preceded by a 6-byte status vector: the next-packet pointer (used by the circular RX bookkeeping), the received byte count, and a status word with CRC-OK and other flags. Each transmitted frame is followed by a 7-byte status vector with the on-air byte count and the TX result.
There is one register page that is always visible (the special function registers — control, status, interrupts) plus a paged set of MAC and PHY registers reached through bank-select bits in the control register. Driver code switches banks before each access to a banked register and clears them afterwards.
Command set
The ENC28J60 SPI command set is intentionally tiny — eight instructions, identified by the top three bits of the opcode byte:
| Opcode (top 3 bits) | Mnemonic | Purpose |
|---|---|---|
000 |
RCR |
Read control register |
001 |
RBM |
Read buffer memory |
010 |
WCR |
Write control register |
011 |
WBM |
Write buffer memory |
100 |
BFS |
Bit-field set in a control register |
101 |
BFC |
Bit-field clear in a control register |
111 |
SRC |
Soft reset |
The remaining five bits of the opcode byte select the target
register, except for RBM/WBM which use a fixed encoding and
operate on the buffer memory pointed to by ERDPT/EWRPT.
Reading and writing the chip's SRAM is just the RBM/WBM
opcode followed by an arbitrary number of data bytes. The chip
auto-increments its internal pointer per byte, so a single SPI
transaction can move an entire frame.
Init
After power-up the chip needs:
- A soft reset (
SRC). - A short wait — the spec calls out an OST (Oscillator Start-up Timer) that must elapse before the chip becomes responsive.
- Programming the RX buffer pointers (
ERXST/ERXND/ERXRDPT) to carve out the partition between RX and TX. - MAC configuration: enable receive, full or half duplex, link-level addressing, and the receive filter. The FPGC enables broadcast + unicast filters; multicast and promiscuous modes are off.
- Programming the local MAC address. The FPGC derives a per-board address from the unique ID of one of the SPI flash chips; the OUI half is fixed.
- PHY configuration: link enable, full or half duplex, and the LED blink mode.
- Enabling the packet-pending interrupt and the global interrupt master.
After all of that the chip starts accepting frames into the RX buffer and the host starts taking interrupts.
RX path
When a frame arrives the chip writes it into the RX buffer behind
the current write pointer and asserts INT. The host responds by:
- Reading
EPKTCNTto find out how many frames are waiting. - Setting
ERDPTto the saved next-packet pointer. - Streaming the 6-byte status vector and the frame payload out via
RBM. - Updating
ERXRDPTto release the buffer slot. - Decrementing
EPKTCNT(by writing thePKTDECbit inECON2).
The status vector's next-packet pointer chains the frames
together; the host always knows where the next one starts because
the chip wrote it as part of the previous frame's header.
When the host falls behind, the chip's RX buffer eventually fills.
The chip then drops new frames and asserts the RXERIF flag.
TX path
Sending a frame is the symmetric flow:
- Write the frame into the TX region of the buffer with
WBM. - Set
ETXSTandETXNDto delimit the frame. - Write the
TXRTSbit inECON1to start the transmission. - Wait until the chip clears
TXRTS(or untilESTAT.TXABRTis set, indicating an error). - Read the 7-byte transmit status vector out of the buffer to find out the on-air byte count and any collision/abort information.
Chained transmissions are not used; the FPGC sends one frame at a time.
DMA path
Both buffer-memory operations (RBM for RX, WBM for TX) are
streamed through the DMA engine's SPI burst port. A
typical RX moves the 6-byte status vector through the per-byte CPU
path, then hands the payload over to the DMA. A TX is the same in
reverse: the CPU writes the destination pointers and the start
opcode, then DMA streams the payload.
The DMA path keeps the CPU free for handling FNP-level work (checksums, ARP, ACK timing) while a packet is moving across the SPI bus.
Interrupt
The chip's INT pin is wired to a dedicated CPU interrupt line.
The handler reads EIR to find out what happened, services any
pending packets, and clears the interrupt by writing the
appropriate bits. When the SPI bus is busy with another transaction
at the moment the interrupt fires, the driver defers the work to a
short timer-driven retry rather than blocking inside the ISR.
Network protocol
The frames the FPGC actually puts on the wire are not IP. The
project uses FNP, a lightweight custom L2 protocol carried in
raw Ethernet frames with EtherType 0xB4B4. FNP defines its own
file-transfer and remote-keyboard message types and runs entirely
between two FPGCs on the same Ethernet segment. There is no IP
stack on board; bridging to a real network requires a separate
host running an FNP-to-IP gateway.