Moon-Firmware

A hard fork of Momentum targeting STM32WB55, with a full BLE stack and XIP loading so big apps don't need to fit in RAM.

The lineage

Moon-Firmware is a hard fork of Momentum (itself a Unleashed fork) targeting the stock Flipper Zero hardware — STM32WB55 application core plus the Cortex-M0+ BlueNRG radio. We chose a hard fork rather than a patch-set because the changes touch the HCI command path, the BLE advertising state machine, and the FAP loader — places where upstream churn would make a rebase loop painful.

Compatibility: FAPs built for stock Flipper firmware run unchanged on Moon as long as they target a supported API level. The min_firmware_api field in the catalog entry is the gate — the on-device MoonOS app flags FAPs whose minimum is higher than what the running firmware exposes.

BLE: both roles, concurrently

The BlueNRG stack is configured as both a peripheral (what Flipper firmware has always done — apps and PCs connect to the Flipper as a GATT server) and a central (new — the Flipper scans for and connects to the paired Moon-Companion phone). Both roles run at once: you can have your phone connected for GPS/time/HTTP while a third-party laptop is still paired to the Flipper's BadUSB interface.

Pairing with the phone uses standard SMP with encryption (LE Secure Connections where available, falling back to legacy). Long-term keys persist across reboots; the phone's auth token is stored in Android's EncryptedSharedPreferences and survives app updates. After the first pair-accept dialog, subsequent reconnects happen silently.

See the companion page for the full pairing + proxy protocol.

XIP: execute in place

The STM32WB55 has 256 KB of SRAM and 1 MB of flash. The Flipper firmware, services, and assets eat most of the flash — and historically, FAPs were copied from flash into RAM before running, which meant your usable app size was capped by the RAM budget (around 150 KB after the kernel and active services took their cut). That's fine for a simple FAP, but Sub-GHz is 600 KB and NFC is 183 KB — they never fit.

Moon-Firmware's loader uses XIP (eXecute In Place): the FAP's code section stays in flash and the CPU fetches instructions from there directly. Only the data section (globals, BSS) gets copied to RAM. Apps with flags=["ForceXIP"] in their application.fam always use this path; large stock apps like Sub-GHz and NFC are shipped with the flag set.

Flash map

Approximate layout for a current fbt firmware_all build. Region sizes move a few KB as code lands — the headline number is the free-flash region at the bottom.

Bootloaderstage-032 KB
Kernelscheduler, drivers, services~250 KB
Assetsicons, fonts, protobufs~120 KB
BLE + radioBlueNRG firmware image~110 KB
.free_flashFAPs via XIP loader488 KB
Why 488 KB matters: every FAP in the catalog fits in this region, and XIP means loading a 258 KB SubGHz app is an address-space operation, not a memcpy. The whole load-launch-unload cycle is bounded by flash read latency (nanoseconds) instead of the RAM copy (tens of milliseconds for the big apps).

What this looks like on-device

Our end-to-end smoke test is a minimal .fapMoon API — that drives the HTTP proxy endpoint through the paired phone. Three quick endpoints, live response bodies, all over BLE GATT with chunked reassembly. If this FAP works, every other app in the store has the connectivity it needs. Grab it from the catalog.

Building

Build and flash with fbt just like stock:

Full source is on GitHub: KaraZajac/Moon-Firmware.