embassy-rs/embassy · error

PHY did not respond

Error message

PHY did not respond

What it means

After issuing an SMI read, the driver waits up to 100 ms for the PHY to respond; if no answer appears it panics. This means the Ethernet PHY is not answering MDIO transactions at the given PHY address.

Solutions

  1. Verify the PHY address from strap pins/schematic and pass the correct value to the PHY constructor.
  2. Check PHY power, reset line, and reference clock at board level.
  3. Confirm MDC/MDIO pin configuration in the embassy-stm32 pins! macro.
  4. Probe the MDIO bus with a logic analyzer; fix/replace silent PHY hardware.

Example fix

// before
let phy = EmbassyEthernetPhy::new(dev, 0); // assumed addr 0
// after
let phy = EmbassyEthernetPhy::new(dev, 1); // actual address from strap pins
Defensive patterns

Strategy: validation

Validate before calling

let phy_addr = read_phy_addr_straps();
assert!(phy_addr <= 31, "invalid PHY address: {}", phy_addr);

Prevention

When it happens

Trigger: Ethinic/generic PHY init calling phy_reset() when no PHY acknowledges on MDIO within 100 ms — wrong phy address, missing/powered-down PHY, or MDIO/MDC wiring issue.

Common situations: Custom boards where the PHY strap address differs from the assumed default; missing 25 MHz PHY crystal or RMII 50 MHz ref clock; MDC/MDIO pins misconfigured.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/42420ed31f3cd8bd. Report an issue: GitHub.

Appendix: source

Thrown at embassy-stm32/src/eth/generic_phy.rs:111

}

impl<SM: StationManagement> Phy for GenericPhy<SM> {
    fn phy_reset(&mut self) {
        // Detect SMI address
        if self.phy_addr == 0xFF {
            for addr in 0..32 {
                self.sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
                for _ in 0..10 {
                    if self.sm.smi_read(addr, PHY_REG_BCR) & PHY_REG_BCR_RESET != PHY_REG_BCR_RESET {
                        trace!("Found ETH PHY on address {}", addr);
                        self.phy_addr = addr;
                        return;
                    }
                    // Give PHY a total of 100ms to respond
                    block_for_us(10000);
                }
            }
            panic!("PHY did not respond");
        }

        self.sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
        while self.sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
    }

    fn phy_init(&mut self) {
        // Clear WU CSR
        self.smi_write_ext(PHY_REG_WUCSR, 0);

        #[cfg(eth_v2a)]
        {
            // The v2a MAC is fixed at 100M full duplex; advertise only that.
            let antx = self.sm.smi_read(self.phy_addr, PHY_REG_ANTX);
            let antx = (antx & !PHY_REG_ANTX_TECH) | PHY_REG_ANTX_100BTX_FD;
            self.sm.smi_write(self.phy_addr, PHY_REG_ANTX, antx);
            self.sm.smi_write(self.phy_addr, PHY_REG_GBCR, 0);
        }

View on GitHub (pinned to 463a07b963)