The Raspberry Pi Zero family lacks a native RJ45 jack, forcing makers to choose between flaky WiFi or bulky USB adapters. To build a reliable, low-profile raspberry pi zero with ethernet, wire a Microchip ENC28J60 SPI Ethernet module directly to the hardware SPI0 pins (MOSI, MISO, SCLK, CE0) and enable the enc28j60 device tree overlay. This yields a dedicated 10BASE-T interface without occupying the USB OTG port, leaving it free for peripherals.

This guide targets the Raspberry Pi Zero 2 W running Raspberry Pi OS Bookworm (64-bit). We will cover the exact pinout, kernel configuration, and provide a Python diagnostic script to verify the PHY layer before you spend hours debugging network stacks.

Hardware Spec Sheet & Parts List

Difficulty Rating: Intermediate (Requires soldering headers and editing boot config files).
Time to Complete: 45 minutes.

The ENC28J60 is a 10Mbps Ethernet controller with an SPI interface. While it won't saturate a Gigabit network, it is perfect for IoT telemetry, MQTT nodes, and headless SSH access where WiFi reliability is a concern.

Component Exact Variant / Model Estimated Cost (2026) Notes
Compute Board Raspberry Pi Zero 2 W $15.00 - $20.00 Do not use the original Zero; the 2 W's quad-core handles SPI interrupts without dropping packets.
Ethernet Module ENC28J60 with Hanrun HR911105A Magjack $6.00 - $9.00 Ensure the board includes the RJ45 magjack with integrated magnetics.
Headers 2x20 Pin Male Header (2.54mm pitch) $1.50 Required if your Zero 2 W shipped without pre-soldered GPIO pins.
Wiring Silicone Female-to-Female Jumper Wires (28 AWG) $4.00 Keep SPI traces under 10cm to prevent signal degradation at 10MHz.
Power Supply 5V 2.5A USB-C or Micro-USB PSU $8.00 The ENC28J60 can draw up to 180mA during transmit bursts; do not rely on PC USB ports.

Pin Mapping & Physical Wiring

The ENC28J60 operates strictly on 3.3V logic. Safety Warning: Never connect the SPI data lines (MOSI, MISO, SCK, CS) to 5V. While some breakout boards include a 5V-to-3.3V LDO for the power rail, the logic pins on the Pi Zero 2 W are strictly 3.3V tolerant. Feeding 5V into GPIO 8 will permanently brick the SoC's SPI controller.

ENC28J60 Pin Pi Zero 2 W GPIO (BCM) Pi Zero 2 W Physical Pin Function
VCC N/A (3.3V Rail) Pin 1 Power (Use 3.3V if bare module, 5V if module has onboard LDO)
GND N/A (Ground) Pin 6 Common Ground
CS GPIO 8 Pin 24 SPI Chip Select (CE0)
SI (MOSI) GPIO 10 Pin 19 Master Out, Slave In
SO (MISO) GPIO 9 Pin 21 Master In, Slave Out
SCK GPIO 11 Pin 23 SPI Clock
INT GPIO 25 Pin 22 Interrupt Request (Active Low)
RST GPIO 17 Pin 11 Hardware Reset (Active Low)

According to the Microchip ENC28J60 Datasheet, the SPI clock frequency can reach up to 10MHz. However, when using jumper wires instead of a rigid PCB HAT, keep the clock closer to 4MHz to avoid phase-shift errors caused by parasitic capacitance in the wires.

Software Setup & Kernel Overlays

The Linux kernel does not probe SPI Ethernet chips automatically; you must explicitly load the device tree overlay. On Raspberry Pi OS Bookworm, the boot partition is mounted at /boot/firmware/ (unlike older Bullseye releases which used /boot/).

  1. Open the configuration file: sudo nano /boot/firmware/config.txt
  2. Scroll to the bottom and add the SPI hardware enablement and the specific overlay for the ENC28J60:
    dtparam=spi=on
    dtoverlay=enc28j60,int_pin=25
  3. Save and reboot: sudo reboot
  4. Verify the interface loaded by checking the kernel ring buffer:
    dmesg | grep enc28j60
    You should see: enc28j60 spi0.0 eth0: link up - Half duplex.

Python Diagnostics Code

Before relying on the OS network stack, it is best practice to verify the physical SPI link and the ENC28J60's internal PHY status. The following Python script uses the spidev library to perform a soft reset and read the ESTAT (Ethernet Status) register. This confirms the chip is alive and the clock is stable.

Prerequisite: Install the SPI tools via sudo apt install python3-spidev.

import spidev
import time
import sys

# Pin definitions for ENC28J60 on Pi Zero 2 W
SPI_BUS = 0
SPI_DEVICE = 0
CS_PIN = 8    # GPIO 8 (Physical Pin 24, CE0)
INT_PIN = 25  # GPIO 25 (Physical Pin 22)
RST_PIN = 17  # GPIO 17 (Physical Pin 11)

# ENC28J60 Register Addresses (Bank 0)
ESTAT = 0x1D
EIR = 0x1C

def read_register(spi, addr):
    # Read Control Register command: 0x00 | addr
    resp = spi.xfer2([0x00 | addr, 0x00])
    return resp[1]

def main():
    try:
        spi = spidev.SpiDev()
        spi.open(SPI_BUS, SPI_DEVICE)
        # Limit to 8MHz for stability on jumper wires (Max is 10MHz)
        spi.max_speed_hz = 8000000 
        spi.mode = 0
    except FileNotFoundError as e:
        print(f'FATAL: {e}')
        print('Fix: Enable SPI via sudo raspi-config or add dtparam=spi=on to /boot/firmware/config.txt')
        sys.exit(1)
    except Exception as e:
        print(f'Unexpected SPI initialization error: {e}')
        sys.exit(1)

    # Issue System Reset Command (SRC) to ENC28J60
    spi.xfer2([0xFF]) 
    time.sleep(0.1) # Wait for PHY to stabilize

    estat = read_register(spi, ESTAT)
    print(f'ENC28J60 ESTAT Register: 0x{estat:02X}')

    # Check CLKRDY (Bit 0) and TXABRT (Bit 1)
    if estat & 0x01: 
        print('SUCCESS: ENC28J60 Clock Ready. PHY is initialized.')
    else:
        print('WARNING: Clock not ready. Check 3.3V power and SPI wiring.')

    spi.close()

if __name__ == '__main__':
    main()

Debugging Network Failures

When wiring a raspberry pi zero with ethernet via SPI, hardware and software misconfigurations often masquerade as network timeouts. Here is the diagnostic decision tree.

The Exact Error: FileNotFoundError: [Errno 2] No such file or directory: '/dev/spidev0.0'

If the Python script above throws this exact string, the kernel has not created the SPI character device. Ranked causes:

  1. Overlay Missing: You forgot dtparam=spi=on in config.txt, or you edited the wrong file (e.g., editing /boot/config.txt on a Bookworm system where it is now a symlink or ignored in favor of /boot/firmware/config.txt).
  2. CS Pin Conflict: Another HAT or script is holding GPIO 8 high. Run sudo gpioinfo | grep gpio8 to check pin reservation.
  3. SPI Blacklisted: Check /etc/modprobe.d/raspi-blacklist.conf to ensure spi-bcm2708 is not blacklisted (common on older OS images).

The First Three Things to Check When eth0 Fails

If the Python script succeeds but you cannot ping the gateway, check these three physical and logical layers:

  • 1. Verify the Interface Name: Run ip a. The ENC28J60 might enumerate as eth1 if the internal USB Ethernet gadget (used for SSH over USB) is active. Adjust your DHCP requests to target the correct interface.
  • 2. Check SPI Voltage Sag: Use a multimeter to measure the 3.3V rail at the Pi's Pin 1 while pinging. If it drops below 3.1V during transmit bursts, the ENC28J60 will silently drop packets. Upgrade your power supply or add a 100µF electrolytic capacitor across the module's VCC and GND pins.
  • 3. Inspect Duplex Mismatch: The ENC28J60 only supports Half-Duplex 10BASE-T. If your managed switch forces Full-Duplex, you will experience massive collision rates. Force the switch port to 10M Half-Duplex, or let auto-negotiation handle it (do not hardcode the Pi's ethtool settings to full duplex).

Extending and Simplifying the Build

Depending on your deployment environment, you may want to alter this architecture.

How to Simplify: If you do not need the USB OTG port for anything else, abandon the SPI wiring entirely. Purchase a Micro-USB OTG to RJ45 Ethernet Adapter utilizing the RTL8152B chipset (~$12). It requires zero configuration, draws power directly from the USB bus, and supports 10/100Mbps Full-Duplex. This is the fastest path to a working raspberry pi zero with ethernet for temporary bench debugging.

How to Extend (PoE Integration): For remote IoT deployments (e.g., attic temperature monitors, outdoor gateways), running a separate 5V power cable is impractical. You can extend this build by adding an Active PoE Splitter (48V to 5V 2.4A). Plug the RJ45 from your PoE switch into the splitter's input, and route the splitter's 5V Micro-USB pigtail to the Pi Zero, and the RJ45 pigtail to the ENC28J60 module. This delivers both data and power over a single Cat6 cable, adhering to 802.3af standards.

FAQ: Raspberry Pi Zero Ethernet Queries

Can I power a Raspberry Pi Zero with Ethernet using PoE?

Yes, but not natively. Unlike the Pi 3B+ or Pi 4, the Zero lacks the 4-pin PoE header. To achieve Power over Ethernet, you must use an inline 48V-to-5V PoE splitter between your switch and the Pi. Ensure the splitter outputs at least 5V/2.5A to accommodate the Pi Zero 2 W and the ENC28J60 module's combined transient current draw.

Why is my Raspberry Pi Zero with Ethernet limited to 10Mbps?

The ENC28J60 chip is fundamentally a 10BASE-T controller. It lacks the internal DSP hardware required to negotiate 100BASE-TX (Fast Ethernet). If your project requires 100Mbps speeds (e.g., streaming a high-framerate camera feed), you must use a USB-based adapter with a Realtek RTL8153 or ASIX AX88179 chipset instead of the SPI module.

How do I fix a Raspberry Pi Zero with Ethernet dropping packets?

Packet drops on SPI Ethernet are almost always caused by CPU starvation or SPI clock errors. The Pi Zero 2 W handles this better than the original Zero, but you should ensure no heavy background tasks (like compiling code or running unoptimized Python loops) are starving the kernel's SPI interrupt handler. Additionally, lower the SPI clock speed in your device tree overlay or Python script from 10MHz to 4MHz to eliminate phase noise on long jumper wires.

Do I need a USB OTG hub if I use an SPI Ethernet module?

No. That is the primary advantage of the SPI approach. Because the ENC28J60 communicates over the GPIO header's SPI bus, your single Micro-USB OTG port remains entirely free. You can plug in a USB WiFi dongle, a software-defined radio (SDR), or a Zigbee coordinator without needing to buy and power a bulky USB hub.