Commit Graph

851 Commits

Author SHA1 Message Date
Julian Oes
ec8718f05e feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237)
* feat(secure_bootloader): add ed25519 key and signing helpers

Scaffolding for PX4 secure-boot firmware signing, split into two
self-contained scripts:

- generate_signing_keys.py: produces <name>.json (private+public hex)
  for use by sign_firmware.py and <name>.pub (C-array public key)
  for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn.
  Refuses to overwrite existing private-key files.

- sign_firmware.py: pads an input .bin to a 4-byte boundary and
  appends a 64-byte ed25519 signature, producing a file that drops
  directly into the flash slot described by the image TOC.
  Optionally appends an R&D certificate binary after the signature.

Replaces the signing path of the old Tools/cryptotools.py that was
removed along with the log-encryption cleanup; the new layout keeps
bootloader-signing tooling separate from log encryption to avoid
confusing the two independent crypto surfaces.

* fix(bootloader): panic if px4_get_secure_random is ever called

sw_crypto's crypto_open() unconditionally references
px4_get_secure_random from its XCHACHA20 path, so even a bootloader
that only performs ed25519 signature verification (and never touches
stream ciphers) pulls in an undefined symbol at link time.

The app build resolves it through nuttx_random.c, which is gated
behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the
NuttX random pool is enabled. That config isn't on in the tiny
bootloader NuttX defconfig, and enabling it would pull in a pile
of kernel code the bootloader doesn't need.

Supply the symbol locally, but make it call up_assert() instead of
returning zeros. Silently handing out predictable bytes would be a
serious security bug if anyone later enables the XCHACHA20 path in
the bootloader without wiring up a real RNG. Aborting makes the
mistake impossible to miss.

* fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check

Today a signed-boot failure is invisible to the uploader: verify_app()
runs inside jump_to_app() after PROTO_BOOT has already rebooted the
chip, so the host sees a successful upload followed by the device
silently staying in the bootloader. There is no protocol-level signal
that the image that was just written is not going to run.

Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run
find_toc() + verify_app(0) *before* the reboot and get a concrete
OK / FAILED / INVALID answer back over the still-open USB connection.
The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built
without secure boot return cmd_bad (INSYNC/INVALID) so an uploader
can tell "I don't know this command" apart from "verification failed".

Two subtleties required care:

1. PROG_MULTI deliberately defers the very first word of the app
   image to a RAM variable (first_word) and only commits it to flash
   inside PROTO_BOOT, so a partial upload can never become bootable.
   But verify_app() reads directly from flash, so if we verified
   before committing first_word, even a valid image would always
   fail (the first four bytes at APP_LOAD_ADDRESS would still be
   0xffffffff). The handler therefore mirrors the first half of the
   PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the
   deferred first word, then run the crypto check.

2. On failure we deliberately do not try to "undo" the first-word
   write — H7 flash programming granularity makes it impossible to
   revert in place, and the device was going to end up in the same
   reject state at the next boot either way. The improvement is
   purely that the uploader sees the failure before REBOOT instead
   of after.

Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and
0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which
an AP-compatible uploader might.

ArduPilot also has bootloader secure boot (monocypher ed25519, like
us) but their verification runs at boot time, not upload time — so
neither project currently solves the "upload silently wrote a bad
image" problem. This puts PX4 ahead on that.

* feat(Tools): add --image_signed to mark signed firmware for uploader

px_uploader.py only needs to run signature verification over USB for
images that actually carry a signature — asking the bootloader to
verify an unsigned image would always fail, and the extra round trip
is wasted time for the common unsigned case. It therefore needs a
reliable way to tell the two apart.

We cannot tell by inspecting the bytes: a sign_firmware.py output is
just the raw .bin with 64 bytes of ed25519 signature glued on the
end, indistinguishable in content from an unsigned image of the same
padded length. The natural place to put the flag is the .px4 JSON
envelope, which already carries board_id / version / summary / etc.

Add --image_signed to px_mkfw.py, which sets "image_signed": true
in the emitted JSON. The flag has no effect on what bytes actually
end up on the device — it just tells the uploader "this blob has a
signature, please verify it before booting".

* feat(Tools): verify firmware signature before reboot

After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to
the bootloader to check the ed25519 signature over the freshly
flashed image *before* sending REBOOT. This way a signature failure
is reported as a clean error from the uploader script, instead of a
silent "device stays in bootloader after reboot" that leaves the user
guessing.

The uploader always probes VERIFY_SIG. The bootloader is the source
of truth for whether secure boot is enabled:

- INSYNC/OK         -> verification passed, proceed to REBOOT
- INSYNC/FAILED     -> raise; "Signature does not verify against any
                       trusted key" if the firmware claims to be signed,
                       "Secure bootloader rejected an unsigned image"
                       otherwise (= helpful guidance for the common
                       misconfiguration of uploading default firmware
                       to a secureboot bootloader)
- INSYNC/INVALID    -> bootloader has no secure boot. Quietly proceed
                       unless the firmware metadata says image_signed,
                       in which case raise.
- recv timeout      -> assume a pre-VERIFY_SIG bootloader, proceed.

Surfaces a "Verifying image signature... passed" line on the upload
status path when the firmware is marked signed, so users get a clear
positive signal that the secure-boot pipeline ran end-to-end.

Also drop the redundant logger.error in the upload() loop, which was
duplicating the error message printed by the top-level handler in
main() for every UploadError path (not specific to verify_signature,
but only became obvious once these clean error messages started
firing in normal usage).

* fix(cmake): fix .px4board variant resolution to require exact match

px4_config.cmake matched the requested CONFIG against each candidate
.px4board with `MATCHES`, which is a regex partial match. For a
config like `px4_fmu-v6x_bootloader_secureboot`, the iteration over
.px4board files (alphabetical glob order) would match
`bootloader.px4board` first — because "px4_fmu-v6x_bootloader" is a
prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently
selecting the wrong board config.

Use `STREQUAL` instead so each candidate has to match the full
requested CONFIG. Existing single-label cases (e.g. exact match on
`px4_fmu-v2_default` or `px4_fmu-v2`) are unaffected because they
were already exact in practice; this just plugs the prefix-match
hole that any future `<label>_<suffix>` variant would trip over.

* fix(nuttx): support bootloader_<variant> labels

Boards can ship bootloader variants beyond the default `bootloader`
label — e.g. a `bootloader_secureboot` that adds crypto + keystore
Kconfig on top of the same source tree. Two pieces of build glue
were hardcoded to the exact label `bootloader` and need to relax to
match any `bootloader_*` label:

1. platforms/nuttx/CMakeLists.txt picked the bootloader linker
   script and bootloader-specific library list only when the label
   was exactly `bootloader`. Any other label (including
   `bootloader_secureboot`) silently fell through to the app build,
   producing nonsensical link flags. Match `^bootloader` instead,
   and explicitly set SCRIPT_PREFIX to `bootloader_` so all
   bootloader variants share the single existing linker script
   regardless of their full label.

2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config
   subdirectory by exact label match, falling back to `nsh` when no
   matching directory exists. For `bootloader_secureboot` that fell
   through to `nsh`, dragging in a full app-style NuttX with cromfs,
   networking, and the full heap subsystem — a 128 KB bootloader
   sector overflowed by ~50 KB. Add an intermediate fallback: if the
   label starts with `bootloader` and a `bootloader/` subdir exists,
   use that instead of `nsh`.

Both changes are backward-compatible: existing single-label
`bootloader` builds take exactly the same path as before. They only
gain the ability for boards to add `bootloader_<suffix>.px4board`
files without duplicating bootloader build wiring.

* feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT

Add a Kconfig pair that boards can opt into:

  CONFIG_BOARD_SECUREBOOT      -- bool: sign the .px4 with ed25519
  CONFIG_BOARD_SECUREBOOT_KEY  -- string: path to JSON private key
                                  (default: Tools/test_keys/test_keys.json)

When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py
step between the unsigned .bin and px_mkfw.py, and passes --image_signed
so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG
step. The unsigned .bin is still produced alongside the .px4, so users
can sign with their own key out-of-tree if they prefer.

A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path
at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn
in stub_keystore. This makes release builds practical:

  BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot

Relative paths in the Kconfig are resolved against the repo root (not
the build directory) so the same value works regardless of where the
build runs from.

Default builds are byte-identical to before; the new code path is gated
on CONFIG_BOARD_SECUREBOOT being set.

* feat(boards): add secureboot demo variant + docs

Two coordinated build variants demonstrate end-to-end secure boot
on px4_fmu-v6x without touching the default builds:

  px4_fmu-v6x_secureboot              -- the app, with TOC + signing
  px4_fmu-v6x_bootloader_secureboot   -- the matching secure bootloader

App side (secureboot.px4board):
  - Selects nuttx-config/scripts/secureboot-script.ld via
    CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default
    layout plus a fixed 0x800 reservation past the vector table for
    the image TOC, and an empty .signature section at end-of-FLASH
    so sign_firmware.py knows where the appended ed25519 signature
    will land.
  - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the
    layout used elsewhere in the tree) into drivers_board, gated on
    PX4_BOARD_LABEL == secureboot so the default build still
    produces the existing layout.
  - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the
    image with the upstream test key by default.

Bootloader side (bootloader_secureboot.px4board):
  - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE,
    which links monocypher and the stub keystore into the bootloader.
  - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired
    with the test_keys.json the app variant signs with.
  - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM
    (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO,
    so they only activate in this variant.

Together the two variants implement the workflow:

  make px4_fmu-v6x_bootloader_secureboot     # build + flash via SWD once
  make px4_fmu-v6x_secureboot upload         # signs with test key, verifies

Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections
stripping the unused libtomcrypt code; nothing in the bootloader
binary depends on monocypher beyond the ed25519 verifier.

Replace the bundled test key for production with
Tools/secure_bootloader/generate_signing_keys.py output and update
both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) —
see docs/en/advanced_config/bootloader_secure_boot.md.

* fix(boards): cap H7 bootloader linker scripts at 128 KB

Roughly half of the H7 boards in tree had `LENGTH = 2048K` for the
bootloader sector in their bootloader_script.ld, even though the
matching app linker script places APP_LOAD_ADDRESS at 0x08020000 —
i.e. the bootloader actually only owns the first 128 KB sector.

The 2048K constraint is wrong: it lets a bootloader that grew past
the 128 KB sector silently overflow into the app sector at link
time and corrupt the start of the app on flash. The linker should
fail the build instead.

The current default bootloader is ~46 KB, well under 128 KB on every
affected board, so this change is a no-op for default builds. It
just plugs a footgun for anyone adding bootloader features (secure
boot, extra UI, network boot, ...) that would have otherwise
silently grown into the app's flash range.

Boards fixed:

  3dr-style H7 reference boards: cubepilot/cubeorange,
    cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7
  vendor variants: corvon/743v1, cuav/nora, cuav/x7pro,
    gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1,
    matek/h743, matek/h743-mini, matek/h743-slim,
    micoair/h743, micoair/h743-aio, micoair/h743-lite,
    micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2

Boards already correct (LENGTH = 128K) are unchanged.

* fix(ci): add pynacl to Python requirements

Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519
signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT
calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot).
Without pynacl in the dev requirements, those builds fail in CI and
fresh dev setups.

* docs(update): Subedit

* docs(update): Fix example error I made

* fix(docs): document BOOT and SIG1 regions

* fix(platforms): style fix

* fix(ci): workaround to get pip dependency

* fix(ci): fall back to plain pip on older build containers

The voxl2 build image ships a pip that predates --break-system-packages
(added in pip 23.0.1), so the install step blew up with "no such option".
Modern containers enforce PEP 668 and need the flag; older ones don't
support it but also don't enforce PEP 668, so plain pip works there.
Try the modern flag first, fall back if pip rejects it.

Signed-off-by: Julian Oes <julian@oes.ch>

* fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build

cmake-build was passing the full build-dir name (including any
BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which
the board-lookup in cmake/px4_config.cmake then tried to match
against <vendor>_<model>_<label> .px4board files. That used to work
by accident because px4_config.cmake matched with regex MATCHES, but
since the switch to STREQUAL (needed to disambiguate
bootloader_secureboot from bootloader) the suffixed CONFIG no longer
matches anything and LABEL ends up empty, tripping a CMake error in
kconfig.cmake.

Pass the bare CONFIG and keep the suffix only on the build dir so
both concerns are independent.

Signed-off-by: Julian Oes <julian@oes.ch>

---------

Signed-off-by: Julian Oes <julian@oes.ch>
Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
2026-05-27 20:21:49 -06:00
Jacob Dahl
659ab6b400 fix(dshot): pick bit width per timer clock for accurate rate (#27402)
Auto-selects DSHOT_MOTOR_PWM_BIT_WIDTH per timer clock at compile time
so ARK FPV emits DSHOT at the same bit period as the rest of the fleet.
The hardcoded WIDTH=20 truncates the prescaler on ARK FPV's 160 MHz APB1
(PLL1N=40, floor(160e6/600e3)=266 not divisible by 20), giving a 1.706us
bit period and 66.7%/33.3% duty cycles (vs DSHOT600 spec 75%/37.5%).

The new ladder tries WIDTH in {20, 19, 18} and picks the first that
divides cleanly. ARK FPV lands on W=19, matching the 1.75us bit period
of the 240 MHz boards. Duty cycles improve to 70%/35%. 240/96/108/84 MHz
boards keep W=20 (unchanged). 200 MHz boards (CubeOrange/Orange+,
h7extreme) fall through to W=20 (unchanged, fix needs W=22 with scaled
BIT_1/BIT_0 -- out of scope).

A #pragma message (not #warning, which -Werror=cpp would treat as an
error) flags boards where APB1 and APB2 timer clocks would emit DSHOT
at different rates -- currently only fmu-v4pro (APB1=90, APB2=180 MHz).
The whole block is guarded on STM32_APB2_TIM8_CLKIN so STM32F1 IO
co-processor boards (no TIM8, header still pulled in by io_timer.c)
keep W=20 silently.

Supersedes #27401.
2026-05-26 13:53:31 -06:00
Alexis Guijarro
c59f208cc7 feat(boards): add support for 3DR Control N1 flight controller (#27395)
* fix(srgbled_dma): stm32_dmasetup now works with H7 boards

* feat(drivers/ak09940a): add AKM AK09940A magnetometer driver

* feat(boards/3dr/ctrl-n1)!: add 3DR Control-N1 flight controller

* fix(boards/3dr/ctrl-n1): macro replacement list is now enclosed in parentheses

* fix(boards/3dr/ctrl-n1): applying copyright changes

* fix(boards/3dr/ctrl-n1): removing serial console
2026-05-19 13:13:54 -05:00
Jacob Dahl
b4b36a2748 fix(nuttx): unblock multi-board and protected builds (#27360)
* fix(ci): wipe NuttX submodule state between boards in build_all_runner

NuttX .o and lib*.a live in the shared submodule trees under
platforms/nuttx/NuttX/{nuttx,apps}, not in per-board build/<board>/.
NuttX's recursive make doesn't treat PX4's per-board defconfig changes
as a reason to recompile, so consecutive board builds in one workspace
were linking stale objects from an earlier board (e.g. stm32_spi.o from
fmu-v2 linked into fmu-v4pro, which doesn't enable SPI4).

Run git clean -dXf on both NuttX submodules between iterations to drop
gitignored build state. This mirrors what make clean already does for
submodules and preserves the incremental-build wins for single-board
use.

* fix(cmake): isolate kernel mm/libc objects with BINDIR=kbin

mm and libs/libc compile the same sources for both the kernel and user
passes in protected builds. Without separate output dirs the kernel
objects clobber bin/*.o and the user-mode libmm.a/libc.a end up pulling
in kernel-only symbols (nxsem_wait, g_current_regs, nx_read, nx_write,
g_mmheap, ...) at link time. Matches NuttX's own tools/LibTargets.mk.
2026-05-17 16:00:06 -06:00
Daniel Fanache
b990430cdc fix(cmake): incremental no-op rebuild 44 s -> 0.15 s on NuttX targets (#27324)
* fix(cmake): use Python3 module; cache PYTHON_EXECUTABLE properly

The legacy `find_package(PythonInterp 3)` is deprecated (warned with
noisy CMP0148 by cmake 3.27+, currently visible on Ubuntu 24.04 CI
runs).

It also stores its result as PYTHON_EXECUTABLE without a proper CACHE
type, which interacts badly with the Makefile's `cmake-cache-check`.
`cmake -L` skips UNINITIALIZED entries, so the
`-DPYTHON_EXECUTABLE=...` passed by the top-level Makefile is never
matched in the cache and every invocation forces a full reconfigure.

Switch to `find_package(Python3 COMPONENTS Interpreter REQUIRED)`,
then bridge to the legacy `PYTHON_EXECUTABLE` name that the rest of
the codebase still references.

Promote it to a CACHE FILEPATH entry so cmake -L lists it, preserving
any user-supplied value verbatim (find_package(Python3) canonicalises
e.g. bin/python3 to bin/python3.13, defeating a string-based cache
match).

Signed-off-by: Daniel Fanache <dan@rts.ro>

* fix(cmake): promote CONFIG to CACHE STRING for incremental builds

When CONFIG is passed via `-DCONFIG=...` on the cmake command line, it
is stored as an UNINITIALIZED cache entry. `cmake -L` skips
UNINITIALIZED entries by design, so the Makefile's
`cmake-cache-check` (which uses `cmake -L` to diff desired vs cached
options) never finds CONFIG in the output, concludes the cache is
stale, and triggers a full reconfigure on every `make <target>`
invocation.

If a config identifier is given, we force promote it to CACHE
STRING. This preserves the user supplied value as it was, while making
it visible to `cmake -L`, so the cache-check succeeds when nothing has
changed.

Signed-off-by: Daniel Fanache <dan@rts.ro>

* fix(cmake): track default.px4board as a configure dependency

Non-default labels merge `default.px4board` + `{label}.px4board` via
`merge_config.py`, but only the label file was listed as a configure
dependency. Changes to `default.px4board` were silently ignored until
a clean build, which is surprising and easy to debug for hours.

Register `default.px4board` as a CMAKE_CONFIGURE_DEPENDS in the
non-default-label branch so edits trigger reconfigure as expected.

Signed-off-by: Daniel Fanache <dan@rts.ro>

* fix(cmake): correct NuttX apps/library build dependency tracking

Three dependency graph defects in the libapps.a and per NuttX library
custom_commands caused either spurious full rebuilds or stale outputs
on incremental builds.

(1) `builtin_list.h` and `builtin_proto.h` are regenerated by the apps
build from `px4.bdat`/`px4.pdat` on every invocation. They were
included in `nuttx_apps_files`, so on each build we saw them as
changed inputs and re-triggered the apps target perpetually. Exclude
them with a `list(FILTER)`.

(2) libapps.a's custom_command lacked `px4.bdat`/`px4.pdat` as
dependencies, so module additions or renames (which regenerate those
registries) did not propagate to a rebuild of the builtin command
table. Add them to DEPENDS.

(3) NuttX's recursive make does not always notice that
`builtin_list.h` has been regenerated and that `builtin_list.c`
therefore needs recompiling. Touch `builtin_list.c` so NuttX's make
picks up the indirect change.

Additionally, drop the destructive cleanup COMMANDs that ran at the
start of libapps.a and each per-library custom_command (`remove
-f *.a`, `find ... -delete *.o`). These were workarounds for the now
fixed dependency tracking; without them removed, they would also force
unnecessary full rebuilds every time.

Signed-off-by: Daniel Fanache <dan@rts.ro>

---------

Signed-off-by: Daniel Fanache <dan@rts.ro>
Co-authored-by: Ramon Roche <mrpollo@gmail.com>
2026-05-17 12:23:24 -06:00
Julian Oes
1a3d232e7b fix(bootloader): remove broken PROTO_SET_DELAY boot-delay feature (#27081)
The bootloader boot-delay feature has been mechanically broken on
every modern FMU board since the STM32F7/H7 transition. It has three
independent bugs that prevent it from ever working:

1. Offset mismatch: BOOT_DELAY_ADDRESS is hardcoded to 0x1a0, but the
   NuttX vector table is 504 B (F76x) to 664 B (H743) long. The
   linker places _bootdelay_signature at ALIGN(32) past end of
   vectors (e.g. 0x2a0 on CubeOrange), never at 0x1a0. The bootloader
   reads random exception_common pointers in place of the magic and
   never matches BOOT_DELAY_SIGNATURE1/2. Verified on CubeOrange with
   objdump of cubepilot_cubeorange_default.elf.

2. Flash cache never flushes: fc_write() stores arbitrary writes in
   cache line 1 and only flushes on a very specific condition tied
   to the sequential firmware upload flow. A standalone write during
   PROTO_SET_DELAY is cached forever. fc_read() then returns the
   cached value, so the post-write verify lies and the bootloader
   reports success. Nothing ever reaches flash.

3. H7 write granularity: the STM32H7 flash controller requires a
   full 32-byte program cycle per write. Single 32-bit writes from
   flash_func_write_word() would not be accepted by the controller
   even if they reached it.

The feature has been silently dead on every H7/F7 FMU board for
years and no one noticed, which is strong evidence nothing actually
depends on it. Rather than fix it (which would mean rewriting
PROTO_SET_DELAY, the flash cache path, and the H7 flash programming
path), remove it.

Changes:
- bl.c: PROTO_SET_DELAY case now immediately NACKs (goto cmd_bad)
  so clients that still send the command get a clear rejection
  instead of the previous silent fake-success. The opcode stays in
  the protocol enum for backwards compatibility.
- bl.h: drop BOOT_DELAY_SIGNATURE1/2 and BOOT_DELAY_MAX.
- stm/stm32_common/main.c, nxp/imxrt_common/main.c: drop the
  startup boot-delay sig check block.
- image_toc.c: decouple find_toc() from BOOT_DELAY_ADDRESS.
  BOARD_IMAGE_TOC_OFFSET is now the required define when
  BOOTLOADER_USE_TOC is enabled. The body is wrapped in #ifdef
  BOOTLOADER_USE_TOC and falls back to a stub returning false when
  the TOC is not in use (no upstream board currently enables it).
- Linker scripts: strip EXTERN(_bootdelay_signature) and the
  FILL/. += 8 block from all 142 affected .ld files across boards/.
- hw_config.h: strip the #define BOOT_DELAY_ADDRESS and its comment
  block entry from all 48 affected boards.
- Tools/px4_uploader.py, Tools/teensy_uploader.py: remove --boot-delay,
  set_boot_delay(), and SET_BOOT_DELAY client-side counterpart.

Smoke-built on cubepilot_cubeorange_default and
cubepilot_cubeorange_bootloader; no link errors, no unresolved
symbols, flash usage unchanged.

Tested:
- New BL, new FW
- Old BL, old FW
- Old BL, new FW
- New BL, old FW
2026-04-29 13:04:03 +12:00
Julian Oes
0546d1c0e7 fix(nuttx): update for NAND bad block management (#27227)
This updates the NuttX submodule to enable the W25N's bad block
management.
2026-04-29 11:14:34 +12:00
alexcekay
ef531ab540 fix(nuttx): update submodule (fix SPI cache problem) 2026-04-24 13:22:14 +02:00
abhijithcv
0571bccda3 fix(imxrt): update arch defaults to match v6x 2026-04-21 22:26:04 +02:00
alexcekay
977cb5fe25 mtd: fix registration of multiple ONCHIP devices 2026-04-17 18:18:16 +02:00
Pavel Guzenfeld
02d9884979 refactor(io_timer): make timer_io_channels[].timer_channel 0-indexed (#26845)
* refactor: make timer_io_channels[].timer_channel 0-indexed

timer_channel was 1-indexed (1-4) to mirror STM32 hardware naming
(TIM_CH1-CH4), but this was purely cosmetic — the ccr_offset field
already handles register mapping. Every consumer did timer_channel - 1
to get a 0-based index, creating underflow bugs when the guard was
missing (e.g. dshot.c capture_complete_callback,
output_channel_from_timer_channel, up_bdshot_get_erpm).

Changes:
- STM32: Timer::Channel enum starts at 0, initIOTimerChannel assigns
  directly, removed all timer_channel - 1 in dshot.c and io_timer.c
- NXP (kinetis, s32k1xx, s32k3xx): removed the + 1 in
  initIOTimerChannel, removed timer_channel - 1 in io_timer.c,
  led_pwm.cpp, and input_capture.c
- RPI: Channel enum starts at 0, removed timer_channel - 1 in
  io_timer.c
- Validity checks updated from timer_channel <= 0 || >= 5 to
  timer_channel >= 4

Closes #26747

Signed-off-by: Pavel Guzenfeld <pavelgu@gmail.com>

* fix: complete 0-indexed timer_channel migration across all platforms

Address review feedback for incomplete migration:

1. STM32H7 io_timer_hw_description.h: update standalone
   initIOTimerChannel() to assign timer_channel from enum
   (0-based) instead of hardcoded 1/2/3/4

2. Switch case labels: update all switch(timer_channel) blocks
   from 1/2/3/4 to 0/1/2/3 in:
   - stm32_common: input_capture.c (4 blocks), led_pwm.cpp (3),
     io_timer.c DMA base register switch
   - kinetis: input_capture.c (2 filter blocks)
   - s32k1xx: input_capture.c (2 filter blocks)
   - spix_sync.c (ark/fpv + ark/pi6x, 3 blocks each)

3. Sentinel checks: replace timer_channel != 0 / == 0 (which
   now conflicts with valid channel 0) with gpio_out-based
   checks in:
   - io_timer_validate_channel_index() across all 5 platforms
   - led_pwm_channel_init() and led_pwm_servo_get() in all
     led_pwm.cpp variants (STM32 + 4 NXP)
   - spix_sync_channel_init() and spix_sync_servo_get()

Tested: px4_fmu-v6x_default (H7) build OK, px4_sitl_default
build OK, 154/154 unit tests pass, ASan build clean.

* fix: update NXP board led_pwm_channels to 0-indexed timer_channel

These 4 board files manually specify led_pwm_channels[] with
1-indexed timer_channel values. Since the platform code no longer
subtracts 1, decrement all values to match the new 0-indexed
convention.

* fix: correct FTM CH3 filter mask in kinetis and s32k1xx input capture

Case 3 in up_input_capture_set_filter() was using CH2FVAL_MASK/SHIFT
instead of CH3FVAL_MASK/SHIFT due to a copy-paste error, causing
channel 3 filter writes to modify channel 2's filter register instead.

---------

Signed-off-by: Pavel Guzenfeld <pavelgu@gmail.com>
Co-authored-by: Jacob Dahl <dahl.jakejacob@gmail.com>
2026-04-12 17:16:47 -08:00
Ashwani Sihag
b53036c2d7 fix(pr26902): scope cleanup and copyright attribution 2026-04-09 04:47:47 -04:00
Ashwani Sihag
ff31d5a04f boards: fix reviewer feedback for saampixv1_1 board
- Replace all MINDPX/MINDPXv2/PX4FMU board references with SaamPixV1_1
- Update Airmind Development Team to Saam Drones Development Team in copyright headers
- Update PX4 copyright year range to 2020-2026 on all C/C++ files
- Rename bootloader binary to match board version (v1_1)
- Remove untracked backup files
2026-04-09 04:47:47 -04:00
alexcekay
c0633d89ff nuttx: update littlefs to 2.11.3 and fix empty path EINVAL 2026-04-08 15:48:56 +02:00
alexcekay
c7295c8a4f mtd: add px4_at24c_set_npages API 2026-04-02 10:59:08 +02:00
Jacob Dahl
f00e46f618 feat(dshot): Extended Telemetry and EEPROM support
Overhauls the DShot driver with per-timer BDShot selection, multi-timer                                                                                                                                  
sequential capture, Extended DShot Telemetry (EDT), and AM32 ESC EEPROM                                                                                                                                  
read/write via MAVLink. Expands ESC support from 8 to 12 channels.                                                                                                                                       
                                                                                                                                                                                                   
BDShot:                                                                                                                                                                                                  
- Per-timer BDShot protocol selection via actuator config UI                                                                                                                                             
- Multi-timer sequential burst/capture on any DMA-capable timer                                                                                                                                          
- Adaptive per-channel GCR bitstream decoding                                                                                                                                                            
- Per-channel online/offline detection with hysteresis                                                                                                                                                   
                                                                                                                                                                                                   
Extended DShot Telemetry (EDT):                                                                                                                                                                          
- Temperature, voltage, current from BDShot frames (no serial wire)                                                                                                                                      
- New DSHOT_BIDIR_EDT parameter                                                                                                                                     
- EDT data merged with serial telemetry when both available                                                                                                                                              
                                                                                                                                                                                                   
AM32 EEPROM:                                                                                                                                                                                             
- Read/write AM32 ESC settings via MAVLink ESC_EEPROM message                                                                                                                                            
- ESCSettingsInterface abstraction for future ESC firmware types                                                                                                                                         
- New DSHOT_ESC_TYPE parameter                                                                                                                                                                           
                                                                                                                                                                                                   
Other changes:                                                                                                                                                                                           
- Per-motor pole count params DSHOT_MOT_POL1–12 (replaces MOT_POLE_COUNT)                                                                                                                              
- EscStatus/EscReport expanded to 12 ESCs with uint16 bitmasks                                                                                                                                           
- Numerous bounds-check, overflow, and concurrency fixes                                                                                                                                                 
- Updated DShot documentation
2026-03-17 16:38:33 -08:00
alexcekay
2450eb3d95 nuttx: update submodule (for PCF85263 compile fix) 2026-02-26 17:31:42 +01:00
Jacob Dahl
ce3e62841f module_base: remove CRTP template pattern to reduce flash bloat (#26476)
* module_base: claude rewrite to remove CRTP bloat

* module_base: apply to all drivers/modules

* format

* fix build errors

* fix missing syntax

* remove reference to module.h in files that need module_base.h

* remove old ModuleBase<T>

* add module_base.cpp to px4_protected_layers.cmake

* fix IridiumSBD can_stop()

* fix IridiumSBD.cpp

* clang-tidy: downcast static cast

* get_instance() template accessor, revert clang-tidy global

* rename module_base.h to module.h

* revert changes in zenoh/Kconfig.topics
2026-02-19 15:17:17 +13:00
Ramon Roche
a06f062bf7 nuttx: add nuttx_context dependency to jlink-nuttx build (#26505) 2026-02-16 20:04:06 -09:00
Julian Oes
833e4536b7 nuttx: add support for NAND flash
This cherry-picks upstream commits adding NAND flash support for the
Winbond W25N specifically W25N01GV chip.

NAND flash is used together with littlefs, hence I updated that to 2.5.1
to match upstream NuttX.
2026-02-10 15:23:51 +13:00
Julian Oes
9460625c99 Tools: rewrite uploader script (#26310)
* Tools: rewrite uploader script

This adds a script called px4_uploader.py which is a complete rewrite
using Claude Code of px_uploader.py.

The main improvements over the previous px_uploader.py script are:
- Separate smaller classes instead of one big uploader class.
- Easier debugging with --verbose or --debug flags.
- Nicer progress animation.
- No more hard to debug Exception swallowing over multiple levels.
- Auto-detection and looping of devices, removing the functionality from
  cmake.
- Auto-detection of PX4 devices by USB VID/PID.
- Add noninteractive mode
- Add JSON output mode
2026-01-24 11:09:17 +13:00
Phil-Engljaehringer
3438d593a1 drivers: MCP23009 & MCP23017 shared code base (#25924)
* Implemented driver for MCP23017

* fixed compatability with mcp23009. (naming of instantiated GPIO-Devices)

* removed some comments

* removed even more comments

* commented out instatntiation of driver since it will not be used with v6x

* removed last useless comments

* re-activated gpio_mcp23009 driver, removed useless comments and empty lines

* removed empty lines at the end of mcp23017.cpp

* removed empty line

* Implemented driver for MCP23017

* fixed compatability with mcp23009. (naming of instantiated GPIO-Devices)

* removed some comments

* removed even more comments

* commented out instatntiation of driver since it will not be used with v6x

* removed last useless comments

* re-activated gpio_mcp23009 driver, removed useless comments and empty lines

* removed empty lines at the end of mcp23017.cpp

* removed empty line

* basic working implementation

* first improved driver version with shared code base for MCP23009 & MCP23017 (built as state machine with sanity checks)

* removed unused imports

* changed module name from MCP to MCP230XX

* removed debug print statements

* adjusted auto start command of driver

* removed comments

* -added seperate main functions for both derivative modules (mcp23009 and mcp23017)

* compile common functions as shared library in src/lib/drivers

* fixed cleanup of modules

* ->unclean working version with shared common library

* used make format

* working & cleaned version

* -> Added CallbackHandler to be able to use multiple reading GPIO-expanders simultaneously
-> Removed old mcap23009 calls and pin registrations
-> Adjusted GpioIn.msg to contain MAX_INSTANCES

* ->removed unused imports
->used make format

* Fix: Re-enabled platform_mcp_gpio for accton-godwit, cuav, fmu-v5x

* Fix: enabled platform_mcp_gpio in px4/fmu-v5x

* added depency to fmu-v5x

* Fix: removed new lines

* Fix: fixed linker errors

* removed unused linkage against mcp-library

* Made mcp start calls consistent for fmu-v5x and fmu-v6x

* moved logging of comm errors to read/write function directly

* added perf_count for sanity_check

* removed error message

* ensured member variables follow naming convention

* added retries to probe function

* simplyfied state-logic

* add break to terminate loop early

* ensured clean state when register_gpios() fails

* add registered-flag to pins

* used path from top dir instead of relative path in CMakeLists

* used constexpr to set parameters instead of calculating them at runtime

* style: used make format

* fix: corrected i2c_bus assignment

* style: init input of callbackhandler to 0

* fix: mark pin as registered if successful

* style: made arguments const type

---------

Co-authored-by: Alexander Lerach <alexander@auterion.com>
2025-12-17 17:48:30 +01:00
Alexander Lerach
e822da74b2 io timer: fix input capture on various boards 2025-12-17 17:02:13 +01:00
Jacob Dahl
b92d21bd31 serial: add txSpaceAvailable function (#26069)
* serial: add txSpaceAvailable function

* serial: txSpaceAvailable and bytesAvailable fixups
2025-12-12 09:31:33 -09:00
Tarmo Tänav
f29aa182a8 Add support for NXP i.MX RT1170B 2025-11-26 09:59:51 -09:00
Alexis Guijarro
5f7e395609 NuttX: Add support for FM25V02A-DGQ 2025-11-24 10:37:45 -09:00
Peter van der Perk
921e91863a dshot: IMXRT BDSHOT baud training
AM32 bdshot doesn't do clock compensation like BLHeli32 did.
Instead we traing BDSHOT timing on known zero value to lock on
best bdshot baudrate to receive.

Reduces CRC and frame errors on AM32 a lot
2025-11-24 09:24:49 -09:00
Niklas Hauser
17f3db9231 [serial] Fix byte size, flow control, parity, stop bits configuration 2025-11-20 10:29:57 -09:00
Peter van der Perk
aaf6632a22 imxrt: move teensy bootloader to normal bootloader
Best for teensy is to use the teeny as normal bl
2025-11-10 00:52:58 -05:00
Jacob Dahl
38847b1cf3 stm32: io_timer: pullup gpio during dma capture (#25850) 2025-11-06 12:33:35 -07:00
Peter van der Perk
1250563ed1 Add support for NXP MR-VMU-Tropic board (#25845)
* rt106x: Use platform SPI hal layer

* rt106x: Add romapi support and reboot to isp/bootloader

* bootloader: imxrt_common: Add rt106x support

* NXP MR-Tropic initial commit

* Add missing file for mr-tropic bootloader

* nxp-mr-tropic:Bootloader Alow Assertion debugging & Keep Ram Vectors

* nxp-mr-tropic: Firmware Boot from bootloader

* nxp-mr-tropic:Add Bootloader bin file

* mr-tropic: Update config and linker

Fixes enet issues with write-back and some code cleanup.
Furthermore increase NOR LittleFS to 256kB to reflect on linker

* Update NuttX

* mr-tropic: fix itcm apping and add mr-tropic to itcm check

---------

Co-authored-by: David Sidrane <David.Sidrane@NscDg.com>
2025-11-05 11:48:26 -05:00
Thijs Hof
c44e0be18a fix bidir dshot for nxp xrt boards 2025-11-03 08:14:27 -09:00
Alexander Lerach
2e586c47b0 update nuttx (to include TX DMA fix) 2025-10-22 15:22:15 +02:00
Peter van der Perk
2f48cb4ef2 MR-CANHUBK344 NXP B3RB Rover support (#23897)
* s32k3xx: EMIOS allow independent frequencies for each channel

* mr-canhubk3: update config

* mr-canhubk344: Fix adap board detect

* mr-canhubk344: Use LPSPI1 (Port P1A) for SD card

* airframes: Add B3RB Ackermann rover config

See https://nxp.gitbook.io/mr-b3rb for more information about the NXP
B3RB platform. PX4 Support basic control for now
2025-10-09 23:28:43 -08:00
Henry Kotzé
dbd13070e5 esp32: pwm register updates correctly on change (#25653)
- removed the bug where some overflow would occur on the PWM signal when
  changing the duty cycle of the signal after power up. (PWM_MAIN_DIS,
PWM_MAIN_MIN or PWM_MAIN_MAX)

removed commented code

cleanup of previous cherry-pick

Co-authored-by: henrykotze <henry@autonosky.com>
2025-09-30 11:15:06 -08:00
Alexander Lerach
03e6f40995 nuttx submodule update (dcache fix)
* nuttx submodule update (dcache fix)
2025-09-29 18:04:26 +02:00
Alexander Lerach
0a8a5472ec nuttx submodule update (fix sem holder list) 2025-09-23 10:02:49 +02:00
Daniel Agar
d3f912ad25 platforms: Serial new dedicated writeBlocking method (#25537)
* platforms: Serial new dedicated writeBlocking method

* finish writeBlocking()

* add back fsync

* updated posix, added string constant for port not open error

* format

* fix build

* remove fsync

* actually remove fsync

* remove fsync from write

* review feedback

---------

Co-authored-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Co-authored-by: Jacob Dahl <37091262+dakejahl@users.noreply.github.com>
2025-09-15 15:22:49 -08:00
Jacob Dahl
1aad8b6ec9 serial: nuttx: revert tcdrain back to fsync (#25538)
* serial: nuttx: revert tcdrain back to fsync

* serial: do not print error on EAGAIN

---------

Co-authored-by: Alexander Lerach <alexander@auterion.com>
2025-09-11 12:32:34 -08:00
Alex Klimaj
af6bf931c1 uavcan bootloader watchdog_pet during long flashes (#25523) 2025-09-04 12:20:03 -08:00
henrykotze
8b58c01cd7 ESP32 Support Sponsored by AutonoSky
nsh console running on USB
param module running
working with i2c and common drivers
provided implementation for drv_pwm_output.h
i2cdetect working as expected with no device
mavlink started succesfully
mounts sd card and logger runs
logger to file succesfully
pwm_servo implemented without using Nuttx lib
pwm_out outputs expected waveforms
- however currently if the frequency is higher than what the pwm_out
driver runs, there will be aliasing, based on how the registers gets
resets
wifi softap working
- Seeing wifi hotspot
- cant connect due to wrong password
- problems with adjusting ssid and password
wifi ssid and password being set accordinglu
connected to wifi hotspot with dhpcd
- made some changes to nuttx to only build for SoftAP mode, however this
was effectivelyy removing the ifdef for STATION mode. Should investigate
the coexist option again
added ifdef to not use timer 0 when wifi enabled
- reverted esp32 rt_timer to make use of timer 0 by default

fix setting incorrect bit in hrt timer register

- hrt running as expected, but on startup the pwm_out driver starts up
at about 200Hz and then rises over a minute or so 250Hz. Not sure if
this was present previously, and could be due to Wifi running at time
priority on timer 0

pull xtensa compilers in setup.ubuntu.sh
revert logger stacksize and cmake argument
esp32 chip revision and PX4 UUID implemented

spi board reset implemented, formatting checked

devkit acts on startup as a wifi bridge for comms

- the most usefull setting for the general developer when buying a esp32 devkit
- testing Mavlink shell using ./Tools/mavlink_shell.py
- todo: Test mavlink messages being forward

improve wifi telemetry by increasing prio

- Remove power save mode on wifi
- increased daemon thread schedule priority to 50

compiles without Nuttx changes

- updated compiler settings to match those of nuttx on px4 side

add espressif_esp32 to excluded boards

ci: allow docker to find xtensa compilers
2025-08-19 11:09:56 -07:00
alexklimaj
bc60307163 boards: ARK DIST 2025-08-07 21:26:13 -04:00
Jacob Dahl
b5bf28c204 platform: serial: add bytesAvailable() function 2025-07-29 09:07:03 -08:00
Sindre Meyer Hegre
3be0cb077c Neural Control Mode (#24366)
* Add tflm to px4 with module

 - Add TensorFlow Lite Micro(TFLM) as a library in px4
 - Make a module that uses neural network inference for control, which uses TFLM for inference
 - Make board config files for PX4 with neural module

* Added neural flight mode

* Add posibility to read of inference times

* Fix comments from review:

- Switch ssh link to https link in submodule
- Remove mc_nn_control from startup

* Add tflm to px4 with module

 - Add TensorFlow Lite Micro(TFLM) as a library in px4
 - Make a module that uses neural network inference for control, which uses TFLM for inference
 - Make board config files for PX4 with neural module

* Added neural flight mode

* Add posibility to read of inference times

* Remove auto start

* Add logging from neural control module

* Fix automatic startup to only be when module is included

* Switch to flight mode registration

* Add docs

* Change min/max/coeff to actual parameters

* add figures to neural network docs

* Switch to e2e network

* Remove toolchain changes and replace with instructions in docs

* Get ready for merge after toolchain upgrade

* switch back to submodule

* Try to figure out cmake

* Get CI working with new toolchain

* Remove fork dependency

* Finalize PR

* fix toolchain inclusion

* Fix ctype_base.h include

* Cleanup includes for TFLM

* Remove redundant std

* Update FW module names in board files

* Fix docs

* Remove cstdlib copy

* Copy header from nuttx

* Prettier, markup, layout

* NeuralControl.msg - update uorb comments to current standard

* Add description to neural topic

* Fix typo

* Typo

* TFLM and Module utitlities

* Neural networks top level

* Update docs

* Add manual control

* Update docs

* Revert the manual control attempt

* Update docs/en/advanced/nn_module_utilities.md

* Add posibility to set trajectory setpoint with manual control

---------

Co-authored-by: Pedro Roque <padr@kth.se>
Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
Co-authored-by: Ramon Roche <mrpollo@gmail.com>
2025-07-25 09:42:12 -08:00
Pedro Roque
6474e5d7c1 feat: configurable board pwm freq from Kconfig (#24787)
* feat: configurable board pwm freq from Kconfig

* feat: add board_pwm_config to submenu

* fix: define sequence correction

* fix: revert Tools/simulation/gz

* fix: track upstream gz

* fix: track upstream mavlink

* feat: adjustable pwm for multiple board types

* feat: add conditional check for CONFIG_ for correct fallback

* add: spacecraft board with correct BOARD_PWM_FREQ supporting 10Hz actuation rate

* fix: set dependencies for submenu arch chips

* fix: keep only upper arch level

* fix: proper checking - still not showing up for board config

* feat: add hidden kconfig for platforms

* Merge Nuttx config into px4board

Allows to expose nuttx into PX4 if needed

* Kconfig: Include nuttx symbols in updateconfig

Only if applicable i.e. defined in the kconfig

* fix: merged config with previously generated boardconfig

* doc: updated code comment

---------

Co-authored-by: Daniel Agar <daniel@agar.ca>
Co-authored-by: Peter van der Perk <peter.vanderperk@nxp.com>
2025-07-23 08:23:13 -07:00
dusan19
8dd14d9aaa platforms/stm32_common: hrt.c: define timer 1 IRQ properly for H7 platform (#25260) 2025-07-21 09:53:38 -08:00
Jacob Dahl
09ebd21e55 mixer: remove used flag stop_outputs
dshot: fix motor test on CANnode

Also includes fixes for the DShot driver since stop_outputs is removed. The esc info command has been removed because it doesn't work with AM32, can only be used via command line, and complicates the driver
2025-07-11 08:53:52 -06:00
Jacob Dahl
bb423bc007 dshot: fix bidirectional dshot stream sharing (#24996)
Freeing the DMA stream in the hrt callback causes other peripherals on that DMA controller to lock up (namely GPS). Moving the free back into thread context, right before allocation, solves the problem
2025-06-10 00:36:45 -08:00
Jacob Dahl
6e7638c14b dshot: fix scaling (#25001) 2025-06-10 00:26:17 -08:00
Jacob Dahl
64989c3b8d dshot: add perf counter for hrt callback (15us avg) (#24976) 2025-06-05 14:45:28 -08:00