Skip to content

meta: port FastLED to NXP LPC8xx (LPC804 + LPC845) — two-stage plan #2836

Closed

Description

@zackees

Meta tracking issue for the NXP LPC8xx port discussion in #2831. Splits the work into two stages so build/toolchain support and the FastLED port itself can be reviewed and merged independently.

Context

Issue #2831 (author: @phatpaul) proposes porting FastLED to:

  • LPC804 — Cortex-M0+, 15 MHz, 32 KB Flash, 4 KB RAM, no DMA, but has a Programmable Logic Unit (PLU) that can generate WS2812 bitstreams.
  • LPC845 — Cortex-M0+, 30 MHz, 64 KB Flash, 16 KB RAM, has DMA. Author proposes 3 PWM channels triggering DMA to GPIO for parallel output.

Feasibility was confirmed in issue #2831 comment:

  • LPC804 bit-bang is marginal (~5 cycles for T1 at 15 MHz); the PLU offload is the right call. Architectural analogue: RP2040 PIO driver (src/platforms/arm/rp/rpcommon/clockless_rp_pio.h).
  • LPC845 bit-bang is comfortable (~11 cycles for T1 at 30 MHz). Direct template: KL26 / Teensy LC driver (src/platforms/arm/kl26/).
  • No existing FastLED port uses PWM→DMA→GPIO; the LPC845 PWM+DMA approach would be a novel pattern (closest analogues: RP2040 PIO and Teensy 4.x FlexIO).

Neither FastLED nor fbuild has any LPC family support today (verified via gh issue list and codebase scan).

Stage 1 — Build/toolchain support in FastLED/fbuild

Goal: produce a clean ARM Cortex-M0+ build for LPC804/LPC845 that the FastLED port can target. Land before Stage 2.

Likely touch points (implementer to confirm against current fbuild layout):

  • Toolchain: ARM GCC for Cortex-M0+ (-mcpu=cortex-m0plus -mthumb). Likely already available from existing nRF51/KL26/Apollo3 targets — verify and reuse.
  • Board definitions (ci/board_sources.py, board JSON under crates/fbuild-packages/assets/): add lpc804 and lpc845 entries with memory map (Flash/RAM addresses), CPU spec, linker script reference.
  • Linker scripts + startup: vector table, Reset_Handler, BSS/data init, stack pointer at top of RAM. Reference: NXP MCUXpresso SDK or community LPC8xx-bare-metal templates (e.g. drolliblog WS2812 example linked in Porting to LPC8xx #2831).
  • Flash/upload tooling: LPC8xx supports ISP via UART boot ROM (use lpc21isp) and/or SWD via CMSIS-DAP / pyOCD. Pick one as default per board; document the other.
  • CI workflows: add .github/workflows/build-lpc804.yml and build-lpc845.yml following the existing per-board pattern (cf. build-apollo3_red.yml, build-attiny85.yml). Add badges to README.
  • validate_boards.py entry so the new boards are smoke-checked in CI.
  • Framework JSON: if LPC8xx lands as bare-metal (no Arduino core), document the framework choice in crates/fbuild-packages/assets/ parallel to avr_frameworks.json.

Stage 1 acceptance criteria

  • fbuild build lpc845 produces a flashable ELF for a minimal blink program from clean checkout
  • fbuild build lpc804 produces a flashable ELF for a minimal blink program from clean checkout
  • .github/workflows/build-lpc804.yml and build-lpc845.yml exist and pass in CI
  • validate_boards.py includes both new boards
  • README badges added for both boards
  • Upload/flash path documented (lpc21isp or pyOCD) per board
  • An fbuild issue is filed and linked here to track Stage 1 PR(s)

Stage 2 — FastLED platform port in FastLED/FastLED

Goal: WS2812 output working from examples/Blink/Blink.ino on both boards via fbuild. Depends on Stage 1 merged.

Stage 2a — LPC845 bit-bang driver (lowest risk, ship first)

  • src/platforms/arm/lpc/is_lpc.h — detect __LPC845__ / __LPC804__ via compiler macros
  • src/platforms/arm/lpc/int.h — ARM 32-bit int typedefs
  • src/platforms/arm/lpc/led_sysdefs_arm_lpc.h — FL_IS_ARM_M0_PLUS, F_CPU, interrupt policy
  • src/platforms/arm/lpc/fastpin_arm_lpc.h — pin/port mapping for LPC845 GPIO
  • src/platforms/arm/lpc/clockless_arm_lpc.h — bit-banged M0+ ASM driver, using src/platforms/arm/common/m0clockless_asm.h cycle macros. Template: src/platforms/arm/kl26/clockless_arm_kl26.h.
  • Hook into ARM dispatcher: add #include \"lpc/is_lpc.h\" to src/platforms/arm/is_arm.h
  • examples/Blink/Blink.ino compiles and runs WS2812 output on a real LPC845 board (validated via examples/AutoResearch/AutoResearch.ino if RPC harness is feasible there; otherwise scope-bench)

Stage 2b — LPC804 PLU driver (novel, follow-up)

  • PLU bitstream program (NXP IDE export or hand-rolled .v / register init sequence)
  • src/platforms/arm/lpc/clockless_arm_lpc_plu.h — wraps PLU + CPU-fed data path. Architectural template: src/platforms/arm/rp/rpcommon/clockless_rp_pio.h (CMinWait + DMA/FIFO feed pattern, adapted for PLU)
  • Compile-time selection between bit-banged fallback (won't fit timing on 15 MHz) and PLU driver
  • AutoResearch or scope validation on real LPC804 board

Stage 2c — LPC845 PWM+DMA driver (novel, optional optimization)

  • src/platforms/arm/lpc/clockless_arm_lpc_pwm_dma.h — 3 PWM channels triggering DMA to GPIO output registers (per author's plan)
  • Document as optional optimization over Stage 2a bit-bang; not required for port-complete
  • AutoResearch / scope validation

Stage 2 acceptance criteria

  • bash compile lpc845 --examples Blink succeeds via fbuild from Stage 1
  • bash compile lpc804 --examples Blink succeeds (with PLU driver path active)
  • WS2812 output verified on hardware for at least one board (Stage 2a minimum)
  • LPC port added to FastLED's platform support matrix / docs

Decisions

  • Priority: P3 — Community-contributor port (author offered to do the work), not blocking shipping. Upgrade if a maintainer takes it on.
  • Stage ordering: fbuild first. Without it, the FastLED port has nothing to compile against. Reviewers can validate Stage 2 PR by checking out the Stage 1 fbuild branch.
  • Single meta issue, not split per-board: LPC804 and LPC845 share enough infrastructure (toolchain, port subdir, ARM dispatcher hook) that splitting per-chip would fragment review. Per-chip work is tracked as Stage 2a/2b/2c checkboxes inside this issue.
  • LPC845 first within Stage 2: bit-banged ASM driver is the lowest-risk path and matches a known-working template (KL26). LPC804 PLU is novel and should come after the boring path is green.
  • PWM+DMA (Stage 2c) flagged optional: no precedent in FastLED; lands as an optimization PR after 2a/2b prove the port works.
  • Home repo for meta issue: FastLED/FastLED, parallel to origin discussion Porting to LPC8xx #2831. fbuild gets its own Stage 1 tracking issue when implementer starts work.
  • Author of Porting to LPC8xx #2831: cc @phatpaul — he offered to do the porting work and has LPC8xx experience.

Related issues

Activity

  1. zackees commented on Jun 5, 2026

    @zackees
    MemberAuthor

    Stage 1 + Stage 2a drafts up for review

    Both PRs are open as drafts and were implemented in parallel by AI sub-agents. No hardware validation possible from this side — host builds and unit tests are green, hardware verification belongs to whoever can flash an LPC845 / LPC804 board.

    Stage 1 — fbuild build/toolchain

    PR: FastLED/fbuild#419 — feat(platform): LPC804 + LPC845 bare-metal targets (Stage 1 of FastLED/FastLED#2836)
    Branch: feat/2836-lpc8xx-support · 27 files, +1011 LOC

    What landed:

    • New Platform::NxpLpc arch in fbuild-core (+ parser/test) and nxplpc build module in fbuild-build (mod.rs, mcu_config.rs)
    • Board defs: crates/fbuild-config/assets/boards/json/lpc804.json and lpc845.json, plus manifest.json sorted insert
    • Linker scripts (lpc804.ld, lpc845.ld) and Cortex-M0+ startup vectors (startup_lpc804.S, startup_lpc845.S) — memory regions taken from NXP datasheets and cited in each file header
    • CI: .github/workflows/build-lpc804.yml, build-lpc845.yml — both continue-on-error: true until Stage 2 lands
    • README + docs/BOARD_STATUS.md updated with NXP LPC badge group
    • All green: workspace cargo check, clippy -D warnings, cargo fmt --check, cargo test across fbuild-core (86 ✓), fbuild-build --lib nxplpc (8 ✓), fbuild-config --lib (142 ✓)

    Documented TODOs (left explicit in code with datasheet pointers, NOT silently faked):

    1. SystemInit stub in startup_lpc845.S — board JSON advertises 30 MHz but boot ROM defaults to 12 MHz IRC; FRO+PLL+flash-wait-state setup deferred to Stage 2 (UM11029 §4)
    2. Vector tables ship as ARMv6-M 16-entry system minimum; peripheral IRQs added as Stage 2 drivers need them
    3. get_nxplpc_config is shared between both chips; split when Stage 2 needs per-chip flag divergence (e.g. PLU defines for LPC804)
    4. Linker-script memory regions cited from datasheets but unverified on hardware — reviewers with boards should sanity-check before flashing

    Stage 2a — FastLED LPC845 bit-bang clockless driver

    PR: #2837 — feat(platform): LPC845 bit-bang clockless driver (Stage 2a of #2836)
    Branch: feat/2836-lpc845-port · 9 files, +353/-4 LOC

    What landed (all under src/platforms/arm/lpc/):

    • is_lpc.h — detects __LPC845__ / __LPC804__ / CPU_LPC845* / CPU_LPC804* from MCUXpresso CMSIS headers; emits FL_LPC845, FL_LPC804, FL_IS_ARM_LPC
    • int.h — delegates to shared src/platforms/arm/int.h
    • led_sysdefs_arm_lpc.h — F_CPU 30 MHz / 15 MHz per chip, FL_IS_ARM_M0_PLUS, cli/sei via __disable_irq/__enable_irq
    • fastpin_arm_lpc.h — _ARMPIN template for PIO0_0..PIO0_31 using LPC_GPIO->SET/CLR/DIRSET/DIRCLR/NOT/PIN[0]
    • clockless_arm_lpc.h — WS2812 controller routed through shared showLedData<HI_OFFSET, LO_OFFSET, ...>
    • fastled_arm_lpc.h — aggregator
    • Hooks into src/platforms/arm/is_arm.h, src/led_sysdefs.h, src/platforms.h

    Key implementation decision worth flagging for review:

    • Chose the shared M0+ C++ implementation path (FASTLED_M0_USE_C_IMPLEMENTATION) over the ASM template because LPC8xx places SET[0]/CLR[0] at +0x2200/+0x2280 — byte offsets 256/384 from PIN[0], which exceed the 124-byte limit of the M0+ STR Rt, [Rn, #imm5*4] encoding the ASM template's "I" constraint requires. The C++ path is still cycle-tight at 30 MHz; expect this to pass scope verification on hardware. If timing is marginal, the fallback is a hand-rolled ASM variant using LPC_GPIO->W[0][n] (word-wide single-bit registers, near PIN[0]).
    • FastPin<>::port() returns &LPC_GPIO->PIN[0]; HI_OFFSET=0x100, LO_OFFSET=0x180 (relative to PIN[0]) pass to showLedData<>.

    Verification:

    • bash lint --cpp: clean (PlatformIO warnings in ci/ are pre-existing, warn-only)
    • Host stub build via FASTLED_STUB_IMPL: clean — LPC code inert when no LPC SoC define is set
    • A pre-existing master failure in src/fl/net/network_detector.h:50 (C++17 nested-namespace syntax under -Werror=c++17-extensions) is unrelated — verified identical on pristine master and flagged in PR body; left untouched to keep scope tight

    Status vs. Stage 2 acceptance criteria

    Criterion Status
    fbuild build lpc845 produces flashable ELF ⏸ blocked — Stage 1 orchestrator returns "Stage 2 required" from build() until merged together
    fbuild build lpc804 produces flashable ELF ⏸ same
    build-lpc{804,845}.yml workflows exist ✅ added (continue-on-error until both PRs land)
    validate_boards.py includes both ⏸ skipped — no PlatformIO source for nxplpc platform; acceptance criterion may need rewording (validate via cargo test instead?)
    README badges added ✅
    src/platforms/arm/lpc/ exists with full port ✅ (Stage 2a — LPC845 bit-bang only)
    ARM dispatcher hooked ✅
    Stage 2b LPC804 PLU ⏸ deferred — Stage 2a-only PR
    Stage 2c LPC845 PWM+DMA ⏸ deferred — Stage 2a-only PR
    WS2812 output verified on hardware ❌ AI agents cannot validate; requires hardware + scope

    Next steps

    1. Human review of both draft PRs — especially the linker-script memory regions and the M0+ C++ vs ASM decision in Stage 2a
    2. Merge order: Stage 1 (Teensy 3.1/3.2 ARMHardwareSPIOutput::waitFully hanging due to race condition #419) first, then rebase Stage 2a (feat(platform): LPC845 bit-bang clockless driver (Stage 2a of #2836) #2837) and remove continue-on-error from the workflows
    3. Hardware validation by @phatpaul or any maintainer with a board
    4. Follow-up issues for Stage 2b (LPC804 PLU) and Stage 2c (LPC845 PWM+DMA) once the boring path is green

    cc @phatpaul — these scaffold both PRs to the point you can pick up hardware validation and the PLU/DMA optimizations.

  2. zackees commented on Jun 5, 2026

    @zackees
    MemberAuthor

    Roadmap continues in #2845 (Stages 3 + 4 — port completion and family expansion). Stages 2b (#2841) and 2c (#2842) remain tracked here as the immediate Stage 2 follow-ups.

  3. zackees commented on Jun 6, 2026

    @zackees
    MemberAuthor

    Closing #2836 — all code-only Stage 1 + 2 work has shipped

    Status of the acceptance criteria in this meta:

    Stage 1 (fbuild toolchain)

    Stage 2a — LPC845 bit-bang clockless driver

    Shipped via #2837 (merged at ebd8791748). Full Stage 2a checkbox set delivered:

    • src/platforms/arm/lpc/is_lpc.h — __LPC845__ / __LPC804__ detection
    • src/platforms/arm/lpc/int.h
    • src/platforms/arm/lpc/led_sysdefs_arm_lpc.h — FL_IS_ARM_M0_PLUS, F_CPU
    • src/platforms/arm/lpc/fastpin_arm_lpc.h — LPC845 GPIO pin mapping
    • src/platforms/arm/lpc/clockless_arm_lpc.h — M0+ bit-bang ASM driver
    • ARM dispatcher hook (is_arm.h picks up FL_IS_ARM_LPC)

    Stage 2b — LPC804 PLU driver

    Shipped via #2848 (merged as dbe38b593f), closing issue #2841:

    • src/platforms/arm/lpc/clockless_arm_lpc_plu.h
    • Compile-time selection between bit-bang fallback and PLU driver

    Stage 2c — LPC845 PWM+DMA driver

    Shipped via #2850 (merged as a9833b8d11), closing issue #2842:

    • src/platforms/arm/lpc/clockless_arm_lpc_pwm_dma.h
    • Documented as optional optimization over Stage 2a bit-bang.

    What remains, by category

    Closing this meta — the Stage 1 + 2 code surface is complete and reviewable as a unit. The hardware-dependent and follow-on items live under #2845.

  4. moved this from Triage to Done in FastLED Trackeron Jun 6, 2026
  5. phatpaul commented on Jun 6, 2026

    @phatpaul
    Contributor

    Wow! Way more than I expected. Ill start validating on real hardware on Monday. Thank you.

  6. zackees commented on Jun 6, 2026

    @zackees
    MemberAuthor

    Protip: use our new tool https://github.com/fastled/fbuild, which is a drop in replacement for platformio. You can install it like this pip install fbuild or use the binaries on the release page.

    If you have problems, ask the AI how to make a platformio.ini that it can use.

  7. phatpaul commented on Jun 8, 2026

    @phatpaul
    Contributor

    I'm having some trouble getting it to compile on bare metal due to FastLED depending on a bunch of Arduino stuff.

    Do you think that creating a "Arduino-compatible framework for NXP LPC8xx" is the best approach? I would prefer that the FastLED library does not depend on Arduino. Then I can use FastLED on bare metal without extra shims for Arduino support. But I realize this might be be impossible given FastLEDs design of which I'm not familiar.

    Just an example, the NMEA2000 library is compatible with both Arduino and bare metal. To allow that, the library defined it's own internal versions of Arduino stuff that it needed like:

    "N2kStream.h"

    #ifdef ARDUINO
    // Arduino users get away with using the standard Stream class and its
    // subclasses. Forward declare the Stream class here and include Arduino.h in
    // the application.
    #include <Arduino.h>
    /** Brief Forward Declaration of the stream class*/
    typedef Stream N2kStream;
    #else
    
    /**************************************************************************//**
     * \class N2kStream
     * \brief Streaming Class to handle all Streams generated by the Library
     * \ingroup group_coreSupplementary
     * 
     * Non Arduino platforms need to implement this class if they want to use
     * functions which operate on streams. 
     */
    class N2kStream {
       public:
    ...

    Thanks!

  8. zackees commented on Jun 8, 2026

    @zackees
    MemberAuthor

    Arduino is not necessary. You can compile fastled for gnu windows/linux/mac just fine. The AI put in arduino.h because it patterned matched. Feel free to stub it out. Arduino core doesn't even exist for NXP. However one of my background tasks is to make such a shim so that our examples/ test suite can compile and run.

    As far as the LED drivers are concerned... the AI vibe coded all of them. The chance any of them work is not high.

    However, if you send me an NXP board, any of them, I can solder the two pins together and run my "autoresearch" tool that allows the AI to finish the job and automatically develop the led driver.

  9. phatpaul commented on Jun 8, 2026

    @phatpaul
    Contributor

    That sounds great, thanks for clarifying. I'll keep on plugging away.
    My end goal is to be able to get it to work in my existing project which uses MCUXpresso SDK and FreeRTOS.

    I do have an extra LPC845-BRK board. If you want, please send me your shipping address to my email: phatpaul at gmail dot com

  10. zackees commented on Jun 9, 2026

    @zackees
    MemberAuthor

    Sent email

    subj: Nxp for Zach Vorhies (Zackees)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions