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).
145 lines
4.4 KiB
Markdown
145 lines
4.4 KiB
Markdown
# 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)
|
|
|
|
### Option A: SOIC Clip + External Programmer (Recommended)
|
|
|
|
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:**
|
|
```bash
|
|
# 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):**
|
|
```bash
|
|
# 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:
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
# 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:
|
|
```bash
|
|
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:**
|
|
```bash
|
|
python3 tools/fw_load.py load firmware/build/skywalker1.ihx
|
|
```
|
|
|
|
2. **Reprogram EEPROM with good C2 image:**
|
|
```bash
|
|
# 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
|