Nerd Family – ESP32-S3 PSRAM Not Detected
Warning — Should be addressed soon
Symptoms
- Boot banner at `115200 8N1` shows `E (xxx) esp_psram: PSRAM ID read error: 0xffffff` or similar `PSRAM ID read error` line
- Boot banner shows `E (xxx) esp_psram: PSRAM init failed` followed by `E (xxx) cpu_start: Failed to init external RAM!`
- Boot banner is missing the expected line `I (xxx) esp_psram: Found 8MB PSRAM device` (Octal) or `I (xxx) esp_psram: Found 4MB PSRAM device` (Quad) for the board's expected variant
- App panics `Guru Meditation Error: Core 0 panic'ed (StoreProhibited)` with `EXCVADDR` in the `0x3F8xxxxx` external-RAM range the first time the firmware allocates from PSRAM
- `heap_caps_get_total_size(MALLOC_CAP_SPIRAM)` returns `0` — no SPIRAM heap available to the app
- `idf.py monitor` shows `cache_err_intr` or `Cache disabled but cached memory region accessed` shortly after boot
- `esptool.py flash_id` reports a flash chip that does not match the documented `WROOM-1 N16R8` (16 MB Winbond `W25Q128` typical) — flash is wrong, module is wrong
- `esptool.py chip_id` reports `Chip is ESP32-S3 (revision X)` but `Features:` line does not include `Embedded PSRAM`
- After flashing custom or community firmware, PSRAM regressed from working to broken — `sdkconfig` was rebuilt with wrong PSRAM mode (OPI vs QPI mismatch)
- Module silkscreen markings are off-centre, blurry, partially legible, or differ subtly from documented Espressif markings — visual counterfeit indicator
- Random `LoadProhibited` panics intermittently, even on builds where boot banner says PSRAM init succeeded — marginal solder joint or dying PSRAM die
- `heap_caps_check_integrity_all(true)` fails with addresses in the SPIRAM range repeatedly across reboots
Step-by-Step Fix
Connect the Nerd / Bitaxe Hex via USB-C and capture the full boot banner at `115200 8N1` (use `idf.py monitor`, `pyserial`, or the Web Flasher's serial console). Save the entire block between `rst:0x1` and `app_main`. The exact PSRAM error string narrows the cause from five candidates to two within a single read — `PSRAM ID read error: 0xffffff` is a different fault class from `PSRAM init failed` is a different fault class from a missing init line entirely.
Run `esptool.py --port <PORT> chip_id` (replace `<PORT>` with your serial port — `COM4` on Windows, `/dev/ttyUSB0` on Linux, `/dev/cu.usbserial-*` on macOS). Read the `Features:` line. A genuine `ESP32-S3-WROOM-1 N16R8` reports `Features: WiFi, BLE, Embedded PSRAM 8MB (AP_3v3)`. If `Features:` does not list embedded PSRAM, the module is counterfeit or wrong-SKU — the PSRAM die is physically absent. No firmware change adds RAM that's not bonded inside the package. This is module-swap-only territory (Tier 4).
Re-flash the official factory image for your specific board variant. Bitaxe Hex: open [Bitaxe Web Flasher](https://bitaxe.org/flasher) in Chrome / Edge, plug in via USB-C, pick latest stable. NerdQAxe / QAxe+ / QAxe++: download the latest release `.bin` from the [shufps/qaxe](https://github.com/shufps/qaxe) GitHub release page and flash via `esptool.py write_flash` per the project README. NerdOctaxe and other Nerd variants: the project's official release page. Stock factory images are built with the correct `CONFIG_SPIRAM_MODE_*` flag for that specific board.
After re-flashing factory firmware, capture the boot banner again. If `Found 8MB PSRAM device` (Octal) or `Found 4MB PSRAM device` (Quad) now appears where it was previously missing, your earlier custom firmware was built with `CONFIG_SPIRAM=n` or the wrong PSRAM mode. Done — pin the official firmware version, document it in your operations notes. If the banner still shows `PSRAM ID read error`, the problem is hardware (counterfeit module, cold solder, VDD_SPI, or dying die), not firmware.
If the WROOM-1 module is hot to the touch within 10 s of boot (~50 °C+) on a board with no ASIC running, that's a short-circuit signature on `VDD_SPI` or one of the PSRAM data lines. Power off immediately. A shorted line burns the SoC's SPI controller if you keep cycling it — every additional power-on attempt makes the bench repair more expensive. Skip ahead to Tier 2 / 3 diagnostic with the board cold.
With multimeter on DC, probe the `VDD_SPI` test point near the WROOM-1 (broken out as a labelled pad on most Nerd / Bitaxe boards — check schematic). Should read 3.3 V on the standard N16R8 (or 1.8 V on a 1.8 V-flash variant — confirm against board schematic before measuring). Out of spec → wrong eFUSE programming, wrong strapping pin state, or a damaged regulator. If voltage sags during the boot window (you'll need a scope to catch the ~50 ms init dip), the brownout chain is the cause — fix electrical first.
Pull the `partitions.csv` and `sdkconfig` for the build you're running. Confirm: `CONFIG_SPIRAM=y`, `CONFIG_SPIRAM_MODE_OCT=y` (for Hex / NerdQAxe / NerdOctaxe N16R8 boards) OR `CONFIG_SPIRAM_MODE_QUAD=y` (for older N16R4 / N8R2 boards), `CONFIG_SPIRAM_TYPE_AUTO=y` (or explicit `CONFIG_SPIRAM_TYPE_ESPPSRAM64=y` for the AP Memory APS6408L), `CONFIG_SPIRAM_SPEED_80M=y` (or 120M on latest IDF revisions). OPI/QPI mismatch is the second-most-common cause D-Central sees on community-built boards — flag set wrong for the soldered hardware.
Verify the cable. Bench rule: half of `PSRAM is broken` tickets are flat-out a charge-only USB-C cable producing brownout-class behaviour during the PSRAM init window. Swap to a known-good data-capable USB-C cable (one that you know works for a phone data sync, not just charging). Re-test boot banner. If PSRAM init now succeeds, document it and move on — the cable is the cheapest fix in mining hardware.
If you suspect a counterfeit module, take a high-resolution photo of the WROOM-1 silkscreen under good light at 10× magnification. Compare against [Espressif's official product imagery](https://www.espressif.com/en/products/modules/esp32-s3). Counterfeits show: blurry or off-centre laser etching, slightly different module dimensions (1-2 mm smaller is common), missing or mis-formatted FCC ID, missing date code or wrong date format. Combined with `chip_id` reporting no embedded PSRAM, you have unambiguous counterfeit confirmation. Source the replacement from Mouser / Digikey / Espressif distributor.
Run a parallel UART logger for 24 hours: `idf.py monitor -p <PORT> | tee nerd-$(date +%F).log`. Capture the exact boot sequence across multiple power-cycles. Intermittent success/failure across boots = solder joint problem (Octal pins floating randomly). Consistent failure = module-level (counterfeit, sdkconfig, or VDD_SPI). Random `LoadProhibited` panics with no boot-banner error = dying PSRAM die. The pattern over 24 hours sorts these three apart.
Reflow the WROOM-1 with hot air. Pre-heat the host PCB to ~150 °C from the bottom side using a hot plate or a second hot-air station underneath. Top-side hot air at 280-300 °C, light flux around the module edge, 30 s working time. Avoid blowing adjacent passives off the board. Cool naturally — do NOT cold-quench (water, air-blast). Re-test. This fixes a real percentage of Octal-mode-only failures because the four Octal-only pins (`SPIIO4`-`SPIIO7`) sit at the corners of the WROOM-1 land pattern where hand-soldering and kit-build joints are weakest.
If reflow doesn't fix it and the module silkscreen is genuine, swap the WROOM-1 entirely. De-solder the existing module with hot air at 350 °C, ~60 s working time, lift carefully with tweezers — do NOT pry (you'll lift pads). Clean the host PCB pads with desolder braid + flux. Place a known-good `ESP32-S3-WROOM-1 N16R8` from a trusted source (Mouser, Digikey, Arrow, or Espressif's official distributor list). Reflow at 280-300 °C. Re-test boot banner. This is the standard repair path; budget ~$15-25 CAD for the genuine module plus your bench time.
Rebuild the firmware from source for your specific board with `idf.py menuconfig` reviewed line-by-line. Set: `CONFIG_SPIRAM=y`, `CONFIG_SPIRAM_TYPE_AUTO=y`, `CONFIG_SPIRAM_MODE_OCT=y`, `CONFIG_SPIRAM_SPEED_80M=y`, `CONFIG_SPIRAM_USE_MALLOC=y`, `CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y`. Build with `idf.py build`. Flash with `idf.py -p <PORT> flash monitor`. Diff your final `sdkconfig` against the upstream reference for your board (the `bitaxeorg/ESP-Miner` repo for Hex, `shufps/qaxe` for NerdQAxe). Pin reproducibility — snapshot the `sdkconfig` and `.bin` artifacts.
JTAG-trace the `esp_psram_init()` call. Hook an `ESP-PROG` JTAG adapter (or any FT2232H-based JTAG dongle) to the broken-out JTAG pins on the host PCB. Run `OpenOCD` with the `esp32s3.cfg` board file. In a second terminal, run `xtensa-esp32s3-elf-gdb` against your build's `.elf`. Halt at the symbol `esp_psram_init`. Step the SPI transactions one at a time. Watch the `READ_ID` command go out on the bus and the response come back — or not. This is the only way to definitively distinguish 'PSRAM die never answers' from 'PSRAM die answers wrong ID' from 'SPI bus never even clocks the read out.'
If JTAG confirms the SPI bus is clocking out a clean `READ_ID` command but the die returns `0xff 0xff 0xff` consistently across multiple power cycles — die is dead or never bonded inside the module package. Module swap (Tier 4). If JTAG shows the SPI bus never even clocks the command out, the SoC SPI controller is damaged or held in reset by a strapping pin error — that's host-PCB / SoC-level damage, also Tier 4 territory but a more expensive repair.
Stop DIY when: `chip_id` confirms no embedded PSRAM (counterfeit / wrong SKU); reflow + sdkconfig + VDD_SPI + cable + factory firmware all check out and the banner still says `PSRAM init failed`; you've swapped to a known-good module and the replacement also fails (rare but real — points at host PCB damage on the WROOM-1 land pattern, lifted pad, or trace fault). Ship to [D-Central ASIC + Bitaxe Repair](https://d-central.tech/services/asic-repair/).
D-Central bench process for `NERD_PSRAM_FAIL`: UART boot capture, `esptool.py chip_id` and `flash_id` reads, visual inspection under stereo microscope, reflow attempt with sized hot-air nozzle first (often fixes a marginal joint), swap WROOM-1 with a graded `N16R8` from our verified-source inventory if reflow fails, post-swap boot test with both `_QUAD` and `_OCT` sdkconfigs to confirm both modes work, 24-hour soak at nameplate. 3-7 business-day turnaround. Canada / US / international.
Ship safely. Wrap the Nerd / Bitaxe in an anti-static bag. Box with at least 3 cm of foam on every side. Include a note with: observed boot banner (full text, not paraphrased), firmware version, board revision, when the symptom started, and what you've already tried. Saves the bench diagnostic time and saves you repair cost. As the company that pioneered the Bitaxe Mesh Stand and the first heatsinks for Bitaxe and Bitaxe Hex, our open-source-miner bench depth covers everything from BM-series hashing silicon up through the ESP32-S3 / WROOM-1 module on which AxeOS and the Nerd firmwares run.
When to Seek Professional Repair
If the steps above do not resolve the issue, or if you are not comfortable performing these repairs yourself, professional service is recommended. Attempting advanced repairs without proper equipment can cause further damage.
Related Error Codes
Still Having Issues?
Our team of Bitcoin Mining Hackers has been repairing ASIC miners since 2016. We have seen it all and fixed it all. Get a professional diagnosis.
