skywalker-1/docs/EEPROM-RECOVERY.md
Ryan Malloy 3d2cd477b2 Add EEPROM boot firmware (exp 0xDB) and supporting tools
Firmware: Rewrite skywalker1.c for EEPROM boot experiment — tests
whether I2C hardware controller works after FX2 boot ROM completes
EEPROM load (bypassing the CPUCS restart that triggers BERR).

Tools:
- fw_load.py: Add I2C cleanup stub, pre-halt register flush, improved
  error handling and segment loading
- eeprom_write.py: Add IHX→C2 EEPROM image converter (16KB format
  with length-prefixed segments, checksum)
- eeprom_dump.py: Refactor for cleaner output, better hex display
- skywalker_lib.py: Minor I2C register constant updates

Docs:
- EEPROM-RECOVERY.md: Four recovery options for soft-bricked device
  (SOIC clip, SDA pull-up, desolder, wait-for-timeout)
- Master reference: Updated with EEPROM boot findings

Status: EEPROM flash blocked — stock firmware I2C proxy returns pipe
errors, host-side 0xA0 writes proven unable to drive peripheral bus.
Device boot ROM intermittently hangs on EEPROM I2C read (~3-6% success).
2026-02-20 10:56:21 -07:00

4.4 KiB

SkyWalker-1 EEPROM Recovery Guide

The device is soft-bricked: the FX2 boot ROM hangs trying to load corrupted firmware from EEPROM, preventing USB enumeration.

Symptoms

  • Hub shows 0101 power connect [] (D+ pull-up active, no enumeration)
  • dmesg: device descriptor read/8, error -110 (timeout)
  • Does not enumerate as bare FX2 (04B4:8613) either
  • NanoVNA on same hub works fine (hub hardware is OK)

Root Cause

The EEPROM (24C128 at I2C 0x51) likely has corrupted boot data. The FX2LP boot ROM reads the EEPROM at power-up and hangs if the C2 image has invalid load record lengths or addresses. The boot ROM occupies the 8051 core, preventing USB control transfer processing.

Recovery Options (pick one)

Blank the first byte of the EEPROM so the boot ROM falls back to bare FX2 enumeration. Then reload via USB.

Hardware needed:

  • SOIC-8 test clip (Pomona 5250 or similar, ~$5)
  • CH341A USB programmer (~$3) or Bus Pirate or any I2C-capable tool
  • OR: Raspberry Pi / Arduino with I2C

Steps:

  1. Power OFF the SkyWalker-1 (unplug USB)
  2. Locate the 24C128 EEPROM on the PCB (SOIC-8 package near the FX2)
  3. Clip the SOIC clip onto the EEPROM
  4. Connect to your I2C programmer (SDA, SCL, VCC, GND)
  5. Read and save the EEPROM contents (16KB backup!)
  6. Write 0xFF to address 0x0000 (corrupts the C2 magic byte)
  7. Remove clip, plug in SkyWalker-1
  8. Device should enumerate as bare FX2 (04B4:8613)
  9. Load custom firmware via fw_load.py
  10. Use the custom firmware to write good C2 image back to EEPROM

With CH341A:

# Read backup
flashrom -p ch341a_spi -c "AT24C128" -r eeprom_backup.bin

# Or use i2c-tools if CH341A is in I2C mode:
# i2cdetect -l  (find the CH341A bus)
# i2cdump -y <bus> 0x51 b > dump.txt

With Raspberry Pi (I2C):

# Enable I2C: raspi-config -> Interfaces -> I2C
# Connect EEPROM: SDA->GPIO2, SCL->GPIO3, VCC->3.3V, GND->GND
i2cdetect -y 1  # Should show 0x51
# Read first byte
i2cget -y 1 0x51 0x00
# Write 0xFF to byte 0 (corrupts C2 header)
i2cset -y 1 0x51 0x00 0xFF

Option B: Hold SDA HIGH During Boot

Prevent the EEPROM from responding by holding SDA HIGH, forcing the boot ROM to see "no EEPROM" and enumerate as bare FX2.

Steps:

  1. Locate the SDA test point or EEPROM pin 5 (SDA)
  2. Connect a 1kΩ pull-up to 3.3V on SDA
  3. Power on the SkyWalker-1
  4. If it enumerates as bare FX2 (04B4:8613), load firmware:
    python3 tools/fw_load.py load firmware/build/skywalker1.ihx
    
  5. Remove the pull-up
  6. Use the loaded firmware to reprogram the EEPROM

Note: This only works if the SDA pull-up is strong enough to override the EEPROM's SDA output. May need to experiment with pull-up values (470Ω to 4.7kΩ).

Option C: Desolder EEPROM Pin

Most reliable but requires soldering skill.

  1. Lift EEPROM pin 5 (SDA) from the PCB pad
  2. Power on → enumerates as bare FX2
  3. Load firmware via USB
  4. Resolder pin 5
  5. Use firmware to reprogram EEPROM with good C2 image

Option D: Wait + Watch (Long Shot)

If the boot ROM eventually times out on the I2C read, the device will briefly enumerate as bare FX2. This might take several minutes.

# Watch for bare FX2 enumeration
sudo dmesg -w | grep -E "04b4|8613|New USB"

# In another terminal, keep power cycling every 5 minutes
while true; do
    sudo uhubctl -l 1-5.4.4 -p 3 -a off
    sleep 5
    sudo uhubctl -l 1-5.4.4 -p 3 -a on
    sleep 300  # wait 5 minutes
done

If it appears even briefly:

python3 tools/fw_load.py load firmware/build/skywalker1.ihx --force

After Recovery

Once the device enumerates (as bare FX2 or with loaded firmware):

  1. Load custom firmware to RAM:

    python3 tools/fw_load.py load firmware/build/skywalker1.ihx
    
  2. Reprogram EEPROM with good C2 image:

    # The custom firmware needs EEPROM write support first
    # (vendor command to relay I2C writes to EEPROM)
    python3 tools/eeprom_write.py flash firmware/build/skywalker1_eeprom.bin
    
  3. Or restore stock firmware: If you have a backup of the original EEPROM contents, flash that instead of the custom firmware.

Prevention

  • Never send BOOT_8PSK (0x89) with mode 0x84 ("firmware load") unless you know what data the firmware expects
  • Always backup EEPROM before experiments that touch vendor commands
  • The stock firmware's I2C proxy (0x83/0x84) may have side effects on the EEPROM that aren't documented