Each default driver instantiation emits the same allocation and initialization failure handling. Share that code outside the template while keeping init() resolved on the concrete driver. Allocation failures are now logged under SPI_I2C.
Extracted from Balduin (mbjd) in PX4/PX4-Autopilot#27816, commit 8a2391730f.
Assisted-by: Codex
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Co-authored-by: Balduin <balduin@auterion.com>
Include PX4/NuttX#418 so the IMXRT and STM32 Ethernet drivers report
IFF_RUNNING through netdev_carrier_on/off(). The Zenoh startup check
relies on these interface flags.
Assisted-by: Codex:gpt-6-astra
Signed-off-by: YG_Kim <yeogyeom1@naver.com>
Provide a supported Jazzy environment for SIH/Gazebo development and source builds, with pinned tooling and reproducible multi-architecture image publishing. Separate package and container assets from ROS source preparation, and keep checkout workspaces fresh through a Python CLI.
Assisted-by: Copilot:gpt-6-astra
On NuttX these are two things: / is the filesystem root, and /fs/microsd is the
SD card mounted under it. MAVLink FTP serves the root and confines writes to the
SD card, so the read-only ROMFS at /etc is visible but cannot be written.
On POSIX they were the same directory. PX4_ROOTFSDIR and PX4_STORAGEDIR both
resolved to CONFIG_BOARD_ROOT_PATH, which on SITL is ".", so the working
directory was simultaneously the FTP root and the only writable area. The
consequences were that the ROMFS symlink sat inside the FTP root, and that
_validatePathIsWritable() had nothing meaningful to check against and so was
compiled out on POSIX entirely, leaving no write restriction at all.
Give POSIX the same split. CONFIG_BOARD_ROOT_PATH keeps its meaning as the
storage directory, and a new CONFIG_BOARD_FS_ROOT_PATH names the root FTP
serves, defaulting to the storage path so every existing board is unchanged.
SITL sets the root to "." and storage to "./fs", which mirrors NuttX: logs,
parameters, dataman and eeprom move under ./fs, and etc/ stays in the root as
read-only data.
With storage distinct from the root, the write restriction now applies on every
platform rather than NuttX only, and no longer compares against a hardcoded
prefix length that was wrong for any board not using /fs/microsd.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Julian Oes <julian@oes.ch>
Every PHY register access on STM32H7 spent 5 ms in up_mdelay(), so the
boot-time autonegotiation link wait ran netinit at 44% CPU for 65 s with
the net lock held whenever no ethernet cable was attached (PX4/NuttX#414,
apache/nuttx#20067). Also picks up the two upstream stm32_mdio fixes for
the lower-half cast and the Clause 22 write register field.
* fix(can-flow-mr): use STM32F412VG and 960K of app flash
The part is STM32F412VGH6 (100-pin, 1MB), not the 48-pin 512KB CE.
App flash starts at 0x08010000 after the 64K bootloader+params window,
so the region is 960K, not 928K.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(boards): select STM32F412VG on the 100-pin 1MB ARK cannodes
Teseo, X20, F9P, and Septentrio/MOSAIC/G5 GPS modules use
STM32F412VGH6, same as Flow MR. They were still selecting the
48-pin 512KB CE and a 928K app region that double-counted params.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/cannode): use STM32F412CG and 960K of app flash
The part is STM32F412CGU6, not the 512KB CE. App flash starts at
0x08010000 after the 64K bootloader+params window, so the region is
960K, not 928K.
* fix(ark/mag): use STM32F412VG and 960K of app flash
The part is STM32F412VGH6, not the 48-pin 512KB CE, and the app region
after the 64K bootloader+params reservation is 960K, not 928K.
* docs(boards): fix the F412 SRAM description in the cannode linker scripts
The F412 has one contiguous 256KB SRAM at 0x20000000. The block list
these scripts carried is F42x boilerplate and describes memory the part
does not have.
* fix(ark/dist): use STM32F412VG and 960K of app flash
The part is STM32F412VGH6, not the 48-pin 512KB CE. App flash starts at
0x08010000 after the 64K bootloader+params window, so the region is
960K, not 928K.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(boards): give F412 cannodes a 256K SRAM region (#28498)
NuttX now ends the F412 heap at 0x20040000. The linker scripts still
capped .data/.bss at 192K, leftover from the F42x split.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(boards): fix the F412 SRAM description on the 512K ARK cannodes
The F412 has one contiguous 256KB SRAM at 0x20000000. The block list
these scripts carried is F42x boilerplate and describes memory the part
does not have.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/cannode): drop the PH1 boot jumper defines
PH1 is OSC_OUT for the HSE crystal. The jumper option was already
undefined, so these defines could not be enabled without stopping
the clock.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(boards): correct ARK cannode I2C bitbang pins
The bitbang GPIO defines did not match the schematic nets, so a bus reset would drive the wrong pins.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Advance the NuttX submodule from 1db7c59 to the fork branch tip
f07832f0 (px4_firmware_nuttx-12.12.0+), pulling in three backports:
- FlexCAN: store the TX deadline only once the frame is sent
- FlexCAN: assign MAXMB rather than OR-ing it in
- STM32F412: set SRAM1_END to 256KiB (#407)
The two FlexCAN backports are the apache/nuttx#19970 follow-ups the
branch was missing; they land the corrected i.MX RT TX-abort behavior.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Assisted-by: Claude:claude-fable-5-1
* fix(uavcan): apply UAVCAN_BITRATE on FlexCAN again
58dfff0de7 turned the SIOCSCANBITRATE path off for i.MX RT, S32K and Kinetis,
which is every board in the tree that builds SocketCAN, so UAVCAN_BITRATE
stopped doing anything at all. It was written before db6f7ec304, and the crash
it works around is that commit's bug: the driver reports bit/s on NuttX 12 and
the caller still divided by 1000, so a 1 Mbit/s board asked its controller for
1000 bit/s on every boot.
Benched on an ARK FMU-v6XRT with the gate removed: 1 Mbit/s -> 500 kbit/s ->
1 Mbit/s round-trips with both DroneCAN nodes coming back OPERAT, buses
error-active, no fault. Requesting a rate the controller cannot reach is also
survivable now -- it is reported and the configured rate is kept, where before
a negative return from here made CanDriver::init() give up and DroneCAN never
started.
The %u for a uint32_t is fixed as well; nothing compiled this branch while the
gate was in place.
* fix(work_queue): size the uavcan and TTY work queues for NuttX 12
NuttX 12.12 costs a few hundred bytes of stack on the paths that go through
the file layer, and that is more than these two defaults left spare. Measured
against the same PX4 tree on 10.3.0:
wq:uavcan 2860/3728 -> 3184/3736 (ARK FMU-v6X, two DroneCAN GNSS nodes)
wq:ttyS4 1088/1704 -> 1432/1712 (ARK FMU-v6XRT, crsf_rc)
load_mon reports wq:ttyS4 low on stack with 280 bytes left, and wq:uavcan sits
at 85 % of its own. 4096 and 2048 restore the margin the 10.3.0 figures had.
The fix is upstream as f20cf4aac3 but landed after the 12.12.0 tag, so
moving the submodule onto 12.12.0 dropped a fix the previous branch
already carried. Backport it.
Without it the group address in the IGMP header, a uint16_t[2] that decays
to a pointer, is compared against INADDR_ANY, which is always false. A
General Query then falls through to the group-specific branch, a group is
allocated for 0.0.0.0, and joined groups never have their report timers
restarted, so the querier ages out the membership and multicast delivery
to the device stops.
CONFIG_NET_IGMP is enabled on ark/fmu-v6xrt, px4/fmu-v6xrt,
nxp/mr-canhubk3, nxp/mr-tropic and nxp/tropic-community.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Julian Oes <julian@oes.ch>
NuttX 12.12.0 added arm_initialize_stack(), which moves thread mode onto
the process stack pointer whenever CONFIG_ARCH_INTERRUPTSTACK > 7. Every
bootloader config qualifies, so the bootloader now reaches arch_do_jump()
with CONTROL.SPSEL set, where previously it ran on the main stack.
arch_do_jump() writes the MSP and branches, but never selects it. The
application therefore starts on the bootloader's PSP while its own startup
code initialises a stack pointer the CPU is not using. Boards booted far
enough to reach NSH and start MAVLink, then hard faulted once the stale
bootloader stack was overwritten, surfacing as an assertion in Idle_Task
with no useful backtrace.
Clear CONTROL.SPSEL so control passes on the stack the application expects.
The i.MX RT bootloader performs the same jump and its configs also exceed
the interrupt stack threshold, so fix both.
Verified on CubePilot CubeOrange and Pixhawk 6C; the prebuilt bootloaders
for both are regenerated, as the shipped binaries have the defect.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Julian Oes <julian@oes.ch>
NuttX 12.12.0 shares one statically allocated g_kthread_group between all
kernel threads, but group_leave() guards the group_release() call behind
HAVE_GROUP_MEMBERS, which is only defined when pthreads are enabled. Every
bootloader config sets CONFIG_DEFAULT_SMALL=y, so DISABLE_PTHREAD defaults
to y, and the first kernel thread to exit tears down the shared group and
calls kmm_free() on a .bss static. The bootloader died before USB
enumeration. Around 64 configs in the tree share that combination.
The submodule now carries the upstream fix, apache/nuttx f20f9ff19e.
The bump also picks up the backport that recombines the per-command CAN
ioctl Kconfig options back into NETDEV_CAN_IOCTL. Defconfigs on this branch
already reference CONFIG_NETDEV_CAN_IOCTL, which does not exist at the
previously pinned commit, so SocketCAN bitrate, filter and state ioctls
were silently disabled on ark/fmu-v6xrt, px4/fmu-v6xrt, nxp/mr-canhubk3,
nxp/tropic-community and nxp/mr-tropic.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Julian Oes <julian@oes.ch>
Main removed this file in f05739035e (#28185) when USB autostart moved
into the cdcacm_autostart driver. The NuttX upgrade rebase brought back
a NuttX 12 adaptation of it, but nothing references it in any build
file, so it is 370 lines of dead code.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The mcp_gpio_dev_s / gpio_pin_dev_s struct layout changed in NuttX
12.12, so use designated initializers (.gp_pintype/.gp_ops) instead of
positional initialization.
Co-authored-by: marinauterion <224611774+marinauterion@users.noreply.github.com>
Signed-off-by: Peter van der Perk <peter.vanderperk@nxp.com>
Upgrading the NuttX apps submodule (kernel bump or switching branches then
`git submodule update`) updates tracked files only. When the new revision
removes an application directory, the autogenerated Kconfig a previous build
left inside it is untracked, so it survives `git clean -dX`. mkkconfig.sh keeps
globbing that orphaned `*/Kconfig`, whose stale `source` points at a file that
no longer exists, breaking `make olddefconfig`:
olddefconfig: apps/gpsutils/Kconfig:9: 'apps/gpsutils/minmea/Kconfig' not found
Add a `cmake -P` helper, invoked at the end of the `clean` target, that walks
the apps Kconfig graph and removes only untracked Kconfig files that source a
missing path. Tracked files and the nuttx tree (whose stale artifacts are all
gitignored and already dropped by `git clean -dX`) are never touched, so a
`make clean` before rebuilding now migrates cleanly across the upgrade.
Assisted-by: Claude:claude-opus-4.8
Signed-off-by: Peter van der Perk <peter.vanderperk@nxp.com>
bootloader: update main prototype for NuttX 12.12.0
platforms/nuttx: Add wrapper for queue.h
For some reason the queue.h header was moved, add this wrapper so
posix and nuttx builds can both still use #include <queue.h>
Fix print_load to be compatible with upstream NuttX
Also Change tg_filelist -> tg_fdlist as per new NuttX
Co-authored-by: Ville Juven <ville.juven@unikie.com>
Signed-off-by: Jukka Laitinen <jukkax@ssrc.tii.ae>
* fix(dshot): emit the DShot rate that was asked for on STM32
io_timer_set_dshot_burst_mode() wrote the tick count into ARR, but an STM32 timer
period is ARR + 1 ticks, and the prescaler divided by that same tick count. Every
bit came out one tick long, so the output ran at 21/20 of the requested rate and
the 7/14 compare counts -- betaflight's, where the period really is 20 ticks --
landed on 21 and gave 33.3 %/66.7 % instead of the protocol's 37.5 %/75 %.
Measured on an ARK FMU-v6X (240 MHz timer, BDShot300) with a logic analyser:
bit period 3.500 us (+5.00 %) -> 3.333 us (-0.01 %)
bit 0 high 33.2 % -> 37.3 %
bit 1 high 66.5 % -> 74.9 %
Subtracting one from ARR alone is not enough. A tick count fixed at 20 (19, 18)
cannot divide every timer clock by every rate: 200 MHz at DShot600 would go from
+0.80 % to -4.00 % and 90 MHz from -2.00 % to -6.67 %. Choose the tick count and
the prescaler together instead, scoring the emitted rate first and the two high
times second, and derive the compare counts from the tick count that wins. That
is exact on 84, 90, 96, 108, 168, 180, 216 and 240 MHz at all three rates, and
within 0.25 % on 160 MHz and 0.80 % on 200 MHz, where no integer pair is exact.
The search only depends on the timer clock and the rate, so io_timer.c caches its
answer per timer and recomputes only if the rate changes, which is once. That
leaves the transmit path with no arithmetic at all where it previously ran a
modulo loop and two divisions on every burst and every capture.
The capture prescaler comes out of the same struct and no longer follows the
transmit tick count. It only sets the resolution of a free-running counter, so it
aims for a fixed 20 ticks per response bit, which is what keeps a one-to-three bit
run inside the interval window convert_edge_intervals_to_bitstream() accepts.
* fix(dshot): search up to 40 ticks per bit and keep the search in 32 bits
333 cycles per bit (200 MHz at DShot600, 100 MHz at DShot300) is 9 x 37, so a
ceiling of 32 ticks left those clocks at 0.79 % when 37 x 9 lands within 0.10 %.
The wider range also moves the clocks that were settling on a 39-40 % bit-0
duty onto 37.5 %.
The rounded prescaler keeps ticks * prescaler * rate within half a bit of the
timer clock, so the 64-bit compare bought nothing. The timing cache now starts
on a rate nobody asks for, so its zero-rate guard is reachable instead of
returning a zeroed struct.
Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(uavcan): report FlexCAN bus state and error counters on SocketCAN
The SocketCAN platform driver returned 0 from getErrorCount(),
getRxQueueOverflowCount() and isInBusOffState(), so a controller sitting
error-passive or bus-off was invisible from `uavcan status` and the
can_interface_status topic on every i.MX RT board. Read them through
NuttX's SIOCGCANERRORS instead, and print fault confinement, TEC/REC and
RX overruns per interface. Builds without the ioctl keep the old zeros.
* fix(uavcan): apply UAVCAN_BITRATE on SocketCAN
CanDriver::init() ignored its bitrate argument, so the controller stayed
at the Kconfig rate and a bus configured for anything but 1 Mbit/s never
came up. Program the nominal rate through SIOCSCANBITRATE when it differs
from what the driver reports, keeping the data-phase settings untouched.
The driver applies the timing at the next ifup, so the interface is taken
down around the request. Older PX4/NuttX restarted a running controller
from inside the ioctl instead, which on FlexCAN with ECC RAM
initialisation is a bus fault; against that NuttX the rate is left as
configured with a warning.
* fix(boards): switch SocketCAN defconfigs to NETDEV_CAN_IOCTL
PX4/NuttX#401 merges the per-command CAN ioctl options into a single
NETDEV_CAN_IOCTL, so the old BITRATE/FILTER/ERROR names no longer
exist there and would be silently dropped, disabling the whole CAN
ioctl block. Requires the NuttX gitlink to include PX4/NuttX#401;
until that bump the option is dropped against the old tree and the
bitrate/error ioctls are inert at runtime (the code builds either
way). mr-canhubk3 is included so its bitrate ioctl survives the bump.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* chore(nuttx): bump NuttX to the px4_firmware_nuttx-10.3.0+ tip
Picks up PX4/NuttX#401 so SIOCGCANERRORS, SIOCSCANBITRATE-requires-ifdown
and NETDEV_CAN_IOCTL are in the tree the SocketCAN changes need. Also
includes PX4/NuttX#399 (STM32F412VG/CG chip selections), which landed
between main's gitlink and #401.
Assisted-by: Grok:grok-4.6
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Picks up PX4/NuttX#402, where memmem() missed a needle that ends the
haystack, and a configurable STM32 Ethernet TX watchdog timeout whose
default is the 60 s the drivers hard-coded before.
* ARKV6X-RT Initial Commit
* icm45686 yaw 270
* iis2mdc yaw 180
* fix(ark/v6x-rt): wrap FLASH_END macro body in parentheses
Fixes clang-tidy bugprone-macro-parentheses.
Signed-off-by: alexklimaj <alex@arkelectron.com>
* update(ark/v6x-rt): modify bootloader binary for enhancements
* feat(ark/v6x-rt): enable LSM6DSV80X IMU on SPI3
Enable the lsm6dsv driver, register the SPI3 chip select with the
LSM6DSV devtype, and start the driver with -T 80 to select the
LSM6DSV80X high-g variant (shared WHO_AM_I 0x73).
Signed-off-by: alexklimaj <alex@arkelectron.com>
* feat(ark/v6x-rt): start IIM-20670 IMU on SPI2
Rotation verified on bench (yaw 90). The driver comes with PX4 PR
Signed-off-by: alexklimaj <alex@arkelectron.com>
#27624; until it merges the start call fails harmlessly at boot.
* fix(ark/v6x-rt): correct SPI3 DRDY2 pin, clang-tidy parens, cleanup
- GPIO_SPI3_DRDY2_SENSOR3 pointed at GPIO_EMC_B2_09 (the buzzer pin); corrected to GPIO_EMC_B2_18 / GPIO2_IO28 per schematic
- parenthesize BOOT_DEVICES_SELECTION / BOOT_DEVICES_FILTER_ONUSB macro bodies (clang-tidy bugprone-macro-parentheses)
- set board_id / BOARD_TYPE to 62
- remove unused ENET INT/RST GPIO macros copied from fmu-v6xrt
- remove duplicate GPIO_VDD_3V3_SENSORS4_EN init-list entry and Configuration banner
- rename fmuv6xrt_* board functions, file headers, include guards, and Kconfig symbols to ark/v6x-rt
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* rename v6x-rt to fmu-v6xrt
* feat(ark/fmu-v6xrt): build the IIM-20670 driver for the SPI2 IMU
rc.board_sensors already starts iim20670, but the Kconfig symbol was left
as a TODO placeholder because the driver was not in tree yet, so the SPI2
IMU never came up. The driver exists now.
Depends on #27624 - the symbol is unknown to Kconfig until that merges.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): declare the IMXRT chip in the board config
Without it Kconfig falls back to ARCH_CHIP_UNSET and every configure warns
"ARCH_CHIP_UNSET was assigned the value 'y' but got the value 'n'".
Cosmetic only - the real chip selection comes from the NuttX defconfig via
CONFIG_ARCH_CHIP_MIMXRT1176DVMAA, and the image is byte-identical either
way. px4/fmu-v6xrt and nxp/tropic-community already declare it.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(ark/fmu-v6xrt): calibrate FlexSPI DLL read strobe at boot
Port of PX4/PX4-Autopilot#28141 (9f4bc80006), which landed on px4/fmu-v6xrt.
The two init.c files were otherwise identical apart from board-specific
names, so this takes the change unmodified.
Corrects the ROM-provided DLL delay by finding the valid DQS sampling range
and selecting its midpoint, for reliable octal-DDR flash reads.
* fix(ark/fmu-v6xrt): declare the SPI2 IMU as an IIM-20670
The LPSPI2 entry still carried the ICM45686 devtype placeholder from before
the driver existed. SPIBusIterator matches a driver to a bus device on
devtype_driver, so iim20670 found no instance and the SPI2 IMU never came up
even with the driver built in.
Depends on #27624 for DRV_IMU_DEVTYPE_IIM20670, same as the Kconfig symbol
already enabled here.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): enable the INA226 by default
rc.board_sensors only starts a power monitor explicitly when one of the
SENS_EN_INA* params is set, and otherwise falls back to i2c_launcher
autostart. With SENS_EN_INA226 left at its 0 default the board always
took the fallback, which never produced a working instance, so the
board had no battery monitor at all.
ark/fmu-v6x already sets this. Verified on hardware: started this way
the INA226 on I2C1 0x41 reads 15.998 V against a 16.007 V bench supply.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): correct the zero-padded DRDY pin macros
GPIO_PIN05 and GPIO_PIN07 do not exist - the NuttX imxrt pin macros are
not zero padded (GPIO_PIN5, GPIO_PIN7). Three DRDY definitions named
them, so any translation unit that expanded GPIO_SPI2_DRDY1_SENSOR2,
GPIO_SPI6_DRDY1_EXTERNAL1 or GPIO_SPI6_DRDY2_EXTERNAL1 would fail to
compile.
Nothing expands them today: the SPI bus description in spi.cpp carries
its own port/pin pairs, and the only other reference is
GPIO_DRDY_OFF_SPI6_DRDY2_EXTERNAL1, which is itself unused. That is why
this has gone unnoticed. Found by writing a bench command that did use
them.
boards/px4/fmu-v6xrt/src/board_config.h has the same three typos and
needs the same fix separately.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(ark/fmu-v6xrt): document the board's architecture and SWD flashing
The RT1176 has no internal flash and boots XIP from an external octal NOR
via a boot ROM that reads an FCB and IVT out of the image, which is enough
unlike an STM32 that the flashing procedure looks arbitrary without it.
Covers the differences, the dependencies, and the verified pyocd sequence
for the bootloader and the application.
* feat(ark/fmu-v6xrt): build the heater driver and regulate on the LSM6DSV80X
The heater (R34/Q1 on GPIO2_IO27) is populated and plumbed in
board_config.h but the driver was never built, so the IMUs ran at
ambient. The LSM6DSV80X publishes its high-g channel, whose zero-g
level moves 2 mg/degC (DS14764 Table 3) - an 0.8 m/s^2 walk over a
40 degC swing, enough to trip the accel consistency check - so bind
the heater to that sensor. HEATER1_TEMP stays at the driver default.
* fix(ark/fmu-v6xrt): place SubscriptionIntervalBase in ITCM
The ITCM include list still named uORB::SubscriptionInterval::{updated,copy},
which stopped existing when those methods moved onto SubscriptionIntervalBase<Lb0/Lb1>.
The wildcards fail open, so the two hottest uORB copies ran XIP instead of ITCM.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): float SPIX_SYNC so it cannot fight LSM6DSV INT2
The MCU pin was driven push-pull high into LSM6DSV80X INT2, which idles
low and is active-high. Same net as ark/fmu-v6x, which leaves the pad
as an input with pulldown.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): complain when the IMU hwtype is unknown
The three internal IMUs only start on ARKV6XRT000. A future FMUM id
would previously boot with mag and baro only and no indication why.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): default RC to CRSF on the RC port
COMMON_RC already builds the per-protocol UART drivers, but none of
them were bound to a port, so there was no RC until a user set
RC_*_PRT_CFG. Bind CRSF to the RC serial (300) and leave the
auto-detect rc_input driver out — PPM/DSM-bind is not wanted here.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(ark/fmu-v6xrt): enable SPARTN framing and PPS capture
Parity with ark/fmu-v6x: build the GPS SPARTN framer so PointPerfect
corrections can be injected, and include pps_capture so a mixer
PPS_Input pin can timestamp GNSS TIMEPULSE.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): drive panic LEDs from the real phy_set_led
autoleds.c defined board_autoled_on/off against a local empty
phy_set_led stub because the real one in led.c was static, so
NuttX PANIC/ASSERT never lit an LED. Fold the autoled hooks into
led.c, matching ark/fmu-v6x.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* chore(ark/fmu-v6xrt): drop leftover Kinetis and unused board symbols
automount.c is still the FMUK66 SD automounter and is compiled out.
GPIO_PWM_IN names a pinmux that does not exist, PX4_I2C_BUS_MTD
contradicts mtd.cpp, the Boot Flash Kconfig choice is unread, and
the RUNFROMISRAM copy in imxrt_ocram_initialize.c does not compile
on this XIP board. Also point HW_REV/VER_SENSE at the ADC channels
they actually sample and fix the USDHC pin table.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* perf(ark/fmu-v6xrt): grow the logger RAM buffer to 128 KiB
The imxrt arch default is 64 KiB and the logger already sat at 96 % of
that at rest. The RT1176 has megabytes of OCRAM; another 64 KiB of
ring buffer is cheap insurance against SD write dropouts in flight.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(ark/fmu-v6xrt): publish LPUART11 as the EXT2 serial port
LPUART11 is built as /dev/ttyS7 and brought out on the PAB UART4 pins.
Without CONFIG_BOARD_SERIAL_EXT2 the device node exists but nothing can
bind a protocol to it from the serial-port params.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): enable 64-bit off_t so SD files can exceed 2 GiB
Without CONFIG_FS_LARGEFILE, off_t is 32-bit: a single ULog cannot
cross 2 GiB and df/ls wrap on cards larger than 4 GiB. px4/fmu-v6xrt
gained this in 05be273a35; the ARK defconfig was forked before that.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): sync the FRAM MTD driver and actually erase it
The local copy never advanced the bwrite source, so a multi-page
param save repeated the first 128 bytes, and lacked the word-aligned
bounce buffer from e8a4304e1c. Pull those in from px4/fmu-v6xrt.
Erase was still wrong in both trees: `uint8_t buf[128] = {0xff}` only
sets byte 0, and BULKERASE issued one WREN for 256 page programs.
WEL clears after each write, so only page 0 was programmed. memset
0xff and WREN per page so `mtd erase` blanks the store.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): match ark/fmu-v6x UART buffer sizes
TELEM2 (LPUART8) and EXT2 (LPUART11) were on the NuttX 256 B default.
Copy the v6x sizes by port: console 180/1500, GPS1 TX 1500, TELEM2 RX
800, EXT2 600/1500.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): keep UAVCAN off CAN3, ESC on CAN2 only
PAB pinouts CAN3 but no ARK carrier breaks it out. FlexCAN3 stays built so a different carrier can bring can2 up.
Assisted-by: Grok:grok-4.6
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): drop i2c_launcher
SENS_EN_INA226 is defaulted on, so the auto-detect fallback is unused. Start INA from the param only, like ark/fmu-v6x.
Assisted-by: Grok:grok-4.6
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): keep SENSORS4 up and float BMP INT
SENSORS4 is the BMP390 analog rail, not the SE051. Cycling it off
while VDDIO (FMU_3V3) stays up skips POR. Leave it on after the
first enable. Configure I2C2_DRDY1 as a floating input; INT idles
push-pull low and is unused by the driver.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): start the IIM-20670 last
Sensor instances follow start order, and at equal priority the voter
keeps the lowest instance, so whichever IMU starts first is the primary
by default. The IIM-20670's gyro filter cannot be opened past 60 Hz,
which is several milliseconds of delay ahead of the rate loop; it is a
fallback, not a primary. Start the ICM-45686 first and the LSM6DSV80X
ahead of it.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(rt117x): define PX4_MAKE_GPIO_EXTI
pps_capture builds its GPIO with PX4_MAKE_GPIO_EXTI, which only the
STM32 micro_hal defines. On i.MX RT an EXTI pin is just an input that
imxrt_gpiosetevent() attaches to, so it is the plain input pinset. Needed
for CONFIG_DRIVERS_PPS_CAPTURE on ark/fmu-v6xrt.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* build(ark/fmu-v6xrt): state CONFIG_IMXRT_USDHC_DMA in the defconfig
It is the Kconfig default, so it was already on, but nothing in the
board tree said so and the question of whether SD ran PIO came up twice.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* build(ark/fmu-v6xrt): give the logger a 5000-byte stack
High-water 3092 of 3608 with the logger at 368 KiB/s, the tightest task
on the board. The RT1176 has 1.7 MB of SRAM to spend.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(ark/fmu-v6xrt): add an IMU section to the README
Bus, start line, ODR, publish rate and full-scale per IMU, why the
publish rates differ, why the instances are ordered as they are, and the
two caveats that lived only in driver comments and PR text: the
LSM6DSV80X publishing its high-g channel, and the IIM-20670's 60 Hz
gyro filter.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(ark/fmu-v6xrt): call out the LSM6DSV80X offset temperature coefficient
The heater exists for this die: its high-g zero-g offset moves ~2 mg/degC, so an accel calibration only holds at the temperature it was done at. Say so, and that calibration and flight both happen with the heater at its setpoint.
* docs(ark/fmu-v6xrt): add the ARKV6X-RT flight controller page
The target shipped with no user-facing page, so it was also absent from
the supported-hardware, PAB-compatible and Ethernet board lists.
Photo, store URL and the mechanical/electrical specs still need to come
from ARK.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(ark/fmu-v6xrt): restructure the page to the current board-doc shape
The docs maintainer has been asking every recent board PR for the same
things: a Specifications block, a flow-control column on the serial
table, and Power, PWM Outputs, Radio Control, GPS & Compass and Debug
Port sections with anchors. Match that rather than the older ARKV6X
page, which predates it.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(ark/fmu-v6xrt): mark the unpublished specs with TODO
Photo, product page, input voltage, current draw, dimensions and weight
are not public yet. Leave a marker where each belongs rather than a
silent gap, so a reviewer can see what is outstanding and the PR
checklist has something to point at.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(ark/fmu-v6xrt): the heater is not specific to the LSM6DSV80X
Every IMU on every ARK board gets a heater; this die is only the most temperature-sensitive one, which is why the heater targets it.
* fix(ark/fmu-v6xrt): regulate the heater on the ICM-45686
HEATER1_SENS_ID pointed at the LSM6DSV80X because its high-g channel drifted 2 mg/°C. The driver now publishes that part's low-g channel (0.07 mg/°C), so the die that flies is the one to hold at temperature. The pad warms the whole board either way; this only picks the feedback sensor.
* fix(ark/fmu-v6xrt): single-IMU selection like ark/fmu-v6x
The imxrt arch defaults turn on multi-EKF (EKF2_MULTI_IMU 3, SENS_IMU_MODE 0), so the EKF2 selector picked the primary by test ratio and at rest it could land on any of the three IMUs. Override to the voter with one primary, as ark/fmu-v6x does.
* fix(ark/fmu-v6xrt): drop the Skynode TELEM2 mavlink autostart
rc.board_mavlink came along with the px4/fmu-v6xrt copy: on base ids 009-011 it starts mavlink at 3 Mbaud on TELEM2 and locks the port. Those ids are Skynode carriers; on an ARK carrier that ever reports one, TELEM2 would be silently taken. ark/fmu-v6x has no such file.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(ark/fmu-v6xrt): whitelist the generic airframes like ark/fmu-v6x
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* chore(ark/fmu-v6xrt): align the driver and module set with ark/fmu-v6x
Add what v6x carriers can use: batt_smbus, payload_deliverer, pca9685_pwm_out (started on PCA9685_EN_BUS like v6x), and the ADIS16507 and SCH16T external IMUs; add the mavlink-dev variant and the rover HIWONDER_EMM. Drop what this board cannot use or does not want: battery_status (no analog battery channels, BOARD_BATT_V_LIST is {-1,-1}), local_position_estimator, septentrio.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* refactor(ark/fmu-v6xrt): name the eighth UART TEL4 like ark/fmu-v6x
The port was EXT2 after the px4/fmu-v6xrt copy, so the same carrier connector is SER_TEL4_* on ark/fmu-v6x and SER_EXT2_* here. One name across the product line.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(ark/fmu-v6xrt): correct the PFD frequency comments
SYS_PLL2 PFD3 is 432 MHz, not 216 — the value FlexIO1 divides by 4 to
reach the 108 MHz that BOARD_FLEXIO_PREQ assumes for DShot timing.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* build(ark/fmu-v6xrt): default eth0 to static 192.168.0.4 like ark/fmu-v6x
The two ARK products should present the same ethernet identity. netman writes
the compiled-in default into the carrier EEPROM on first boot, so the v6XRT
left a fresh carrier on DHCP with a ~70 s fallback to 10.41.10.2, an address
nothing at ARK uses, while the v6X has been 192.168.0.4 since #24281.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* perf(ark/fmu-v6xrt): run the DShot cycle from ITCM
Same list as px4/fmu-v6xrt: up_dshot_trigger ran over XIP and its critical section measured 5.6 µs worst case on cache misses at 800 Hz.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): start the onboard baro unconditionally
SENS_INT_BARO_EN gated the BMP390 even though it is started as an external
sensor, so the parameter never meant what it says here, and it is being
replaced by CAL_BAROn_PRIO.
* fix(ark/fmu-v6xrt): receive RC on LPUART6 RX
The NXP v6XRT template single-wires on TX because its RC net is the TX pad. This board wires PAB X1-70 (carrier SBUS/RC pin 2) to LPUART6 RX.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ark/fmu-v6xrt): pin ICM-45686 as the primary IMU
The three IMUs run at equal voter priority, so the sensor voter selects
the primary by whichever validates first at boot and keeps it — a
non-deterministic race that on a test flight landed the primary on the
LSM6DSV80X instead of the ICM-45686. Seed the ICM's calibration slot with
a higher priority so selection is deterministic; the voter still fails
over to the other IMUs if it degrades.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(ark/fmu-v6xrt): add board photos and correct the user page
The remaining TODOs were the photos, store URL, and the v6x electrical/mechanical numbers. The IMU section and serial table still described the LSM6DSV80X high-g channel, a heater on that die, and EXT2.
Assisted-by: Grok:grok-4.6
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: alexklimaj <alex@arkelectron.com>
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Co-authored-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(sensors): decouple sensor internal/external classification from the bus
A sensor's internal/external classification was derived from its bus
(px4_i2c_bus_external / px4_spi_bus_external), but a bus is a wire: one bus
routinely serves both chips soldered on the FC and a pinned-out connector, and
any onboard sensor on such a shared bus was classified external. That hands an
onboard mag an operator-settable rotation instead of the board rotation, feeds
an onboard baro's self-heated die temperature into air density as if it were
ambient, and inverts the 75/50 default priority. FMU-v6C and AirBrainH743
worked around it with hand-rolled device_id whitelists behind
BOARD_OVERRIDE_I2C_DEVICE_EXTERNAL; FMU-v6XRT's second onboard baro was simply
misclassified.
Classify the device instead of the bus: drivers publish is_external in
sensor_accel/gyro/mag/baro, derived from the device id by default and
overridden by the new -O start flag ("onboard") for onboard sensors that share
a bus with an external connector. -I/-X stay pure bus probe filters.
The question "is this sensor external" had four answers. It now has one, with
a single override point:
-O -> I2CSPIDriverConfig::external -> Device::set_external() and the
PX4* wrappers -> is_external in the sensor topic
px4_i2c_device_external() was px4_i2c_bus_external() with a device id decode in
front, and calibration::DeviceExternal() forwarded to device_is_external();
both are gone. Device::external() stops being a bus query: it is non-virtual,
defaults to device_is_external(), and takes the declared value through
set_external(), so the five I2C/SPI overrides that used to answer it from the
bus are deleted and cannot diverge again. device::I2C and device::SPI set it
from the config, so every driver built on the bus framework follows -O without
doing anything. px4_i2c_bus_external() and px4_spi_bus_external() survive as
what they honestly are - bus predicates - reachable only through the fallback.
-O is opt-in per driver (BusCLIArguments::support_onboard), the same way -k is:
a flag that every driver advertised but only a handful honoured would be a
silent no-op on the rest. This also drops the special case for the mcp23009 and
mcp23017 GPIO expanders, which use -O for their output state and simply do not
opt in.
sensor_gyro_fifo carries is_external too. VehicleAngularVelocity prefers the
FIFO topic for any IMU that publishes one, so without it the rate controller
would take its rotation from the bus while VehicleIMU took it from the topic -
the same chip, two classifications.
The BOARD_OVERRIDE_I2C_DEVICE_EXTERNAL hook is removed along with both board
implementations, replaced by -O on the affected rc.board_sensors lines.
FMU-v5x, MR-CANHUBK3, KakuteF7, NXT-Dual and MicoAir H743-Lite each start an
onboard barometer on an external bus and get the flag as well.
Assisted-by: Claude:claude-fable-5, Claude:claude-opus-5[1m]
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(sensors): treat shared buses as first-class topology
A boolean internal/external flag cannot describe a bus that carries both
hard-mounted chips and a connector. -O was an opt-in override for that
case, so most drivers silently ignored it and classification still
followed the bus.
Declare Internal / External / Shared on the bus, probe External and
Shared, and classify each sensor from -I/-s vs -X/-S.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ci): drop stale ITCM symbols and clang-tidy errors
ITCM lists still named calibration::DeviceExternal and
px4_spi_bus_external after both were removed. The host test stubs
forwarded varargs in a way the analyzer rejected, and stripped I2C
headers kept extra trailing newlines.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(sensors): inline device_is_external into the header
Reaching it through drivers__device pulled the kernel-only library into
the userspace image of a protected build; giving it a library of its own
put an archive referencing px4_i2c_buses/px4_spi_buses after the board
library that defines them. Inlining sidesteps both.
* fix(sensors): compile tcbp001ta and probe canhubk3 GPS mag
tcbp001ta is not an I2CSPIDriver, so config.external does not exist; it
only ever starts on internal SPI. -X on canhubk3 I2C2 never ran because
that bus is Internal.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
hrt_elapsed_time() was a static inline expanding to ~15 bytes at each
of its ~450 call sites (call to hrt_absolute_time plus 64-bit compare
and subtract). Move the definition into px4_platform so each call site
is a single branch. px4iofirmware does not link px4_platform, so it
compiles the new source directly.
Saves 3592 bytes of flash on px4_fmu-v6x_default.
Co-authored-by: Balduin <balduin@auterion.com>
* refactor(px4_work_queue): out-line ScheduledWorkItem constructor to save flash
The header-inline constructor zero-initialises the hrt_call member at
every derived work-item constructor across ~150 classes. Move the
definition (verbatim) into ScheduledWorkItem.cpp next to the
destructor; the derived constructors already pay a call into the base
constructor chain, so this only removes the duplicated inline stores.
Saves 1376 B of .text on px4_fmu-v6x_default.
Signed-off-by: Balduin <balduin@auterion.com>
* refactor(px4_work_queue): out-line WorkItem::ScheduleNow to save flash
The body was inlined at ~240 call sites; a plain call is smaller at
every one of them.
Saves 672 B FLASH on px4_fmu-v6x_default.
Signed-off-by: Balduin <balduin@auterion.com>
---------
Signed-off-by: Balduin <balduin@auterion.com>
Co-authored-by: Balduin <balduin@auterion.com>
The constructor is inlined into every I2C/SPI driver's command-line
entry point, and with it the ~15 default member initializers and the
32-byte _options zero-fill, costing ~50-70 B per driver. Move the
definition (verbatim) into i2c_spi_buses.cpp, which already holds the
rest of the CLI parsing code. Purely cold-path (driver start/CLI).
Saves 2456 B of .text on px4_fmu-v6x_default.
Signed-off-by: Balduin <balduin@auterion.com>
Co-authored-by: Balduin <balduin@auterion.com>
* feat(dshot): EDT and BDShot HAL contract on i.MX RT
The FlexIO driver ignored edt_enable and only marked a channel ready after a CRC-good post-training frame, so one missing ESC blocked telemetry for every motor. Match the STM32 consumer contract: ready every cycle, consecutive CRC hysteresis, train on any valid GCR, and gate FlexIO output from up_dshot_arm.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(dshot): keep the trained BDShot offset across an i.MX RT dropout
Going offline restarted baud training from BDSHOT_TCMP_MIN_OFFSET. The
offset tracks the ESC oscillator, not the link, so a transient dropout
threw away a still-valid result and pinned the channel offline for the
whole re-sweep, starving the ESC RPM notch. Train once on first connect
and let the success hysteresis handle recovery.
Also close three smaller gaps: the sweep stopped one round early and
never evaluated BDSHOT_TCMP_MAX_OFFSET, up_bdshot_get_erpm carried a
bound check the next line subsumes, and re-arming left a stale channel
state that latched a garbage SHIFTBUFBIS read as a response.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(dshot): harvest i.MX RT BDShot RX before the next TX
dshot_motor_data_set flipped state to DSHOT_START and cleared SHIFTSTAT before the frame was consumed, so a delayed FlexIO IRQ transmitted irq_data instead of latching telemetry. Harvest under a critical section and skip the burst while the receive window is still open.
Zero driver state in up_dshot_init so a module restart cannot keep a stale online bit through retraining. After a second offline period, restart the TCMP sweep so a wrong baud can recover.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(dshot): guard the whole i.MX RT DShot cycle, not just the receive
The busy window started at the IRQ's receive timestamp, so a trigger landing during the frame itself reconfigured the shifter mid-transmit, and up_dshot_arm enabled the shifter interrupt with nothing queued. The first trigger after arming also counted a missing response, and the trained TCMP was updated outside the critical section the IRQ reads it in.
Stamp the cycle at transmit and size the window for frame, ESC turnaround and response. Latch, decode and reconfigure in one critical section, mask the IRQ by the enable registers instead of a channel mask, and leave the timer interrupt off while receiving. Warn for outputs the FlexIO cannot serve instead of dropping them silently.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(dshot): keep the i.MX RT DShot trigger out of a critical section
up_dshot_trigger runs at the output rate, so masking every interrupt on the MCU for the whole latch, decode and reconfigure pass was far too long. The IRQ only acts on a channel whose interrupt is enabled and the trigger only touches a channel whose cycle is over, so the two contexts never own the same channel at once and none of that needed a lock.
What does: the SHIFTBUF write and the interrupt enable must not be separated by preemption, since the IRQ has to queue the second word within 20 us at DShot1200, and SHIFTSIEN/TIMIEN have no set/clear aliases, so the thread's read-modify-write must be atomic against the IRQ's. That is a dozen register accesses.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(dshot): do not clear SSF after re-enabling the i.MX RT transmit shifter
In transmit mode SSF sets on enable and is the timer's active-low trigger. Clearing it before SHIFTBUF is written asserts the trigger, so the timer shifts an empty shifter for one compare and the real word lands late: 14 garbage sub-bits, a truncated frame, no ESC response. Only the SHIFTBUF write may clear it.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(dshot): resynchronise the i.MX RT BDShot receive timer on the channel pin
The receive timer was set to reset on its timer pin's rising edge, but the timer pin was left at FXIO_D0, so the baud counter never resynchronised; and with the timer output starting high the first shift came a full period after the start edge, so every sample sat on a bit boundary. Only a baud 2-3 % faster than the ESC's pulled the samples inside the bits, which is why training found a three-count window and why channels fell off it per run.
Point the timer pin at the channel pin so a baud-mode reset reloads the divider on every falling edge of the response, and start the output low so the shift lands mid-bit. On an ARK 4in1 at DShot300 every offset from -10 to +15 now decodes 198/200, all four channels train on the first sweep, and the CRC error rate matches the previous driver. The status output shows the training mask.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* perf(dshot): run the i.MX RT DShot cycle from ITCM
up_dshot_trigger executed from the NOR over XIP, so its ~1 µs critical section measured 5.6 µs worst case on instruction cache misses at 800 Hz. Map the per-cycle path — the trigger, its FlexIO callees, the HAL getters and the DShot module's Run/updateOutputs/telemetry — into ITCM on fmu-v6xrt, about 3 KB. decode_gcr_payload is inlined so the list needs no compiler-named partial section.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(dshot): keep the i.MX RT BDShot offset across a dropout
A missing response counted toward the re-sweep, so any dropout over 0.5 s — a wire, an ESC power cycle — cost a full seven-second sweep after the ESC came back although its oscillator had not changed. Only frames that arrive and fail to decode restart training now; a dropout just takes the channel offline and it is back 200 good frames after the ESC returns.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* perf(dshot): sweep the i.MX RT BDShot baud in 25-frame rounds
With the receive timer resynchronising, every offset is either clean or fails outright, so 200 frames per offset only stretched the sweep to eight seconds at 800 Hz once the whole window started passing. 25 frames with one allowed miss give the same mask in a second, well inside the five seconds DShot.cpp ignores telemetry after boot.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(dshot): restore the i.MX RT FlexIO register comments
The rewrite dropped the comments naming what each shifter and timer register write configures. They are the only prose map of the FlexIO setup, so keep them wherever the code they describe survives.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
EDT enable was sent once, a second after bidirectional telemetry came online, and never checked. AM32 only executes commands once armed, which takes a second of zero throttle plus its arming tune, so that single request can be dropped. Bluejay clears EDT whenever the motor stops, so it was off after the first flight. Treat any EDT frame after a request as confirmation, retry once a second up to five times, and start over on reconnect and on disarm.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
The imxrt FlexCAN driver left the TX mailbox CS word uninitialised, so
classic frames went out with EDL set and appeared on the wire as CAN FD,
and its TX timeout handler aborted mailboxes that were still
transmitting. Either one takes the interface error passive and it never
recovers.
Picks up PX4/NuttX #395 and #396.
Brings in PX4/NuttX#393 (backport of apache/nuttx#19936). The DWC2-derived
USB device drivers masked off the WKUP interrupt, so CLASS_RESUME was never
delivered. cdcacm_suspend() marks the serial device disconnected and the
matching resume never runs, leaving the CDC/ACM port returning -ENOTCONN for
the rest of the boot after the first host autosuspend.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Brings in PX4/NuttX#394 (backport of apache/nuttx#19957). imxrt FlexCAN
handed out the lowest free TX mailbox, so a refilled low mailbox could
win arbitration over an older frame of the same CAN ID still queued in a
higher one. Multi-frame DroneCAN transfers arrived out of order and were
dropped by the receiver.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
#28366 unintentionally carried a submodule bump to 39508f26a2, which
exists on PX4/NuttX only as refs/pull/394/head. main therefore depends on
an open pull request's head commit instead of a branch commit: it resolves
today only because GitHub serves PR refs, and breaks if #394 is closed or
its branch is force-pushed.
The two imxrt FlexCAN commits it pulled in are unreferenced by anything on
main and land properly when PX4/NuttX#394 merges.
Every FMU has advertised NodeInfo.name "org.pixhawk.pixhawk" since 2014, so an
ARK FMU-v6XRT, an ARK FMU-v6X and a Pixhawk 6X are indistinguishable on the bus
by anything except their unique id. The cannode side already derives its name
per board through board_get_uavcan_hw_name(); do the same on the FMU side from
px4_board_name(), which is the only board identity the module already has.
NuttX's <cstdlib> only re-exports the C int abs(int) and its <cmath> adds
no abs overloads, so under -nostdinc++ every abs(float/double/int64)
call binds to int abs(int) and truncates, while the same source is
correct under libstdc++ on SITL. -Werror never sees it because the
implicit conversion is not warned on.
A build-time trap (deleted float/double/long/long long abs declarations)
across v5, v6x, v6xrt and v6x_uuv found truncating sites in
lat_lon_alt, ekf2 checkLatLonValidity, ilabs INS position validity,
local_position_estimator bias saturation, uuv_pos_control height
thresholds, hott longitude, the uxrce_dds_client clock-sync delta, and
the uavcan stm32/stm32h7/kinetis UTC lock thresholds.
Force-include a header declaring the overloads libstdc++ provides so
both qualified and unqualified calls resolve correctly everywhere, and
nothing can bind to int abs(int) again.
Every Param<> constructor inlines param_set_used(handle()) followed by
param_get(handle(), &_val), materialising the handle constant twice at
each of the ~2000 instantiation sites. Fold both into a single
out-of-line param_get_mark_used() so each constructor emits one call.
The failsafe_web build stubs the param API itself, so it gets a matching
stub. The smaller constructors let the compiler fully inline the
defaulted FlightTaskDescend constructor on the ITCM boards, so its entry
is dropped from their linker scripts.
Saves 7232 B of .text on px4_fmu-v6x_default.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Co-authored-by: Balduin <balduin@auterion.com>
Both were defined inline in the header, so the List add/remove bodies
were duplicated into the constructor and destructor of every one of the
150+ ModuleParams-derived classes. Construction and destruction are cold
paths; a call is smaller at each site.
Two consumers reach ModuleParams without px4_platform on the link line
and now need the definitions explicitly: health_and_arming_checks (the
functional-ModeManagement test only pulls it in transitively through
modules__commander, after px4_platform) and the failsafe_web emscripten
build, which compiles module_params.cpp directly.
The smaller constructors let the compiler fully inline the defaulted
FlightTaskDescend constructor on the ITCM boards, so its entry is
dropped from their linker scripts.
Saves 3968 B of .text on px4_fmu-v6x_default.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Co-authored-by: Balduin <balduin@auterion.com>
board_determine_hw_info() inits LPADC2 and consumes the function-static
once flag, so board_adc's later LPADC1 init is a no-op. CFG stays at
reset (PWREN=0, no settling). Match the STM32 once-per-base pattern.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
board_query_manifest walked the list for mft[ndx].id == id then
returned &mft[id]. On a sparse list that is the wrong row, and for
PX4_MFT_T100_ETH (id 7) it is out of bounds.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
macos.sh --sim-tools installs the unversioned Homebrew opencv formula, which
is now 5.0.0, and PX4-OpticalFlow does not build against it:
klt_feature_tracker/src/trackFeatures.cpp:43:10:
fatal error: 'opencv2/core/types_c.h' file not found
PX4-OpticalFlow/src/flow_opencv.cpp:110:7:
fatal error: no member named 'undistortPoints' in namespace 'cv'
types_c.h was removed in OpenCV 5, and undistortPoints moved when calib3d was
split into 3d/calib. The failure lands about a thousand targets into
make px4_sitl and points at submodule sources rather than at the dependency.
ubuntu.sh takes libopencv-dev from apt, which is still 4.x, so CI never sees
this.
Install opencv@4 instead. It is keg-only, so find_package still resolves to
5.0.0 without a prefix hint. Add one alongside the qt@5 hint from 9c2e634325,
which is keg-only for the same reason.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Jackson Korba <jackson.korba@gmail.com>
Run the ELF import checker after linking the QURT shared object when a
board registers provider symbol files or forbidden import prefixes.
Include the linked C++ runtime shared objects as providers when
validating against a target system image.
Assisted-by: OpenAI:Codex
* fix(cdcacm_autostart): start MAVLink without holding the USB port
SYS_USB_AUTO=2 opened /dev/ttyACM0 O_RDONLY and kept it for the life of
the link, then treated a successful mavlink spawn as permanent success.
If mavlink later failed its UART open retries and exited, the driver
stayed "connected" and never restarted — listen-first hosts (production
USB MAVLink benches) saw no heartbeats until a VBUS cycle.
Start mavlink without a probe open, track its PID and restart if it
dies while VBUS is present, close the autodetect fd before handing the
device to a protocol, and drop the unused legacy cdc_acm_check path.
Assisted-by: Grok:grok-4.5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(cdcacm_autostart): initialise actuator_armed before the armed gate
copy() leaves the destination untouched when a topic has never been advertised,
so with commander not running `report` is whatever was on the stack. When that
garbage has armed set, run_state_machine() takes the "do not reconfigure USB
while flying" branch every cycle and never advances the state machine, so
MAVLink is never started on the USB CDC — on a vehicle that is definitionally
not flying, because commander is not running.
Seen on an ARK FMU v6X production test bench: a `commander stop` early in the
sequence leaves `listener actuator_armed` reporting "never published", and from
then on `mavlink status` shows no ttyACM instance at all while a host that opens
the port waits out its timeout against silence.
Zero-initialising restores the correct default for that case: not armed, so the
state machine runs.
* Update src/drivers/cdcacm_autostart/cdcacm_autostart.cpp
* Update src/drivers/cdcacm_autostart/cdcacm_autostart.cpp
* Update src/drivers/cdcacm_autostart/cdcacm_autostart.cpp
* Update src/drivers/cdcacm_autostart/cdcacm_autostart.cpp
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Make px4::atomic's value constructor and ModuleBase::Descriptor
constexpr so the ~40 per-module 'desc' statics are constant-initialised
instead of each emitting static-init code, and apply the same to the
mixer_module FunctionProvider table.
Signed-off-by: Balduin <balduin@auterion.com>
* refactor(platforms/nuttx): remove dead PX4_I2C_BUS_MTD board define
The macro's value has been unused since the MTD manifest refactor
(68ab736b1 "Refactor mtd to make available to board startup"), which made
the board manifest the source of truth for the EEPROM bus and address:
at24xxx_attach() derives the bus from PX4_I2C_DEVID_BUS(instance.devid).
All that survived was a presence check that silently degraded a former
compile-time #error into a runtime failure.
Because the value stopped mattering, it drifted freely. Eleven boards
carry "4,5", which is not even a usable bus number, and several boards
disagree with their own manifest (fmu-v5x declares 4,5 against actual
buses 3 and 4; fmu-v6xrt declares 1 against 3 and 6; 7-nano declares 1
against 4). crazyflie21 defines it with no MTD manifest at all.
Guard at24xxx_attach() on CONFIG_I2C instead, which is the condition the
code actually depends on and matches how the neighbouring ramtron_attach()
guards on CONFIG_MTD_RAMTRON.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(platforms/nuttx): guard at24xxx_attach on CONFIG_MTD
CONFIG_I2C is too broad: nearly every board enables I2C, including those
without MTD. Compiling the real at24xxx_attach body kept the mtd_partition
/ register_mtddriver / ftl_initialize path live, so boards without
CONFIG_MTD failed to link.
CONFIG_MTD is the NuttX flag that actually enables that infrastructure
(and is set on every board with an I2C EEPROM manifest). CONFIG_MTD_AT24XX
is not suitable: only crazyflie sets it; FMU boards use px4_24xxxx_mtd.c
and deliberately omit the NuttX AT24 driver.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>