May 18 / Sebastian Helmut

Ethernet for Embedded Developers: PHY, MDIO, MAC, and DMA Descriptors from Scratch

Don't hesitate

Get the Professional Embedded Starter Kit: Production-ready templates and architectural cheat sheets for your firmware projects.

Ethernet for Embedded Developers: PHY, MDIO, MAC and DMA Descriptors from Scratch


1. Introduction:

Ethernet is the most widely used wired networking technology in the world, and it is increasingly common in embedded systems. Industrial controllers, network switches, medical devices, and automotive ECUs all rely on Ethernet to move data reliably at high speed. Yet most embedded developers who integrate Ethernet into their designs treat it as a black box, configuring a HAL driver or dropping in LwIP without understanding what is happening at the hardware level.

This article builds that foundation. We cover the full Ethernet hardware stack from the physical wire to the point where your software receives a frame: the PHY layer, signal encoding, the magnetics, the MDIO bus, the MAC layer, frame structure, and how DMA descriptors move data between the hardware and your buffers. Understanding these layers is essential before writing a single line of bare metal Ethernet code.


2. The Ethernet Physical Layer: PHY and the Wire

2.1 What the PHY Does

The PHY, short for Physical Layer transceiver, is the chip that sits between the MAC and the network cable. Its job is to convert the digital signals produced by the MAC into analog waveforms suitable for transmission over a copper cable, and to do the reverse on reception.

On the transmit side, the PHY takes parallel data from the MAC interface, encodes it, and drives the cable with the resulting analog signal. On the receive side, it detects incoming signals on the cable, recovers the clock, decodes the data, and presents it back to the MAC as digital bits. The PHY also handles link detection, auto-negotiation, and loopback testing.

In embedded designs, the PHY is almost always a separate chip connected to the microcontroller's Ethernet MAC peripheral. Common examples include the LAN8720, DP83848, and KSZ8081.

2.2 Ethernet Standards: 10BASE-T, 100BASE-TX, and 1000BASE-T

The naming convention for Ethernet standards encodes the key properties of each variant. The number at the start is the speed in megabits per second. BASE means baseband transmission, as opposed to broadband. The final part describes the physical medium or encoding scheme.

10BASE-T operates at 10 Mbps over twisted pair cable. It uses Manchester encoding, where each bit is represented by a signal transition at the center of the bit period. This self-clocking property means no separate clock line is needed.

100BASE-TX, also called Fast Ethernet, operates at 100 Mbps over two pairs of Category 5 cable. It uses MLT-3 encoding combined with 4B5B encoding to reduce the signal bandwidth while maintaining DC balance on the line.

1000BASE-T, also called Gigabit Ethernet, operates at 1000 Mbps over four pairs of Category 5e or better cable. It uses PAM-5 encoding, which carries 2 bits per symbol using five voltage levels, and transmits simultaneously on all four pairs in both directions using echo cancellation.

For most STM32-based embedded designs, 100BASE-TX is the practical target. Gigabit requires a more complex PHY and a MAC with GMII or RGMII interface support, which not all STM32 variants provide.

2.3 Signal Encoding and the Transformer: Why Galvanic Isolation Matters

Between the PHY chip and the RJ45 connector sits a magnetic transformer, often called the magnetics or the LAN transformer. This component is not optional. It serves two critical functions.

The first function is galvanic isolation. The transformer provides electrical isolation between the cable and the PHY chip. Without it, voltage differences between two connected devices, or a cable that picks up interference, would couple directly into the PHY and potentially into the microcontroller. The isolation prevents ground loops and protects the hardware from transient voltages.

The second function is common mode noise rejection. The transformer is a balun, converting between the balanced differential signal on the cable and the single-ended or differential signals expected by the PHY. This rejects common mode noise picked up by the cable.

Some RJ45 connectors come with integrated magnetics, which simplifies board layout. When designing your own hardware, always follow the PHY datasheet recommendations for the transformer specification, as the wrong transformer will degrade signal integrity and cause link failures.

2.4 MII and RMII Interfaces

The interface between the MAC and the PHY is standardized. The two most common variants in embedded designs are MII and RMII.

MII, the Media Independent Interface, was defined in the original IEEE 802.3u standard for Fast Ethernet. It uses a 4-bit wide data path with separate transmit and receive clocks. The PHY provides a 25 MHz clock for 100 Mbps operation and a 2.5 MHz clock for 10 Mbps operation. MII requires 18 signals in total, which consumes a large number of GPIO pins.

RMII, the Reduced Media Independent Interface, cuts the pin count roughly in half by using a 2-bit wide data path running at 50 MHz. Both transmit and receive use the same 50 MHz reference clock, which can be provided by an external oscillator or by the PHY itself. RMII requires only 9 data and control signals, making it the preferred choice for microcontroller designs where GPIO is limited.

On STM32F4 and STM32F7 devices, RMII is the standard configuration. The 50 MHz reference clock is typically supplied by an external crystal oscillator to the PHY, which then distributes it to the MAC.

Fig 1. Signal path from STM32 MAC to RJ45: RMII interface, PHY chip, transformer, and connector.

2.5 Auto-Negotiation and Link Detection

Auto-negotiation is the process by which two Ethernet devices agree on the best common operating mode: speed (10, 100, or 1000 Mbps) and duplex (half or full). It is defined in IEEE 802.3 and operates at the physical layer before any data is exchanged.

During auto-negotiation, each device transmits Fast Link Pulses encoding its capabilities. The remote device reads these pulses and selects the highest common capability. If auto-negotiation is disabled or fails, the device falls back to a default mode, typically 10 Mbps half duplex.

In embedded firmware, the PHY handles auto-negotiation autonomously once enabled. The firmware monitors the link state by reading PHY registers over the MDIO bus, waiting for the link to come up before enabling the MAC transmitter and receiver.


Struggling to implement this for a professional project? If you need to master full-scale firmware architecture, security, and build automation, join our 1-D or 4-Day Live Implemnetation Workshops. I'll show you the exact direct path to production-ready firmware without the trial and error.

3. The MDIO Bus: Configuring and Monitoring the PHY

3.1 What MDIO Is and Why It Exists

The PHY chip has internal registers that control its operating mode, report link status, configure auto-negotiation, and expose diagnostic information. To read and write these registers, the MAC uses a dedicated two-wire serial bus called MDIO, the Management Data Input/Output bus, also known as the Station Management Interface (SMI).

MDIO uses two signals: MDC, the clock driven by the MAC, and MDIO, the bidirectional data line. The MAC is always the bus master. Up to 32 PHY devices can share the same MDIO bus, each addressed by a 5-bit PHY address configured via hardware pins on the PHY.

3.2 MDIO Frame Format

Every MDIO transaction follows a defined frame format transmitted serially on the MDIO line. A read transaction and a write transaction share the same structure with minor differences.

The frame consists of the following fields in order: a 32-bit preamble of all ones, a 2-bit start delimiter (01), a 2-bit operation code (10 for read, 01 for write), a 5-bit PHY address, a 5-bit register address, a 2-bit turnaround, and 16 bits of data.

The preamble synchronizes the PHY and ensures it is ready to receive a transaction. The turnaround field gives the bus time to change direction before the data phase. On a read transaction, the PHY drives the data field. On a write transaction, the MAC drives the data field.

Fig 2. MDIO frame format

3.3 Reading and Writing PHY Registers from the MAC

On STM32 devices, the Ethernet MAC peripheral includes a built-in MDIO controller. Performing a PHY register access requires writing to the MAC MIIAR register to specify the PHY address, register address, and operation type, then waiting for the busy bit to clear.

A typical PHY register read and write in C looks like this:

#define ETH_MIIAR_PA_SHIFT 11U

#define ETH_MIIAR_MR_SHIFT 6U

#define ETH_MIIAR_CR_SHIFT 2U

#define ETH_MIIAR_MW_BIT (1U << 1)

#define ETH_MIIAR_MB_BIT (1U << 0)



uint16_t mdio_read(uint8_t phy_addr, uint8_t reg_addr)

{

/* set PHY address, register address, clock divider, read operation */

ETH->MACMIIAR = ((uint32_t)phy_addr << ETH_MIIAR_PA_SHIFT) |

((uint32_t)reg_addr << ETH_MIIAR_MR_SHIFT) |

(4U << ETH_MIIAR_CR_SHIFT) |

ETH_MIIAR_MB_BIT;



/* wait for busy bit to clear */

while (ETH->MACMIIAR & ETH_MIIAR_MB_BIT);



return (uint16_t)(ETH->MACMIIDR & 0xFFFFU);

}



void mdio_write(uint8_t phy_addr, uint8_t reg_addr, uint16_t value)

{

ETH->MACMIIDR = value;



ETH->MACMIIAR = ((uint32_t)phy_addr << ETH_MIIAR_PA_SHIFT) |

((uint32_t)reg_addr << ETH_MIIAR_MR_SHIFT) |

(4U << ETH_MIIAR_CR_SHIFT) |

ETH_MIIAR_MW_BIT |

ETH_MIIAR_MB_BIT;



while (ETH->MACMIIAR & ETH_MIIAR_MB_BIT);

}

The clock divider value (4U in the example above) must be chosen based on the HCLK frequency. Consult the STM32 reference manual for the correct divider for your target clock speed.

3.4 Key PHY Registers: Basic Control, Basic Status, Link State

IEEE 802.3 mandates a set of standard registers that every compliant PHY must implement. The two most important for firmware are register 0 and register 1.

Register 0, the Basic Control Register (BCR), controls the PHY operating mode. The key bits are: bit 15 to trigger a software reset, bit 12 to enable auto-negotiation, bit 9 to restart auto-negotiation, bit 8 to enable loopback mode, and bit 13 combined with bit 6 to set the speed manually if auto-negotiation is disabled.

Register 1, the Basic Status Register (BSR), reports the current PHY state. The key bits are: bit 2 to indicate link up or down, and bit 5 to indicate that auto-negotiation is complete. Firmware polls these bits after reset to wait for the link to come up before enabling the MAC.

#define PHY_BCR_REG 0x00U

#define PHY_BSR_REG 0x01U

#define PHY_BCR_RESET (1U << 15)

#define PHY_BCR_AUTONEG_EN (1U << 12)

#define PHY_BCR_AUTONEG_RST (1U << 9)

#define PHY_BSR_LINK_UP (1U << 2)

#define PHY_BSR_AUTONEG_DONE (1U << 5)



uint8_t phy_wait_link_up(uint8_t phy_addr)

{

uint32_t timeout = 5000U;

while (timeout--)

{

uint16_t bsr = mdio_read(phy_addr, PHY_BSR_REG);

if ((bsr & PHY_BSR_LINK_UP) && (bsr & PHY_BSR_AUTONEG_DONE))

return 1;

}

return 0;

}


4. The MAC Layer: Framing and Addressing

4.1 MAC Addresses

Every Ethernet interface is identified by a 48-bit MAC address, also called a hardware address or physical address. The address is split into two halves: the upper 24 bits identify the manufacturer (the OUI, Organizationally Unique Identifier) and the lower 24 bits are assigned by the manufacturer to uniquely identify the device.

Two bits in the first byte have special meaning. Bit 0 is the multicast bit. When set, the frame is addressed to a group of devices rather than a single one. Bit 1 is the locally administered bit. When set, the address has been assigned locally rather than by the manufacturer.

The broadcast address, FF:FF:FF:FF:FF:FF, is a special multicast address that every Ethernet device must accept.

4.2 Ethernet Frame Structure

An Ethernet frame is the unit of data exchanged at the MAC layer. Every frame transmitted on the wire follows a fixed structure:

Preamble (7 bytes): A sequence of alternating 1s and 0s (0x55 repeated) that allows the receiver to synchronize its clock to the incoming signal.

Start Frame Delimiter, SFD (1 byte): The value 0xD5, which signals the end of the preamble and the start of the frame data.

Destination MAC Address (6 bytes): The MAC address of the intended recipient.

Source MAC Address (6 bytes): The MAC address of the sender.

EtherType / Length (2 bytes): Values above 0x05DC indicate the protocol type of the payload: 0x0800 for IPv4, 0x0806 for ARP, 0x86DD for IPv6. Values of 0x05DC or below indicate the payload length in IEEE 802.3 format.

Payload (46 to 1500 bytes): The data being carried. The minimum payload of 46 bytes ensures the frame is long enough for collision detection on half duplex links. If the actual data is shorter, the frame is padded to 46 bytes.

Frame Check Sequence, FCS (4 bytes): A CRC32 computed over the destination address, source address, EtherType, and payload. The receiver recomputes the CRC and discards the frame if it does not match.

Fig 3. Ethernet frame structure from preamble to FCS.

The preamble and SFD are added and stripped by the PHY and are not visible to the MAC or to software. The MAC sees frames starting from the destination address.

4.3 Frame Transmission and Reception Flow

On transmission, the software places the frame data starting from the destination MAC address into a buffer and instructs the MAC to transmit it. The MAC reads the buffer, computes and appends the FCS, prepends the preamble and SFD, and passes the resulting bit stream to the PHY for transmission on the wire.

On reception, the PHY detects the preamble, synchronizes, and passes the decoded bits to the MAC. The MAC strips the preamble and SFD, checks the FCS, and if valid, stores the frame from destination address to the last byte of payload without the FCS in a receive buffer. Software then reads the frame from the buffer.


5. How Data Moves: DMA Descriptors and Buffers

5.1 Why DMA Is Needed

Copying Ethernet frames to and from memory using the CPU would consume significant processing time, especially at 100 Mbps where a maximum size frame arrives every 120 microseconds. DMA, Direct Memory Access, allows the Ethernet MAC to read and write frame data in memory autonomously without CPU involvement.

The CPU sets up a set of descriptor structures in RAM that tell the DMA where the frame buffers are, how large they are, and which ones are ready for use. The DMA hardware processes these descriptors and transfers data directly between the buffers and the MAC FIFO.

5.2 Descriptor Ring Structure

The STM32 Ethernet DMA uses a ring of descriptor structures in RAM. Each descriptor describes one frame buffer and carries status and control bits that coordinate ownership between the CPU and the DMA.

A simplified descriptor structure looks like this:

typedef struct

{

volatile uint32_t status; /* owned by DMA when bit 31 is set */

volatile uint32_t ctrl; /* buffer size and control flags */

volatile uint32_t buf1_addr; /* address of frame buffer */

volatile uint32_t buf2_addr; /* address of next descriptor */

} eth_dma_desc_t;

The ownership bit in the status field is the key synchronization mechanism. When bit 31 is set, the descriptor belongs to the DMA and the CPU must not touch the buffer. When bit 31 is clear, the descriptor belongs to the CPU and the DMA will not access the buffer.

5.3 TX and RX Flow

On the transmit path, the CPU fills a buffer with the frame to send, sets the buffer address and size in the descriptor, sets any required control flags, and then sets the ownership bit to hand the descriptor to the DMA. The CPU then writes to the transmit poll demand register to wake the DMA if it is suspended. The DMA reads the descriptor, transmits the frame, and clears the ownership bit when done.

On the receive path, the CPU populates the descriptor ring at startup with empty buffers and sets the ownership bit on each descriptor to give them to the DMA. When a frame arrives, the DMA finds the next owned descriptor, writes the received frame into the buffer, updates the status field with frame length and status information, and clears the ownership bit. The CPU polls or waits for interrupt notification, then reads the ownership bit to detect completed receptions.

Fig 4. DMA descriptor ring showing ownership handoff between CPU and DMA.


6. The Protocol Stack Above Ethernet

6.1 Where Ethernet Fits in the Stack

Ethernet operates at the two lowest layers of the network stack. The physical layer, Layer 1, covers signal encoding, the cable, the transformer, and the PHY. The data link layer, Layer 2, covers MAC addressing, frame structure, and the FCS. Everything above that is the responsibility of higher layer protocols running in software.

The EtherType field in the frame header is what connects Ethernet to the layers above it. When a frame arrives, software inspects the EtherType to decide which protocol handler should process the payload.

6.2 ARP, IP, UDP, and TCP as Upper Layers

Above Ethernet, the most common protocols in embedded systems are ARP, IPv4, UDP, and TCP.

ARP, the Address Resolution Protocol (EtherType 0x0806), maps IPv4 addresses to MAC addresses. Before sending an IP packet to another device, the sender must know that device's MAC address. ARP broadcasts a request asking who has a given IP address, and the owner replies with its MAC address.

IPv4 (EtherType 0x0800) is the network layer protocol that handles addressing and routing between devices on different networks. Every IP packet carries a source and destination IP address and a protocol field that identifies whether the payload is UDP, TCP, ICMP, or another protocol.

UDP is a lightweight, connectionless transport protocol built on top of IP. It adds source and destination port numbers and a checksum, but provides no delivery guarantees. It is the right choice for low-latency embedded applications where a dropped packet is acceptable.

TCP adds reliable, ordered, connection-oriented delivery on top of IP. It is more complex to implement but necessary for applications that cannot tolerate data loss, such as file transfers or configuration interfaces.


7. Conclusion

Ethernet hardware is built from several layers that work together to move data reliably from one device to another. The PHY handles signal encoding and transmission at the wire level, the magnetics provide isolation and noise rejection, the MDIO bus gives the MAC control over the PHY configuration and link state, the MAC adds addressing and framing, and the DMA descriptor ring moves frame data between the MAC and system memory without CPU involvement.

With this foundation in place, the next article moves to implementation: configuring the STM32 Ethernet MAC directly from registers, setting up the DMA descriptor rings, and sending and receiving raw Ethernet frames in C without any HAL or middleware.


Want to master this? Here are your next steps:



Created with