embassy-rs/embassy · critical

ErevidIsZero

Error message

ErevidIsZero

What it means

During enc28j60::Device::init, after the clock-ready (CLKRDY) wait, the driver reads the EREVID register (silicon revision ID, bank 3) and panics if it reads 0. EREVID == 0 means the SPI read did not return a valid revision ID, which indicates the chip is not responding correctly (wiring/SPI issues, a fake/counterfeit module, or unsupported silicon). The library treats this as an unrecoverable hardware sanity check.

Solutions

  1. Verify SPI wiring (CS, SCK, MISO, MOSI), SPI mode 0, and a stable 3.3 V supply; scope/check MISO during the EREVID read.
  2. Test basic SPI communication first (e.g. read ECON1 and write/read back) before init to isolate bus problems.
  3. If using a cheap module, check for counterfeit ENC28J60 silicon — many clones report EREVID 0; consider a fallback that logs and continues.
  4. Patch the driver to warn instead of panic (replace panic!("ErevidIsZero") with a logged warning) if your hardware tolerates revision 0.

Example fix

// before (driver)
if self.read_control_register(bank3::Register::EREVID) == 0 {
    panic!("ErevidIsZero");
}
// after (driver)
let erevid = self.read_control_register(bank3::Register::EREVID);
if erevid == 0 {
    defmt::warn!("enc28j60: EREVID is 0 (counterfeit or SPI issue?), continuing");
}
// caller-side guard: verify SPI echo before init
// let econ1 = dev.read_control_register(common::Register::ECON1);
// assert!(econ1 == expected, "SPI bus not responding correctly");
Defensive patterns

Strategy: validation

Validate before calling

// Rust: verify SPI bus responds before calling init
fn spi_bus_alive<D>(dev: &mut D) -> bool
where D: read_control_register(...)
{
    // write a known pattern to ECON1 and read it back
    let probe = dev.read_control_register(common::Register::ECON1);
    probe != 0xFF && probe != 0x00 // all-0xFF/all-0x00 usually means no chip / floating bus
}

Type guard

// Rust: guard the EREVID read yourself before driver init
fn erevid_valid(dev: &mut Device<Spi>) -> bool {
    dev.read_control_register(bank3::Register::EREVID) != 0
}

Try / catch

// Rust panics cannot be caught in embedded; gate init instead:
if !spi_bus_alive(&mut dev) {
    defmt::error!("enc28j60: SPI bus not responding; check wiring/power");
    return Err(InitError::Bus);
}
dev.init(mac_addr); // safe once bus sanity-checked

Prevention

When it happens

Trigger: Calling enc28j60::Device::init when EREVID reads back 0: missing/incorrect SPI mode (must be mode 0), wrong CS pin or miswired MISO/MOSI, insufficient power, counterfeit ENC28J60 modules returning 0, or reading bank-3 register EREVID before the SPI interface is functional.

Common situations: Breadboard wiring with long/unstable SPI traces; power supply below 3.14 V; cheap clone modules where EREVID legitimately reads 0; forgetting to set the correct bank before reading EREVID in a modified driver; using a partially broken SPI bus where other reads appear to work.

Related errors


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

Appendix: source

Thrown at embassy-net-enc28j60/src/lib.rs:102

            embassy_time::block_for(Duration::from_millis(5));
            rst.set_high().unwrap();
            embassy_time::block_for(Duration::from_millis(5));
        } else {
            embassy_time::block_for(Duration::from_millis(5));
            self.soft_reset();
            embassy_time::block_for(Duration::from_millis(5));
        }

        debug!(
            "enc28j60: erevid {=u8:x}",
            self.read_control_register(bank3::Register::EREVID)
        );
        debug!("enc28j60: waiting for clk");
        while common::ESTAT(self.read_control_register(common::Register::ESTAT)).clkrdy() == 0 {}
        debug!("enc28j60: clk ok");

        if self.read_control_register(bank3::Register::EREVID) == 0 {
            panic!("ErevidIsZero");
        }

        // disable CLKOUT output
        self.write_control_register(bank3::Register::ECOCON, 0);

        self.init_rx();

        // TX start
        // "It is recommended that an even address be used for ETXST"
        debug_assert_eq!(TXST % 2, 0);
        self.write_control_register(bank0::Register::ETXSTL, TXST.low());
        self.write_control_register(bank0::Register::ETXSTH, TXST.high());

        // TX end is set in `transmit`

        // MAC initialization (see section 6.5)
        // 1. Set the MARXEN bit in MACON1 to enable the MAC to receive frames.
        self.write_control_register(

View on GitHub (pinned to 463a07b963)