armhub.dev
Systems · 16 pages
Systems

Drone flight controller

Inside a Pixhawk-class flight controller — Cortex-M7 at 480 MHz, 8 kHz attitude loop, IMU + barometer + GPS, DSHOT ESCs, PX4 on NuttX.

3 min read · 684 wordsupdated · May 12, 2026

A multirotor stays in the air because a Cortex-M7 reads its inertial measurement unit 8000 times per second, runs an extended Kalman filter, and updates four motor PWM outputs faster than the human reaction time. Lose any one of those, lose the aircraft. This is hard real-time at its purest.

At a glance

At a glance
Product class
Open-source FC for racing / fixed-wing / multirotor (Pixhawk-class)
Newer designs
Renesas RA8M1 (Cortex-M85) — Helium for ML, faster scalar
RAM
1 MB SRAM + 64 KB ITCM + 128 KB DTCM
Flash
2 MB internal (dual-bank for safe update)
Sensors
2× IMU (redundant), barometer, magnetometer, optical flow, lidar
Connectivity
GPS (UART), telemetry radio (UART), R/C receiver (SBUS/CRSF), CAN
Outputs
8–16 PWM/DSHOT channels to ESCs
Control loop
8 kHz attitude, 1 kHz EKF, 100 Hz position
Certifications
None for hobby, DO-178C for commercial UAS (rare)

Why Cortex-M7 specifically

The control loop budget on an 8 kHz attitude controller is 125 µs per iteration. In that window the firmware must:

  1. Read both IMUs over SPI (gyro + accel + temp = 14 bytes × 2 = 28 bytes).
  2. Apply calibration, temperature compensation, and a low-pass filter.
  3. Run the inner-loop PID controller (rate → motor command).
  4. Mix the four-motor allocation matrix.
  5. Update the four PWM/DSHOT outputs.

A Cortex-M4 at 168 MHz can just barely do this without the FPU; an M7 at 480 MHz with cache + dual-issue does it with ~20% CPU headroom. The headroom is what lets you add velocity estimation, log to SD, stream MAVLink telemetry, and respond to mode changes — all without missing a control deadline.

Block diagram

Pixhawk-class flight controller — sensors → control → actuators
corememoryradioperiph
SPI 8 kHzI²C / UARTcontrolIPCDMA bufDSHOTRedundant IMUsSPI · 8 kHz gyro/accelNavigation sensorsbaro · mag · GPSRC receiverSBUS/CRSF · UARTCortex-M7 real-time core480 MHz · FPU · ITCM/DTCMDeterministic memoryITCM 64K · DTCM 128KSafety state machinefailsafe · arming · watchdogCortex-M4 companionlogging · telemetryLogs + telemetrySD card · USB · radioCAN-FD ×2DroneCAN nodesAdvanced timersDSHOT600 · DMA buffer4× ESCbrushless drivers4× BLDC motorBattery monitorV · I · cell count
Hard real-time data flows left→right. The IMU SPI bus runs at 8 kHz; gyro→Clarke→PID→DSHOT round-trip completes in <125 µs. Logging and telemetry are deliberately exiled to the M4 so they can never delay the M7's control loop.

The 8 kHz attitude loop

Single most important code path in the firmware:

// Pseudocode — runs from ITCM, ISR triggered by TIM5 at 8 kHz
__attribute__((section(".itcm.text"), no_inline))
void attitude_loop_isr(void) {
    uint32_t start = DWT->CYCCNT;            // for timing watchdog
 
    // 1. Pull fresh IMU samples (already in DTCM via DMA)
    imu_sample_t s = imu_samples[imu_select_best(/* health */)];
 
    // 2. Apply notch filter to remove motor-frequency vibration
    rate_filtered = notch_apply(s.gyro);
 
    // 3. Inner-loop PID: rate setpoint → torque demand
    torque = pid_rate.update(rate_setpoint, rate_filtered);
 
    // 4. Mixer: torque + thrust → 4× motor demands
    motor_mix(torque, thrust_setpoint, motors);
 
    // 5. Write to DSHOT600 timer DMA buffer (4 channels)
    dshot_write(motors);
 
    // 6. Watchdog — fail if we're more than 80 µs in
    if (DWT->CYCCNT - start > 38400) panic("attitude overrun");
}

Notable details:

  • No malloc, no logging, no waiting on a mutex. Anything that can block is banned.
  • Notch filters are critical because brushless motors generate strong vibration at their commutation frequency, which appears in the gyro as broadband noise. Adaptive notches (PX4 calls them "harmonic notch") track the motor RPM and follow the noise peak.
  • DSHOT (digital signal for ESCs) is a 16-bit serial protocol where the throttle value is sent over a single PWM line at 150 / 300 / 600 / 1200 kHz. Generated via the timer's DMA + advanced-timer hardware.
  • DWT cycle counter is the precision timestamp for the watchdog. See SysTick & timing.

The EKF (state estimation)

The inner loop knows the rate (gyro). To know the attitude (rotation) and position, the firmware runs an Extended Kalman Filter at 250 Hz – 1 kHz that fuses:

  • Gyro (high frequency, drifts over seconds)
  • Accelerometer (low frequency, noisy short-term)
  • Magnetometer (heading, low frequency, distorted by motors)
  • GPS (position + velocity, ~10 Hz, ~2 m accuracy)
  • Barometer (altitude, 50 Hz, slow drift)
  • Optical flow (velocity, available indoors, when present)

PX4's EKF2 (ekf2) and ArduPilot's EKF3 are both 24-state filters running on the Cortex-M7. Each iteration ≈ 200–500 µs depending on which observations are being incorporated. The matrix math relies heavily on the FPU.

Software stack

ArduPilot runs on ChibiOS. PX4 runs on NuttX (a POSIX-like RTOS — see the RTOS landscape). Betaflight (racing/freestyle drones) runs essentially bare-metal with a tiny scheduler.

Boot ROM → custom bootloader → flight stack
                                    │
                                    ▼
                            ┌────────────────────┐
                            │ Sensor drivers     │  SPI/I²C tasks
                            │ Estimator (EKF)    │  250 Hz – 1 kHz
                            │ Controllers (PID)  │  8 kHz attitude, 100 Hz pos
                            │ Mixer + outputs    │
                            │ Logging (uLog/.bin)│  to SD or via MAVLink
                            │ MAVLink telemetry  │  over radio + USB
                            │ Failsafe state-mach│
                            └────────────────────┘

Failsafes are non-negotiable: if R/C link is lost for >500 ms, auto-RTL (return to launch); if battery <20%, smart-land; if attitude excursion >75° while in stabilize mode, auto-recover or kill. These are tested mercilessly because the alternative is hardware in trees.

Real products

ProductMCUNotes
Holybro Pixhawk 6XSTM32H753 + STM32F103 IO MCUStandard reference; multi-IMU redundancy
Holybro Pixhawk 6CSTM32H743Single-MCU, cost-optimized
CUAV V5+ / Nora+STM32H753Industrial-grade, popular in commercial UAS
Matek H743-WINGSTM32H743Fixed-wing optimized, integrated PDB
Mateksys H743 SLIMSTM32H743Tiny FPV racing form factor
mRo X21STM32F765 (older)Compact open-source design

Newer 2024+ designs are starting to use STM32H7+ dual-core, Renesas RA8M1 (Cortex-M85), or NXP i.MX RT1170 — all aimed at running ML-based vision/obstacle-avoidance alongside the traditional flight stack.

Tradeoffs you make

  • More CPU headroom = more features — vibration analysis, log rate, MAVLink streams, vision filters.
  • More peripherals = more wiring complexity — every UART is a connector; every connector is a failure mode.
  • Dual-core (H757) = simpler timing — M7 owns the fast loop, M4 owns logging + telemetry, neither preempts the other.
  • Hard vs. soft failsafes — DSHOT bidirectional gives you actual motor RPM feedback, enabling smarter failsafes. Costs extra CPU.

See also