Skip to content

LPC845-BRK: AutoResearch firmware HardFaults during early init (regression since b468ed7) #3200

Description

@zackees

Summary

LPC845-BRK firmware built from current master HardFaults during early init -- before reaching setup() -- so Serial.begin() is never called and the device is silent on COM10. This is a regression vs b468ed7 (fix(autoresearch): wire LPC bring-up end-to-end against real hardware, 2026-06-13), which captured a verified end-to-end echo round-trip from the same bench.

Conclusive evidence from live SWD halt:

pyocd commander --target lpc845 -c "halt" -c "rr pc" -c "rr sp"
pc = 0x0000093a       # HardFault_Handler (matches vector table: HardFault = 0x0000093b - thumb bit)
sp = 0x100032e8       # Mid-SRAM -- fault happened during early init, before user code

b468ed7 documented this exact bench produced:

RX: b'FL_WARN: echo invoked\r\nREMOTE: {"id":1,"result":4242,"jsonrpc":"2.0"}\r\n'

The hardfault is independent of:

Reproduction

# 1. Build current master AutoResearch for lpc845brk
bash compile lpc845brk --examples AutoResearch
# -> firmware.bin at .fbuild/build/lpc845brk/release/firmware.bin (62.52 KB / 64 KB = 97.7%)
#    RAM: 14.49 KB / 16 KB = 90.6%

# 2. Erase + flash + reset
uv run python -m pyocd erase --target lpc845 --chip
uv run python -m pyocd load --target lpc845 .fbuild/build/lpc845brk/release/firmware.bin
uv run python -m pyocd reset --target lpc845

# 3. Probe live state -- PC will be in HardFault_Handler
uv run python -m pyocd commander --target lpc845 -c "halt" -c "rr pc" -c "go" -c "quit"
# pc = 0x0000093a   <-- HardFault loop

Vector-table evidence

From od -An -tx4 -v -N 32 firmware.bin:

Index Vector Value Notes
0 SP 0x10004000 top of 16 KB SRAM
1 Reset 0x00006e01 -> Reset_Handler (+thumb)
2 NMI 0x0000093b -> default handler
3 HardFault 0x0000093b -> default handler (where PC is stuck)
4-6 MemMgr/Bus/Usage 0x00000000 reserved on M0+
7 Checksum 0x00000939 checksum bytes are wrong but the boot ROM still hands off (pyocd reset --target lpc845 bypasses ROM checksum verify) -- this is a separate latent bug not the cause here

Reset_Handler itself (disassembled at 0x6e00) is correct: copies .data, zeros .bss, sets a SYSCON enable bit, calls __libc_init_array, then main.isra.0. The fault fires somewhere inside that chain.

Likely cause (hypothesis -- not yet confirmed)

RAM-ceiling regression. The build sits at 14.49 KB / 16 KB static RAM with only 1.5 KB left for stack + heap. AutoResearchLowMemory.h declares two static fl::EdgeTime buffers totalling 4 KB .bss:

  • edges_buf[512] in pinToggleRx (line ~200)
  • probe[512] in ws2812SctTest (line ~306)

These were intentionally moved off the stack in PR #3133 (fix(autoresearch/lpc): move pinToggleRx + ws2812SctTest edge buffers off the stack, closes #3125) -- a correct fix for the stack-overflow they previously caused. The side effect was a 4 KB .bss increase. Combined with other RAM-pressure landings since b468ed7, the headroom may have shrunk past what __libc_init_array needs to construct all C++ globals -- which would land in HardFault during early init exactly as observed.

Quickest confirmation probe

Shrink both kLowMem*BufSize constants in examples/AutoResearch/AutoResearchLowMemory.h:163 and :305 from 512u to 64u (-3.5 KB .bss), rebuild, flash, repeat the pyocd commander -c halt -c "rr pc" step. If PC is no longer in the 0x900-0x93f range -> RAM-ceiling confirmed and the fix is to drop one of the buffers, gate them behind their RPC handlers being called, or shrink their static-size constants permanently.

Commits to bisect across if probe (1) doesn't confirm

Range: b468ed7..HEAD -- the candidates that touched LPC, AutoResearch, or the linker boundary:

2df75a644 fix(examples/autoresearch): gate companion .cpp files on FASTLED_AUTORESEARCH_LOW_MEMORY (#3123)
fbd663b29 fix(autoresearch/lpc): move pinToggleRx + ws2812SctTest edge buffers off the stack (#3133)
3e14cd2a9 refactor(wave): move perf-bench logic into wave simulator; AutoResearch becomes external binder (#3120)
4f620ff0d feat(autoresearch): add perfProbe sanity probes (#3118)
8d19776fd feat(autoresearch): add wave2dPerf RPC handler (#3116)
81bcaf3e3 perf(rpc/lpc): gate schema generator + enable RX_SCT_WS2812 default on lpc845brk (#3089)
e18aa2bbd perf(rpc): gate rpc.discover + revert SBO bump (#3088)
dc92fe177 fix(lpc): F_CPU=24MHz + platform-detection ordering + SCT macro shim (#3055)

Hardware

  • LPC845-BRK on COM10 (NXP VID:PID = 1fc9:0132)
  • Host: Windows 10 19045
  • Toolchain: arm-none-eabi-gcc 15.2.1 (vendored via fbuild's developer-gnu cache)
  • ArduinoCore-LPC8xx: upstream 195a2eddd31eba8472ceaffa6a1a1902f72439ae (current HEAD of zackees/ArduinoCore-LPC8xx)
  • Tested with both fbuild==2.2.28 (PyPI) and fbuild==2.2.29 (local fbuild2 with Archiving built core (caching) #606 in_waiting/reset_input_buffer fixes) -- identical firmware byte-for-byte, identical hardfault.

Refs

Filed via Claude Code on behalf of zachvorhies@protonmail.com.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions