From 61e1a2a1c6427be6594d31939c4f37fb42c42d15 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 13 Apr 2021 12:28:05 +0200 Subject: [PATCH] Correcting I2C MAC address read --- src/hardware/configuration.rs | 11 ++++------ src/hardware/eeprom.rs | 40 ++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/hardware/configuration.rs b/src/hardware/configuration.rs index dfab1e0..0351db9 100644 --- a/src/hardware/configuration.rs +++ b/src/hardware/configuration.rs @@ -495,13 +495,10 @@ pub fn setup( .set_speed(hal::gpio::Speed::VeryHigh); } - let mac_addr = match eeprom::read_eui48(&mut eeprom_i2c) { - Err(_) => { - info!("Could not read EEPROM, using default MAC address"); - smoltcp::wire::EthernetAddress([0x10, 0xE2, 0xD5, 0x00, 0x03, 0x00]) - } - Ok(raw_mac) => smoltcp::wire::EthernetAddress(raw_mac), - }; + let mac_addr = smoltcp::wire::EthernetAddress(eeprom::read_eui48( + &mut eeprom_i2c, + &mut delay, + )); let network_devices = { // Configure the ethernet controller diff --git a/src/hardware/eeprom.rs b/src/hardware/eeprom.rs index d84dd70..b9b237c 100644 --- a/src/hardware/eeprom.rs +++ b/src/hardware/eeprom.rs @@ -1,12 +1,42 @@ -use embedded_hal::blocking::i2c::WriteRead; +use embedded_hal::blocking::{delay::DelayMs, i2c::WriteRead}; +// The EEPROM is a variant without address bits, so the 3 LSB of this word are "dont-cares". const I2C_ADDR: u8 = 0x50; -pub fn read_eui48(i2c: &mut T) -> Result<[u8; 6], T::Error> +// The MAC address is stored in the last 6 bytes of the 256 byte address space. +const MAC_POINTER: u8 = 0xFA; + +pub fn read_eui48(i2c: &mut T, delay: &mut impl DelayMs) -> [u8; 6] where T: WriteRead, { - let mut buffer = [0u8; 6]; - i2c.write_read(I2C_ADDR, &[0xFA_u8], &mut buffer)?; - Ok(buffer) + let mut previous_read: Option<[u8; 6]> = None; + // On Stabilizer v1.1 and earlier hardware, there is a fault where the I2C bus is not connected + // to the CPU until the P12V0A rail enables, which can take many seconds, or may never come up + // at all. During these transient turn-on conditions, we may fail the I2C read operation. To + // accomodate this, we repeat the I2C read for a set number of attempts with a fixed delay + // between them. Then, we wait for the bus to stabilize by waiting until the MAC address + // read-out is identical for two consecutive reads. + for _ in 0..40 { + let mut buffer = [0u8; 6]; + if i2c + .write_read(I2C_ADDR, &[MAC_POINTER], &mut buffer) + .is_ok() + { + if let Some(old_read) = previous_read { + if old_read == buffer { + return buffer; + } + } + + previous_read.replace(buffer); + } else { + // Remove any pending previous read if we failed the last attempt. + previous_read.take(); + } + + delay.delay_ms(100); + } + + panic!("Failed to read MAC address"); }