Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/PX4/PX4-Autopilot/llms.txt

Use this file to discover all available pages before exploring further.

Porting PX4 to a new flight controller means creating a board support package that tells the build system which MCU to target, which peripherals are present, and how those peripherals are wired. PX4 separates hardware description into a small set of configuration files under boards/<vendor>/<board>/; once those files are correct, the rest of the flight stack compiles and runs without modification.

What porting involves

A PX4 port is not a fork. You do not modify core flight control code. Instead, you provide:
  • A Kconfig-based build configuration that enables the drivers and modules your hardware needs.
  • A NuttX board support package (BSP) that describes the MCU’s clocks, GPIO pinout, serial ports, SPI buses, and I2C buses.
  • Startup scripts that initialize peripherals in the correct order.
  • Optional board-specific drivers or shims if your hardware deviates from a supported bus topology.
PX4 currently targets NuttX as its RTOS on all Cortex-M and Cortex-M7 flight controllers. If your MCU is already supported by NuttX, the BSP layer is straightforward. If it is not, you must bring up NuttX first before working on the PX4 layer.
Linux-based flight controllers (Raspberry Pi, BeagleBone, VOXL 2) follow a different porting path through the boards/raspberrypi/, boards/beaglebone/, and boards/modalai/ directories. The steps below focus on bare-metal NuttX targets.

Board directory structure

Every board lives under boards/<vendor>/<board>/. Use lowercase, hyphen-separated names for both the vendor and board directories — for example, boards/holybro/durandal-v1/.
boards/<vendor>/<board>/
├── default.px4board          # Main build config (drivers, modules, features)
├── bootloader.px4board       # Minimal config for the bootloader build
├── firmware.prototype        # Firmware metadata (board name, version)
├── nuttx-config/
│   ├── Kconfig               # NuttX board-level Kconfig options
│   ├── nsh/
│   │   └── defconfig         # NuttX NSH shell configuration
│   ├── bootloader/
│   │   └── defconfig         # NuttX config for the bootloader
│   ├── scripts/
│   │   └── <linker>.ld       # Linker script for flash/RAM layout
│   └── include/
│       └── board.h           # MCU clock config, GPIO init, peripheral mux
├── init/
│   └── rcS                   # Startup script run at boot
└── src/
    └── board_config.h        # Pin assignments and bus topology
Start by copying the directory of the board whose MCU is closest to yours. If your board uses an STM32H7, copy boards/holybro/durandal-v1/ (STM32F7) or boards/px4/fmu-v6x/ (STM32H7) as a baseline rather than starting from scratch.

Required files explained

This file is the primary build configuration. It uses Linux Kconfig .config format: each line is CONFIG_<KEY>=y or # CONFIG_<KEY> is not set.
CONFIG_BOARD_TOOLCHAIN="arm-none-eabi"
CONFIG_BOARD_ARCHITECTURE="cortex-m7"

# Serial port assignments
CONFIG_BOARD_SERIAL_GPS1="/dev/ttyS0"
CONFIG_BOARD_SERIAL_TEL1="/dev/ttyS1"
CONFIG_BOARD_SERIAL_TEL2="/dev/ttyS2"

# Drivers
CONFIG_DRIVERS_IMU_INVENSENSE_ICM42688P=y
CONFIG_COMMON_BAROMETERS=y
CONFIG_DRIVERS_GPS=y
CONFIG_DRIVERS_DSHOT=y
CONFIG_DRIVERS_PWM_OUT=y
CONFIG_DRIVERS_TONE_ALARM=y
CONFIG_DRIVERS_UAVCAN=y

# Core modules
CONFIG_MODULES_COMMANDER=y
CONFIG_MODULES_EKF2=y
CONFIG_MODULES_MAVLINK=y
CONFIG_MODULES_LOGGER=y
Run make <vendor>_<board> menuconfig to explore available options interactively rather than editing this file by hand.
This C header configures the MCU: PLL multipliers, peripheral clock gates, and GPIO alternate functions. Every STM32 NuttX port requires this file.
#pragma once

// STM32H7 PLL configuration: 480 MHz system clock
#define STM32_BOARD_XTAL        16000000ul
#define STM32_HSE_FREQUENCY     STM32_BOARD_XTAL

#define STM32_PLL1P_FREQUENCY   480000000ul
#define STM32_PLL1Q_FREQUENCY   120000000ul

// UART1 → GPS
#define GPIO_USART1_TX  GPIO_USART1_TX_2  // PA9
#define GPIO_USART1_RX  GPIO_USART1_RX_2  // PA10

// SPI1 → IMU
#define GPIO_SPI1_MISO  GPIO_SPI1_MISO_1
#define GPIO_SPI1_MOSI  GPIO_SPI1_MOSI_1
#define GPIO_SPI1_SCK   GPIO_SPI1_SCK_1
The NuttX defconfig enables or disables kernel features, device drivers, and file system support. Generate it using make <board> nuttx-menuconfig and then save. Key options for a PX4 port include:
  • CONFIG_ARCH_CHIP_STM32H753 — select your exact MCU
  • CONFIG_STM32H7_SPI1 — enable SPI buses
  • CONFIG_STM32H7_I2C1 — enable I2C buses
  • CONFIG_STM32H7_USART1 — enable UART ports
  • CONFIG_RAMLOG — in-RAM logging for early boot debug
This shell script runs at boot inside NuttX NSH. It mounts the SD card, starts drivers in dependency order, and launches the main flight modules.
#!/bin/sh
# Board startup script

set VEHICLE_TYPE mc

# Mount SD card
if mount -t vfat /dev/mmcsd0 /fs/microsd; then
    echo "SD mounted"
fi

# Start IMU driver
icm42688p start -s -R 4

# Start barometer
bmp388 start -I

# Start GPS
gps start -d /dev/ttyS0

# Start MAVLink on telemetry port
mavlink start -d /dev/ttyS1 -b 57600 -m onboard

# Hand off to the commander
commander start
Board-specific pin and bus assignments that the PX4 platform layer reads. This file maps logical names (like PX4_SPI_BUS_SENSORS) to physical NuttX bus numbers and chip-select GPIOs.
#pragma once

// SPI bus assignments
#define PX4_SPI_BUS_SENSORS     1
#define PX4_SPI_BUS_MEMORY      2

// Chip-select GPIOs for SPI1
#define PX4_SPIDEV_ICM42688P    PX4_MK_SPI_SEL(PX4_SPI_BUS_SENSORS, 0)
#define PX4_SPIDEV_BARO         PX4_MK_SPI_SEL(PX4_SPI_BUS_SENSORS, 1)

// I2C bus assignments
#define PX4_I2C_BUS_EXPANSION   1
#define PX4_I2C_BUS_ONBOARD     2

// UART/Serial
#define GPS_DEFAULT_UART_PORT   "/dev/ttyS0"

Porting workflow

1

Find your closest existing board

Search the boards/ directory for a port using the same MCU family as your target. For an STM32H753-based board, look at boards/px4/fmu-v6x/. For STM32F765, look at boards/holybro/durandal-v1/.
ls boards/
# 3dr/  ark/  auterion/  cubepilot/  holybro/  modalai/  mro/  px4/ ...
2

Copy and rename the board directory

cp -r boards/holybro/durandal-v1 boards/<your-vendor>/<your-board>
Replace every occurrence of the source board’s name in the copied files. Pay attention to firmware.prototype, nuttx-config/Kconfig, and any hard-coded paths in board.h.
3

Update nuttx-config/include/board.h

Set the correct PLL values for your crystal frequency and MCU speed. Map GPIO alternate functions to match your schematic’s pin assignments. This file controls clocks and pin muxing — incorrect values here cause silent failures or hard faults at boot.
Always verify your PLL configuration against your MCU’s reference manual. An incorrect multiplier can run the core out of its rated frequency and cause unpredictable behavior.
4

Configure the NuttX defconfig

Enable the MCU variant and peripherals your board uses:
make <your-vendor>_<your-board> nuttx-menuconfig
Confirm the correct CONFIG_ARCH_CHIP_* is selected, and enable only the SPI, I2C, and UART instances physically present on your board.
5

Update default.px4board

Enable the exact driver set for your sensor suite. Use menuconfig to browse what is available:
make <your-vendor>_<your-board> menuconfig
Assign serial port paths in CONFIG_BOARD_SERIAL_GPS1, CONFIG_BOARD_SERIAL_TEL1, etc. to match your schematic.
6

Write the startup script (init/rcS)

Start drivers in dependency order. Sensor drivers must start before the EKF; EKF must start before the commander. Follow the pattern from an existing rcS that matches your vehicle type (multicopter, fixed-wing, or rover).
7

Build and flash

make <your-vendor>_<your-board> px4
# Flash with J-Link, ST-Link, or the PX4 bootloader
make <your-vendor>_<your-board> upload
8

Validate in SITL before hardware

If your board is based on an existing FMU design, run SITL against the reference board first to confirm your module selection compiles:
make px4_sitl none

Peripheral configuration checklist

Use this checklist before declaring a port ready for testing.
  • Correct SPI bus and chip-select GPIO in board_config.h
  • SPI clock polarity and phase match the sensor datasheet (SPIDEV_MODE3 for most InvenSense parts)
  • Driver enabled in default.px4board with the correct rotation constant (-R <n>)
  • listener sensor_accel shows plausible values at boot
  • I2C or SPI address matches physical pull-up configuration
  • Driver started in rcS after IMU
  • listener sensor_baro shows altitude near sea level (approximately 1013 hPa)
  • Correct UART path in CONFIG_BOARD_SERIAL_GPS1
  • Baud rate matches receiver default (typically 9600 for cold start, 115200 after configuration)
  • gps status shows fix type and satellite count
  • Timer assignments in board.h match schematic ESC connections
  • pwm info lists the expected channels
  • Motor spin-up test with actuator_test confirms correct channel mapping

Submitting a port upstream

If you want your port included in the official PX4-Autopilot repository, the board must pass CI and meet the contribution requirements described in the PX4 contributing guide.
The PX4 project distinguishes between Pixhawk Standard ports (maintained by the core team) and manufacturer-supported ports (maintained by the manufacturer). Submit a manufacturer-supported port if your company will own ongoing maintenance.

Build docs developers (and LLMs) love