Skip to main content
Contents3 / 11 ▾
Chapter III

Firmware & RTOS

Hard real-time embedded flight systems demand sub-microsecond timing determinism, strict memory allocation limits, and robust fieldbus communication protocols.

3.1

NuttX vs. bare-metal vs. FreeRTOS — how do you choose for a flight controller?

rating — near-certain

Choosing an OS architecture for flight control requires evaluating real-time determinism against software abstraction convenience.

Table 3.1 — Real-Time OS Architecture Comparison
DimensionBare-Metal Super-LoopFreeRTOSNuttX (PX4 Architecture)
Scheduling ModelSingle non-preemptive loop / ISR interruptsPreemptive priority-based microkernelPOSIX-compliant RTOS microkernel
Memory FootprintMinimal ($<16\text{KB}$ Flash, $<4\text{KB}$ RAM)Small ($<32\text{KB}$ Flash, $<8\text{KB}$ RAM)Large ($>512\text{KB}$ Flash, $>128\text{KB}$ RAM)
POSIX CompatibilityNoneNone (Minimal POSIX wrapper)Full POSIX VFS (`open`, `read`, `pthread`)
Inter-Thread OverheadGlobal variables / volatile flagsDirect Task Notifications / Queue pointersuORB publish-subscribe bus queues
Worst-Case JitterLowest ($<100\text{ns}$)Low ($<1\mu\text{s}$)Moderate ($5-15\mu\text{s}$)

For high-frequency actuator loops ($200\text{kHz}$ motor control), bare-metal or FreeRTOS with static memory allocation (`xTaskCreateStatic`) is mandatory. For full-featured flight stacks with filesystem logging and dynamic driver loading, NuttX provides POSIX APIs at the cost of higher interrupt latency and scheduling jitter.

3.2

Explain your 200kHz EtherCAT/CAN control loop — what makes that hard?

rating — near-certain · your strongest story

At a $200\text{kHz}$ sampling rate, the total timing budget per cycle is precisely **$5.0\mu\text{s}$**. Any CPU stall, cache miss, or dynamic allocation instantly causes deadline overrun.

1. 5.0 Microsecond Cycle Budget Breakdown

  • $0.0 - 1.0\mu\text{s}$: SPI / DMA Sensor Readout: Read raw gyro/encoder registers over high-speed SPI ($40\text{MHz}$) directly into MCU Tightly-Coupled Memory (ITCM/DTCM).
  • $1.0 - 3.0\mu\text{s}$: Control Math Execution: Execute floating-point PI/PD loop. Uses Cortex-M7 hardware single-cycle FPU instructions. Trigonometric calculations use lookup tables. Zero `malloc` calls.
  • $3.0 - 4.2\mu\text{s}$: Actuator Wrench / Motor Command Assembly: Format EtherCAT Process Data Object (PDO) or CAN-FD frame bytes. Write directly to peripheral registers.
  • $4.2 - 5.0\mu\text{s}$: Timing Headroom / Margin: Safety margin reserved for interrupt context switching.

2. Hardware Management: DTCM & Cache Invalidation

Standard MCU SRAM passes through L1 Data Cache, introducing non-deterministic cache-miss latencies ($20-50$ CPU cycles). We map the hot control loop memory directly into **Data Tightly-Coupled Memory (DTCM)** at address `0x20000000`, guaranteeing single-cycle zero-wait-state memory access bypass of cache controllers.

3.3

What is priority inversion, and how do you prevent it?

rating — likely

Priority Inversion occurs when a High-Priority Task ($T_H$) is indirectly blocked by a Medium-Priority Task ($T_M$) because $T_H$ is waiting on a mutex held by a Low-Priority Task ($T_L$). $T_M$ preempts $T_L$ (since $T_M > T_L$), extending $T_H$'s wait time indefinitely.

Priority Inheritance Protocol (PIP) Mechanism

Under PIP, when $T_H$ attempts to acquire a mutex currently held by $T_L$, the RTOS scheduler temporarily elevates the priority of $T_L$ to match $T_H$ ($\text{Priority}(T_L) \leftarrow \text{Priority}(T_H)$). $T_L$ executes without preemption by $T_M$, releases the mutex, and instantly reverts to its original low priority, allowing $T_H$ to acquire the mutex immediately.

// FreeRTOS Mutex Creation with Priority Inheritance Enabled
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex(); 
// Note: FreeRTOS Mutexes (xSemaphoreCreateMutex) automatically implement PIP.
// Binary Semaphores (xSemaphoreCreateBinary) DO NOT implement PIP and must never be used for resource locking!
3.4

CAN bus arbitration vs. EtherCAT synchronization — how do they differ?

rating — likely

CAN and EtherCAT solve fieldbus communication using fundamentally different physical and data-link layer protocols.

1. CAN 2.0 / CAN-FD CSMA/CR Arbitration

CAN is a multi-master broadcast bus using **Carrier Sense Multiple Access with Collision Resolution (CSMA/CR)**. Arbitration occurs bit-by-bit using dominant (`0`, driven low voltage) and recessive (`1`, high impedance) bus states. If Node A transmits CAN ID `0x100` (`00100000000`) and Node B transmits `0x104` (`00100000100`), at the 9th bit Node B sees dominant `0` while outputting `1`, loses arbitration silently, and stops transmitting, allowing Node A's frame to proceed without collision.

2. EtherCAT Distributed Clocks (DC) Synchronization

EtherCAT uses a Master-Slave ring topology with **Processing-on-The-Fly**. An Ethernet frame passes through hardware EtherCAT Slave Controller (ESC) ASICs, which extract and insert data within nanoseconds while the frame flows physically through the chip. **Distributed Clocks (DC)** synchronize all slave hardware timers to a master reference clock by measuring propagation delay $t_{\text{prop}}$ across nodes:

$$t_{\text{prop}} = \frac{(t_4 - t_1) - (t_3 - t_2)}{2}$$

This allows EtherCAT slaves to trigger PWM updates simultaneously with sub-microsecond jitter ($<100\text{ns}$).

3.5

How did you bring up ArduPilot on custom hardware (Strix H7 via DFU)?

rating — likely

Bringing up ArduPilot on a custom STM32H7 flight board follows a rigorous hardware validation pipeline:

  1. Hardware Definition (`hwdef.dat`): Define MCU pin assignments, SPI/I2C peripheral clock mapping, DMA channels, and timer PWM pin assignments for ChibiOS compilation.
  2. DFU Bootloader Flashing: Pull `BOOT0` high, connect USB, and flash the compiled `bootloader.bin` via `dfu-util` or `STM32CubeProgrammer`:
    dfu-util -a 0 -s 0x08000000:leave -D ArduPilot_bootloader.bin
  3. Peripheral Communication Verification: Connect MAVLink GCS console via USB VCP. Query raw SPI sensor registers (e.g., verifying `WHO_AM_I` register `0x75` for MPU6000 / ICM20689 IMUs over SPI).
  4. Sensor & Actuator Calibration Gates: Perform 6-position accelerometer calibration, 3D magnetometer sphere fitting, and verify DShot motor ESC signals on an oscilloscope before mounting propellers.
3.6

Hard vs. soft real-time — where's the line in your stack?

rating — possible

The distinction between hard and soft real-time is defined by the utility function $U(t)$ when a task deadline $T_{\text{deadline}}$ is missed:

  • Hard Real-Time ($U(t) \to -\infty$ for $t > T_{\text{deadline}}$): Missing a deadline constitutes complete system failure (e.g., $200\text{kHz}$ motor commutation loop, EtherCAT DC frame synchronization, EKF IMU prediction step). Handled via dedicated RTOS tasks with high priorities and zero memory allocation.
  • Soft Real-Time ($U(t)$ degrades gracefully for $t > T_{\text{deadline}}$): Missing a deadline degrades system performance but causes no safety risk (e.g., GCS telemetry packet streaming, H.264 video bitrate encoding, UI rendering). Handled on Linux compute nodes using standard POSIX threads (`SCHED_OTHER`).