MAVLINKHUD

Threading & Scheduling

Executive Summary

While the ArduPilot Flight Code (Copter/Plane) is largely single-threaded (the "Main Loop"), the underlying system is highly multi-threaded. AP_HAL_ChibiOS creates dedicated threads for I/O, storage, and RC handling to ensure that slow operations (like writing to an SD card) never block the flight stabilization loop.

Theory & Concepts

1. Static Thread Allocation

In embedded safety-critical systems, dynamic thread creation is risky (heap fragmentation). ChibiOS allows Static Allocation:

  • Working Area: A statically defined array (e.g., static THD_WORKING_AREA(_io_thread_wa, 2048);) acts as the stack for the thread.
  • Benefits: We know exactly how much RAM is used at compile time.

2. Cooperative vs. Preemptive

  • ArduPilot Main Loop: Runs in the main thread. It is cooperative internally (tasks must yield), but the thread itself is preemptable by the OS.
  • Driver Threads: Run asynchronously. For example, the UART driver receives bytes via DMA and signals a semaphore to wake up the I/O thread.

Codebase Investigation

1. Thread Creation: Scheduler::init()

Located in libraries/AP_HAL_ChibiOS/Scheduler.cpp.
ArduPilot spawns the following core threads:

  1. _timer_thread: Runs 1kHz periodic tasks.
  2. _rcin_thread: Decodes PPM/SBUS signals.
  3. _io_thread: Low-priority background tasks (logging, files).
  4. _storage_thread: Handles EEPROM/FRAM emulation on flash.
  5. _monitor_thread: Watchdog that checks for thread lockups.

2. The Yield: delay_microseconds()

When the main loop calls hal.scheduler->delay(1), it calls chThdSleep(ticks).

  • This moves the Main Thread to the SLEEPING state.
  • The ChibiOS scheduler immediately context-switches to the next highest priority READY thread (e.g., UART processing).

3. Priority Hierarchy

Priorities are defined in AP_HAL_ChibiOS.h (mapped to ChibiOS levels):

  1. SPI/I2C High Priority: Drivers that need instant bus access.
  2. Main Thread (Flight Loop): Above normal I/O.
  3. Timer Thread: 1kHz ticks.
  4. RC Input: Needs low latency capture.
  5. IO / Storage: Lowest priority. Can take milliseconds to run without affecting flight.

Source Code Reference

Practical Guide: Analyzing Stack Usage

Running out of stack causes a HardFault.

  • Check: Set HAL_CHIBIOS_ENABLE_STACK_CHECK to 1 in hwdef.dat (dev boards only).
  • Monitor: Scheduler::check_stack_free() fills the stack with a pattern (0x55) and counts unused bytes.
  • Output: 'Stack Low' messages in the console/logs if a thread gets dangerously close to its limit.