ArduPilot on the RP2350: feasibility and effort (2026-10-09)
Ryan asked (relayed by th-eda) what it would take to run ArduPilot on a Raspberry Pi RP2350B as
the MCU of a future TerraHawk flight controller, against the STM32H743 of the current design
(terrahawk-eda/docs/flight-controller-brief.md). This page is a scoping note, not a design.
Every fact has a source and a date; every effort figure is an estimate and says so. Written by
th-simulator, with a research pass over GitHub, the ChibiOS forum and vendor pages on 2026-10-09.
The short answer
Section titled “The short answer”ArduPilot on the RP2350 is no longer hypothetical: an open pull request, ArduPilot #32995 “RP2350 Port” (davidbuzz with andyp1per, opened 2026-05-06, 180 files, +30,788 lines, not merged), has flown a copter on its RPI_UAVFC board. It depends on an equally unmerged ChibiOS change, ArduPilot/ChibiOS #113 “RP2350 Support” (+22,060 lines). It has no CAN, it was flown at a 225 MHz system clock against the datasheet’s 150 MHz, and it has not flown a plane.
For TerraHawk the deciding item is CAN. The airframe’s own controller is meant to carry two DroneCAN buses, the first one for the four lift ESCs. The RP2350 has no CAN peripheral, nothing in ArduPilot drives CAN on it, and both ways of adding CAN cost months: software CAN in PIO (can2040, classic CAN only, with interrupt-latency demands an autopilot struggles to meet) or an external SPI controller (no ArduPilot driver exists for one). Add the PIO budget, which two CAN buses and four more UARTs already exceed, and the RP2350 is the less capable part for this board, not the more capable one. The H743 does all of it in hardware, today, in tree.
Where the RP2350 does make sense is set out at the end.
1. ChibiOS on the RP2350
Section titled “1. ChibiOS on the RP2350”| Where | RP2350 state |
|---|---|
| ChibiOS stable (newest tag ver21.11.5, 2026-04-04) | None: os/hal/ports/RP/ has the RP2040 only, and no ADC, PWM, USB, flash or PIO driver (GitHub API on the tag, 2026-10-09) |
| ChibiOS trunk (chibios-upstream) | RP2350/ platform (commits 2026-01-09 to 2026-09-28), both Cortex-M33 and Hazard3 cores; LLD drivers ADC, DMA, EFL (flash), GPIO, I2C, PIO (from 2026-03-10), PWM, RTC, SPI, timer, UART, USB, watchdog |
| ArduPilot’s ChibiOS fork, as pinned in our tree (9aebaf4, 2026-08-17) | None. os/hal/ports/RP/ has RP2040/ and drivers for DMA, GPIO, I2C, RTC, SPI, the system timer, UART and watchdog only; the RTOS has an ARMv6-M-RP2 port (the RP2040’s M0+) and a generic ARMv8-M-ML (M33) port. Measured in ~/claude/drone/ardupilot/modules/ChibiOS |
| ArduPilot’s fork, pending | ArduPilot/ChibiOS #113: SMP plus ADC, DMA, flash, GPIO, I2C, PIO, PWM, SPI, timer, UART, USB and watchdog drivers. Open, last updated 2026-09-24 |
The ChibiOS forum threads (RP2350 support and RP2040 update, from 2025-12-26; PIO units, April 2026) say the PIO driver is mostly output-oriented. So the RTOS layer exists in trunk and in a pending fork change, but in nothing ArduPilot builds against today.
2. ArduPilot work on the RP2040 and RP2350
Section titled “2. ArduPilot work on the RP2040 and RP2350”PR #32995 is the one that matters. From its description (read 2026-10-09):
- It flies: “RPI_UAVFC is a real flight controller running this, with bidirectional DShot600, an eRPM-driven harmonic notch, analog OSD and microSD logging in the air.” A copter. No plane flight is reported.
- Dual-core SMP, “the first SMP implementation in ChibiOS”: IMU, rate loop and DShot on core 1, main loop at 200 Hz with EKF3 inline on core 0.
- CAN / DroneCAN: “No. No hardware for it.”
- Clock: run at 225 MHz; “the datasheet limit is 150 MHz and it has been flight-tested on one sample”. Silicon spread at 225 MHz is an open item.
- Memory and flash pressure: the 16 KB XIP instruction cache, shared by both cores, drove the
design. Everything from gyro sample to DShot frame is relocated to SRAM; one relocation
(
AP_DAL) measured 8x to 10x faster out of flash. Flash writes park core 1, because XIP is off during every erase and program; so parameter storage must stay on core 0. The port setsHAL_WITH_POSTYPE_DOUBLE0 to save flash. - Two PIO UARTs on top of the two hardware ones, “since two hardware UARTs are not enough for a flight controller”.
- Review state: open, not a draft, mergeable state “dirty”; changes requested by review on 2026-10-03 and further review on 2026-10-07.
Earlier attempts went nowhere: a Pi Pico porting thread stalled on 2024-12-31 for want of ChibiOS support, and a 2021 RP2040 thread was discussion only. The ESP32 HAL is the nearest precedent for a non-STM32 HAL: in master since 2021-10-27, 195 commits from 32 authors, still “experimental” with no OEM board, and “planes will fly at 50 Hz” by its author in 2024 (dev docs, post).
3. What AP_HAL_ChibiOS assumes is STM32
Section titled “3. What AP_HAL_ChibiOS assumes is STM32”PR #32995 has already done most of this for a copter-class board. The column “after #32995” is what remains for a TerraHawk board if that PR lands; the efforts are estimates in person-months (pm) for an engineer who knows ArduPilot’s HAL.
| Item | On the H743 | RP2350 state | After #32995, for TerraHawk |
|---|---|---|---|
| hwdef generator, pin muxing | chibios_hwdef.py with STM32 alternate-function tables |
done in #32995 for its boards (RP2350 pads take a function select, not AF tables) | a new board hwdef: 0.3 to 0.5 pm |
| Bootloader, flash layout | internal 2 MB flash, ArduPilot bootloader | external QSPI, XIP through a 16 KB cache; boot ROM and UF2 | done in #32995; plane’s larger code set needs its own SRAM-relocation pass: 1 to 2 pm |
| Storage (params, mission) | FRAM on SPI, flash fallback | flash writes stall XIP and park core 1 | FRAM on SPI (the brief already has it) removes the flash-write problem: 0.2 pm |
| UARTs with DMA | 8 hardware (U)SARTs | 2 hardware UARTs, the rest in PIO (#32995 adds two) | the brief needs 6: four PIO UARTs, which collide with CAN for PIO (below): 0.5 pm plus the PIO budget |
| SPI | 6 SPI, DMA | 2 hardware SPI | the brief puts the two IMUs on separate buses, which takes both; FRAM, baro and SD need a third and fourth bus, by sharing or PIO: 0.5 pm |
| I2C | 4 | 2 hardware | enough (Q43 compass, baro if not on SPI) |
| PWM, DShot timers | TIM-based, bdshot | 24 PWM channels, DShot in PIO | done in #32995 (bidirectional DShot600 flown); elevons on hardware PWM are fine |
| ADC | 3 ADCs, many channels | 8 channels on the RP2350B | done in #32995 (current scaling still a placeholder there); 0.2 pm |
| SD card | SDMMC 4-bit | no SD host; SPI mode or PIO SDIO | #32995 logs to microSD; check its interface and speed: 0.3 pm |
| USB | OTG FS | USB 1.1 device | done in #32995 |
| CAN | 2 to 3 FDCAN, in tree | none | section 4: 2 to 5 pm |
| Double-precision EKF | HAL_WITH_EKF_DOUBLE 1 (hardware double) |
single-precision FPU only; #32995 sets it to 0 | same as the F405 boards ArduPlane already flies; loses accuracy far from the origin (#17988), which matters little inside one survey area |
Peripheral counts for the RP2350 are from the RP2350 datasheet: 2 UART, 2 SPI, 2 I2C, 24 PWM channels, 3 PIO blocks of 4 state machines, a USB 1.1 controller, 8 ADC inputs on the QFN-80, 520 KB SRAM, no CAN, no SD host. The datasheet also describes a double-precision coprocessor (DCP); whether ChibiOS or ArduPilot builds could use it was not checked.
4. CAN, which decides it
Section titled “4. CAN, which decides it”TerraHawk’s own controller is specified with two DroneCAN buses: bus 1 for the four lift ESCs
only, bus 2 for everything else (Decisions table, CLAUDE.md). Two ways to add CAN to an RP2350:
| can2040 (CAN in PIO) | External SPI controller (MCP2518FD) | |
|---|---|---|
| What it is | can2040: software CAN in one PIO block plus an interrupt handler; RP2350 support since 2024-12-13 | a CAN FD controller on SPI, one per bus, plus a transceiver |
| CAN FD | no: CAN 2.0B only, up to 1 Mbit/s (Features.md) | yes |
| Cost | one whole PIO block per bus, so two of the three; about 15 % of one core per fully loaded 1 Mbit/s bus on the RP2350, which can2040 states as expected, not measured | one SPI bus (or chip select) per controller, interrupt and SPI traffic per frame |
| Timing demand | interrupt latency above about 3 bit times (3 us at 1 Mbit/s) delays transmits, above about 7 causes retransmits, above about 80 loses messages; the handler must run from RAM (flash loads take 320 ns or more, API.md) | relaxed: the controller buffers frames; latency becomes SPI bus contention with the IMUs |
| Error handling | never transmits error frames and never goes bus-off by itself | full CAN error state machine in the controller |
| In ArduPilot | nothing: no CANIface for it, no PR; one unresolved user report of DroneCAN frames never sent (Klipper forum) | nothing: no SPI CAN driver for CANIface in tree or in a PR (the only MCP2515 mention is a companion computer in the Lectron-Pi5-H7 README; Linux has SocketCAN) |
| Effort (estimate) | CANIface on can2040, two buses, its interrupt on a core that keeps its latency under 3 us while ChibiOS runs, plus DroneCAN validation: 3 to 5 pm | a CANIface driver over SPI with its interrupt line, then DroneCAN validation: 2 to 3 pm, plus about 20 x 20 mm of board and an SPI bus each |
DroneCAN timing: the lift ESCs take 4 commands and send 4 status messages at the ESC rate (a few hundred hertz each) on bus 1 alone. can2040 can carry that at 1 Mbit/s, but its 3 us latency budget sits on the same core as either the 200 Hz main loop or the rate loop, and a missed bit window becomes retransmissions on the bus that holds the lift motors. A node that never sends error frames or goes bus-off also changes how a faulty bus fails, on the bus where a failure matters most. The SPI controller is the sound engineering choice of the two, and it puts two more devices on an MCU with only two hardware SPI buses, both already taken by the IMUs.
The PIO budget, counted for the brief: two CAN buses by can2040 take 2 of the 3 PIO blocks; four more UARTs need 8 state machines, which is the other block twice over; SD in SDIO mode would take more. It does not fit. With SPI CAN controllers instead, the PIO has room for the UARTs and DShot, but the SPI buses do not have room for IMUs, FRAM, SD and two CAN controllers without sharing, which the brief avoided on purpose (one SPI fault must not take both IMUs).
5. Performance
Section titled “5. Performance”| STM32F405 | RP2350 (M33) | STM32H743 | |
|---|---|---|---|
| Clock | 168 MHz | 150 MHz (datasheet), 225 MHz in #32995 | 480 MHz |
| CoreMark | 566 (ST) | about 600 at 150 MHz from 4.02/MHz (NXP AN13579, arithmetic, not measured); measured 281 to 428 in two hobbyist runs from flash; about 900 at 225 MHz by the same arithmetic | 2424 (ST) |
| FPU | single | single | single and double |
| SRAM | 192 KB | 520 KB | 1 MB |
| Code | internal flash | external QSPI through a 16 KB cache | internal 2 MB flash with a 16 KB I-cache |
| ArduPlane today | flies (single IMU class boards, features trimmed) | not flown; #32995 flies copter | flies (Pixhawk 6C, our base) |
Per core the RP2350 is an F405, with more RAM and a second core, and code that runs at full speed only once moved into SRAM. ArduPlane already flies on F405-class boards with EKF3 in single precision, so EKF3 with two IMUs at a 200 Hz main loop is within reach; #32995 shows it for a copter. The headroom is the problem: the H743 has about four times the integer throughput, double precision in hardware, and no cache-miss cliff, and TerraHawk adds a quadplane’s two control sets, Lua scripts (the CG slider, the dock approach, charge interlock and more), DroneCAN on two buses and logging at survey rates. #32995’s own measurements (the main loop falling from 296 to 225 Hz when bring-up threads shared core 1) show how little margin there is.
6. Effort, and other flight stacks
Section titled “6. Effort, and other flight stacks”Estimates in person-months for one engineer fluent in ArduPilot’s HAL, assuming #32995 and ChibiOS #113 merge in roughly their present form. If they do not, add carrying them as a fork.
| Goal | Work | Estimate |
|---|---|---|
| Flies on the bench with SITL-equivalent features (ArduPlane quadplane, two IMUs, FRAM, SD logging, six UARTs, two DroneCAN buses, our Lua) | board hwdef; plane SRAM-relocation and loop profiling; PIO and SPI budget; CAN (SPI controllers: 2 to 3, can2040: 3 to 5); storage and SD; HIL against SITL; bench and tethered tests | 6 to 10 pm |
| Supported in tree | the above plus upstream review of the CAN driver and the plane changes, a board in the build server, and keeping pace with #32995’s own review (open 5 months so far) | 9 to 15 pm, with the schedule set by maintainers |
| For comparison: the H743 board as planned | hwdef derived from the Pixhawk 6C’s (hw/flight-controller/make_hwdef.py), both FDCAN native |
weeks, not months; the hwdef and its Docker firmware build are already in hw/flight-controller/ |
Other stacks with RP2 support, none of which flies a quadplane with DroneCAN today:
| Stack | RP2 state |
|---|---|
| Betaflight | official RP2350 target since 2025.12 (notes); acro and racing, no missions or VTOL |
| INAV | RP2350_PICO target in the 10.0 release candidates, UART driver still in development (#11592) |
| PX4 | RP2040 board since 2021 (#18083), “kinda works” in a 2025 test; RP2350 only in a fork |
| madflight, PicoFlight, MicroPython projects | hobby autopilots, no fixed-wing VTOL or DroneCAN |
Where the RP2350 fits
Section titled “Where the RP2350 fits”The RP2350 is the more capable part than the RP2040 and a good part in its own right: dual core, PIO, plenty of SRAM, open documentation, low cost, and now a flying ArduPilot port. Against the H743 for this airframe’s flight controller it is the weaker choice on every axis the controller needs: CAN (none against two or three FD buses), throughput (about a quarter), double precision, code execution (cache-bound against internal flash), UART and SPI counts, and maturity (an open PR against a decade of in-tree boards).
Two places it could earn a role without that cost: a DroneCAN peripheral node where one classic CAN bus at modest rates is enough and the node’s whole firmware is small (a servo node or the lights node; this still needs can2040 under AP_Periph, which does not exist), or a second board for PIO-heavy jobs that the H743 should not carry. If an RP2350 flight controller is still wanted later, the way to do it is to follow #32995 upstream, let it land, and build on the in-tree port, with two SPI CAN controllers and the CANIface driver for them as the TerraHawk contribution.
Source: docs/rp2350-flight-controller.md in the repo. Edit it there; this page is generated.
Comments
Comment on the whole page here, or on one section or step with the button beside it.