NavHAL

Interface Design (APIs)

The interface design of NavHAL is centered around simplicity, consistency, and explicit control over hardware behavior. The API is intentionally designed to provide a development experience similar to high-level frameworks, while preserving the determinism and performance required in real-time embedded systems.

Design Principles

The following principles guide the API design:

  • Simplicity: APIs are designed to be minimal and intuitive, reducing the amount of boilerplate required for common operations.

  • Consistency: All peripherals follow a uniform naming and usage pattern, enabling developers to interact with different modules using a predictable interface.

  • Explicit Configuration: Hardware configuration is always performed explicitly by the user, avoiding hidden initialization or implicit behavior.

  • Low Overhead: APIs are implemented as lightweight functions, with internal operations resolved using inline functions and macros to minimize runtime cost.

  • Hardware Abstraction: Peripheral identifiers and configurations abstract underlying hardware details, allowing code to remain portable across platforms.

API Structure

NavHAL follows a consistent naming convention across all modules:

hal_<peripheral>_<operation>

Examples include:

  • hal_gpio_setmode()

  • hal_gpio_digitalwrite()

  • hal_uart_init()

  • hal_i2c_read()

This structure ensures that all peripherals expose a uniform and predictable interface.

Example: GPIO Interface

A representative example of the API design is shown below:

#define CORTEX_M4
#include "navhal.h"

int main(void)
{
    systick_init(1000); // 1 ms tick

    hal_gpio_setmode(GPIO_PA05, GPIO_OUTPUT, GPIO_PUPD_NONE);

    while (1)
    {
        hal_gpio_digitalwrite(GPIO_PA05, GPIO_HIGH);
        delay_ms(100);
        hal_gpio_digitalwrite(GPIO_PA05, GPIO_LOW);
        delay_ms(100);
    }
}

This example highlights key characteristics of the interface:

  • Readable and Minimal: The code closely resembles high-level frameworks, reducing the learning curve.

  • Explicit Timing Control: System timing is initialized explicitly using systick_init(), ensuring predictable behavior.

  • Abstract Pin Representation: Identifiers such as GPIO_PA05 abstract the underlying hardware mapping, enabling portability.

  • Deterministic Execution: No hidden scheduling or background processes are involved; all operations are directly controlled by the application.

Compile-Time Resolution

NavHAL APIs are designed such that most hardware-specific details are resolved at compile time. Peripheral identifiers are represented as compile-time constants, which are translated into register-level operations through inline functions and macros within the core and vendor layers.

This approach ensures that API usage does not introduce significant runtime overhead, and that generated code remains close to hand-written low-level implementations.

Design Trade-offs

To maintain simplicity and performance, NavHAL avoids introducing complex configuration objects or runtime polymorphism. While this reduces flexibility in dynamic scenarios, it ensures predictable behavior and minimal overhead, which are critical in embedded flight control systems.

Additionally, NavHAL does not manage resource ownership or concurrency. These responsibilities are delegated to the execution layer when required, allowing the API to remain lightweight and execution-model agnostic.