Recovering Bricked Walksnail Avatar X Goggles: QSPI Flash, U-Boot and Raspberry Pi Pico

Disassembled Walksnail Avatar X goggles with Raspberry Pi Pico programmer wiring connected to the mainboard

I recovered a Walksnail Avatar Goggles X after an incompatible firmware image and a forced DDR change replaced low-level boot components. The SoC ROM still executed, but the resulting SPL could no longer initialise the on-board QSPI flash. This repair used direct in-circuit access to the Winbond W25Q01JV with a Raspberry Pi Pico running pico-serprog, then restored only enough of the boot chain for the official Avatar X updater to finish the job.

This is a repair log, failure analysis and reproducible recovery guide for the specific hardware and firmware I investigated. Verify every offset and binary against your own board revision before writing anything.

Warning: direct flash access can destroy the board

  • This procedure can permanently brick or electrically damage the goggles.
  • The flash uses 3.3 V logic. Never apply 5 V to it.
  • Disconnect the goggles’ normal battery/input power while directly powering the flash rail.
  • Power the Pico independently over USB and connect Pico ground to target ground.
  • Do not connect the Pico 3V3 pin to the target when using the external 3.3 V supply.
  • The shared target 3.3 V rail can power other circuitry, not only the flash.
  • Use short wires, start at a conservative SPI clock and verify repeated reads by hash before writing.
  • Restrict every write to an explicit flashrom layout region whenever possible.
  • Never perform a chip erase for this recovery. Make backups before modifying anything.

How the goggles were bricked

The goggles worked normally before the incident. I accidentally flashed firmware intended for another hardware configuration and forced the DDR change. The broken SPL identified itself as:

U-Boot SPL 2017.07Arto (Apr 18 2026 - 10:54:14)

It configured DDR4 at 2133 MHz with a 32-bit bus. The correct Avatar X configuration is DDR4 at 2400 MHz, also 32-bit. The first failure was:

Trying to boot from emmc_and_qspi
Read flash ID: 2140ef
QSPI: unrecognized JEDEC id: ...
probe spi device failed!
SPL: failed to boot from all boot devices

This was an important diagnostic clue: the SoC ROM executed and DDR initialised, but the low-level boot firmware could no longer initialise the QSPI flash correctly. The repair therefore had to begin below Linux and below the normal firmware updater.

The flash device

The mainboard uses a Winbond W25Q01JV / W25Q01JVIQ: a 128 MiB, 3.3 V SPI NOR device in a WSON-8 package. Its JEDEC ID is EF 40 21. flashrom 1.8.0 reports:

Close-up of the Winbond W25Q01JV QSPI flash on the Walksnail Avatar X mainboard
Winbond W25Q01JV 128 MiB QSPI NOR flash on the Walksnail Avatar X mainboard.
Found Winbond flash chip "W25Q01JV" (131072 kB, SPI) on serprog.
PinSignalFunction
1/CSChip select
2DO / IO1 / MISOData output
3WP# / IO2Write protect / quad I/O
4GNDGround
5DI / IO0 / MOSIData input
6CLKSPI clock
7HOLD# / RESET# / IO3Hold/reset / quad I/O
8VCC 3.3 VSupply

This table is a top-view pinout. The package dot or mark identifies pin 1.

Pico-serprog wiring

I used a Raspberry Pi Pico running opensensor/pico-serprog. The following table records the actual wiring. WP# and HOLD#/RESET# were already pulled high on the target board and were not driven by the Pico during normal programming.

Disassembled Walksnail Avatar X goggles with Raspberry Pi Pico programmer wiring connected to the mainboard
Avatar X disassembled for in-circuit QSPI access using Raspberry Pi Pico and pico-serprog.
Flash pinSignalPico GPIOSeries resistorNotes
1/CSGP5~1 kΩChip select
2MISOGP4~1 kΩFlash to Pico
5MOSIGP3~1 kΩPico to flash
6CLKGP2~1 kΩSPI clock
4GNDGNDNoneCommon ground

The approximately 1 kΩ series resistors in the SPI signal lines help limit contention with circuitry that remains connected to the shared bus. They add a useful margin of safety during in-circuit experiments, although they do not replace careful power and signal-integrity checks.

Powering the flash rail

The Pico must not power the target from its 3V3 output. I powered the Pico independently over USB and used a laboratory bench supply set to 3.3 V for the target flash/3.3 V rail. Pico 3V3 was left disconnected, the grounds were joined, and normal goggles battery/input power was disconnected.

The in-circuit rail drew approximately 113 mA. That is far more than a bare idle flash device and showed that the supply was back-powering part of the goggles electronics. Anyone repeating this work must treat the connection as power to a shared board rail, not power to an isolated memory chip.

Top rear view of Walksnail Avatar X goggles showing an accessible UART debug connector
UART debug connection brought out to an accessible connector for future diagnostics.

This photograph shows the permanent UART/serial debug lead, not the SPI programmer connection.

Host software and reliable SPI speed

The host was Windows with MSYS2 UCRT64, flashrom 1.8.0, and the Pico running opensensor/pico-serprog. My initial conservative command was:

flashrom 1.8 terminal output detecting a Winbond W25Q01JV through pico-serprog
flashrom 1.8 detecting the W25Q01JV through pico-serprog.
./builddir/flashrom.exe \
  -p serprog:dev=COM13:115200,spispeed=1M \
  -c W25Q01JV

Although the programmer appears as a serial COM port, pico-serprog uses USB CDC. The 115200 parameter is therefore not the actual limiting UART speed. I began programming at 1 MHz. Later, 8 MHz was stable for full-flash reads; at 16 MHz the flash was no longer detected reliably with my in-circuit wiring. The practical ceiling depends heavily on wire length, board loading and signal integrity.

Stage 1: recover only the boot region

The first repair targeted only 0x000000-0x10FFFF, a total of 0x110000 bytes (1,114,112 bytes). It contains:

RangeComponentSize
0x000000-0x00FFFFROM code64 KiB
0x010000-0x08FFFFSPL0512 KiB
0x090000-0x10FFFFSPL1512 KiB

I built a recovery image from a known-correct Avatar X firmware and described the permitted write range in boot.layout:

00000000:0010ffff boot

The write command was:

./builddir/flashrom.exe \
  -p serprog:dev=COM13:115200,spispeed=1M \
  -c W25Q01JV \
  -N \
  -V -o recovery-write.log \
  -w \
  -l boot.layout \
  -i boot:AvatarX_boot_recovery_0x110000.bin

flashrom completed with VERIFIED. On the next boot the SPL was the correct build:

U-Boot SPL 2017.07Arto (Jan 23 2025 - 17:10:02)

DDR init:
type 4
freq 2400
width 32

Read flash ID: 2140ef
Name: w25q01jviq
spi nor flash init success

This restored DDR and QSPI initialisation, but it did not yet recover the goggles.

Stage 2: find the incompatible full U-Boot

The repaired SPL successfully loaded the second-stage bootloader, but the active full U-Boot was still the incompatible build:

U-Boot 2017.07Arto (Apr 18 2026 - 10:54:14 +0800)

It again failed to initialise the W25Q01JV. Reading both physical U-Boot slots showed:

SlotPhysical rangeResult
uboot00x740000-0x7BFFFFCorrect 10:48:27 build; contained w25q01jviq support
uboot10x7C0000-0x83FFFFActive incompatible 10:54:14 build

I copied the good uboot0 image to uboot1. The next log showed:

U-Boot 2017.07Arto (Apr 18 2026 - 10:48:27 +0800)

Read flash ID: 2140ef
Name: w25q01jviq

The system could now continue into the Linux kernel.

Stage 3: let the official updater repair the mixed state

Linux and GlassesUI booted, but the displays remained black and the LEDs did not work. The log also contained hardware/configuration-related messages, including missing GPIO and PWM resources. This showed that the flash still held a mixture of partitions from the incompatible firmware and the correct Avatar X firmware.

Once the correct U-Boot could access QSPI normally, I inserted a USB drive containing the official Avatar X firmware 39.44.18 and allowed the built-in updater to complete the remaining partition updates. After the official update, the displays, LEDs and GUI all worked, and the firmware reported version 39.44.18.

The distinction matters: the manual procedure restored only enough of the boot chain for the official updater to work again. It was the complete official update that restored the remaining hardware-specific software state.

Physical layout of the working 128 MiB flash

Bottom side of the Walksnail Avatar X mainboard
Avatar X mainboard, bottom side.
OffsetSizeSize (human)Partition
0x0000000x01000064 KiBromcode
0x0100000x080000512 KiBspl0
0x0900000x080000512 KiBspl1
0x1100000x01000064 KiBgpt
0x1200000x2000002 MiBfactory
0x3200000x3800003.5 MiBlogo
0x6A00000x01000064 KiBenv0
0x6B00000x01000064 KiBenv1
0x6C00000x040000256 KiBoptee0
0x7000000x040000256 KiBoptee1
0x7400000x080000512 KiBuboot0
0x7C00000x080000512 KiBuboot1
0x8400000x8000008 MiBkernel
0x10400000x01000064 KiBdtb0
0x10500000x01000064 KiBdtb1
0x10600000xD0000013 MiBuserapp0
0x1D600000xD0000013 MiBuserapp1
0x2A600000xF0000015 MiBuiapp
0x39600000x6000006 MiBa7_rtos

The partitioned area ends at 0x03F60000. The remainder of the 128 MiB chip was 0xFF in the captured working dump.

Create a full working backup

After the goggles were fully working, I read a complete 128 MiB “golden” dump at the stable 8 MHz SPI speed:

./builddir/flashrom.exe \
  -p serprog:dev=COM13:115200,spispeed=8M \
  -c W25Q01JV \
  -V -o full-read.log \
  -r AvatarX_full_working_39.44.18-flash_dump.bin

The expected file size is 134217728 bytes. The SHA-256 of my working dump is:

e591ff3f944529d2c8adea1b9ea04e32d5e398314b2f61684bd7da74a80ff2a7

This hash identifies the dump from my device. It is not a universal firmware hash, and the dump is intentionally not offered for download.

Why a raw dump is not the official upgrade image

The official .img file is an update package. It contains an OTRA header, hashes, an RSA signature, partition or segment metadata, compressed payloads and instructions that control updater behaviour.

A raw 128 MiB read is the actual state of one physical pair of goggles: boot firmware, GPT, factory data, current environment, both A/B slots, filesystem state, runtime-modified files, device-specific information and unused flash space. It therefore contains data that is not present in the updater image.

In particular, the factory partition may hold calibration data, hardware configuration, MAC or device identifiers, and serial or other unit-specific values. Readers should create and protect their own dump rather than copying one from another device.

Recovery sequence

  1. The wrong firmware replaced low-level boot components.
  2. The SoC ROM still ran, but the broken SPL could not access QSPI correctly.
  3. I established direct access to the W25Q01JV with a Raspberry Pi Pico and pico-serprog.
  4. I recovered the restricted low-level boot region.
  5. A second incompatible U-Boot was then found in the active A/B slot.
  6. I replaced the active U-Boot with the known-good version.
  7. The goggles booted far enough for the official 39.44.18 updater to run.
  8. The official update restored the remaining hardware-specific partitions and functions.
  9. I saved a complete 128 MiB working flash dump for future analysis.

The exact offsets and recovery binaries are specific to the hardware and firmware examined here. Confirm the flash identity, board revision, slot contents and every layout boundary before applying this procedure to another revision.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.