hal
Hardware Abstraction Layer
HAL

Overview

This project is an experiment in building a testable hardware-abstraction layer for the STM32F4 from first principles, oriented toward flight-control–class embedded systems. It addresses the tension between development speed and rigor through automated testing, modern tooling, containerized builds, and continuous integration.

The HAL provides a small set of purpose-built drivers (UART, I2C, PWM, timers, GPIO) built around a classic embedded architecture: a super-loop execution model with interrupt-driven peripherals, no RTOS, no DMA, and strictly static memory. Its scope is intentionally narrow and includes only the primitives required for embedded control workloads, avoiding generic configuration layers, dynamic allocation, and broad peripheral coverage. The design favors simplicity, predictability, and testability over configurability or feature breadth.

Architecture

Layer Descriptions

  • Applications - Logic executed in the project’s super-loop (main.c).
  • Hardware Abstraction Layer - Public interfaces in include/hal.
  • STM32F4 Peripheral Drivers - Implementations in src that operate directly on device registers.
  • Device Support Package - CMSIS and vendor headers plus startup code and the linker script in device.
  • STM32F4 Hardware - The STM32F446RE development board.

Quick Start

Prerequisites

  • A UNIX-style command line environment.
  • Have git installed.
  • Have docker installed

Clone

$ git clone git@github.com:cmckiel/hal.git && cd hal
$ git submodule update --init

Build

First, from inside the repo directory, build the docker image:

$ docker build -t hal-build-env .

Next, run the docker image, mounting the repo dir. This command launches an interactive shell inside the container. (Commands executed inside the container are distinguished by #)

$ docker run --rm -it -v "$PWD":/workspace -w /workspace hal-build-env

If needed: exit the docker container by pressing ctrl-p followed quickly by ctrl-q.

Build for desktop:

# cmake --preset desktop-debug
# cmake --build --preset desktop-debug

Run the unit tests:

# ctest --preset desktop-debug

Build for target hardware:

# cmake --preset embedded-debug
# cmake --build --preset embedded-debug

Target firmware should be visible in build/embedded-debug/ as .elf and .bin files.

Example Application

#include "uart.h"
#include "gpio.h"
#include "systick.h"
int main(void)
{
uint8_t message[] = "Hello from HAL!";
size_t bytes_successfully_written = 0;
// Print hello message over serial.
hal_status_t status = hal_uart_write(HAL_UART2, message, sizeof(message), &bytes_successfully_written);
// Easy error checking.
if (status != HAL_STATUS_OK || bytes_successfully_written != sizeof(message))
{
// Transmission error handling.
return 1;
}
// Super loop
while (1)
{
/* APPLICATION CODE HERE */
// Example application:
// Toggle onboard LED at 10 Hz.
}
return 0;
}
Toggles the onboard LED.
hal_status_t
Return type for HAL functions.
Definition: hal_types.h:17
@ HAL_STATUS_OK
Definition: hal_types.h:18
hal_status_t hal_gpio_init()
Initialize the module. Must be called only once prior to using toggle.
Definition: stm32f4_gpio.c:21
hal_status_t hal_gpio_toggle_led()
Toggle the onboard LED.
Definition: stm32f4_gpio.c:35
void hal_delay_ms(uint32_t delay)
Delay for a given number of milliseconds.
Definition: stm32f4_systick.c:20
hal_status_t hal_uart_write(hal_uart_t uart, const uint8_t *data, size_t len, size_t *bytes_written)
Write an outgoing byte stream.
Definition: stm32f4_uart.c:71
hal_status_t hal_uart_init(hal_uart_t uart)
Initialize the UART channel associated with the parameter uart. Must be called prior to using the cha...
Definition: stm32f4_uart.c:23
Provides millisecond delays.
Provides serial communication over UART1 and UART2.
@ HAL_UART2
Definition: uart.h:18

Project Integration

To integrate a pre-built HAL release into a CMake project, see Project Integration.

Deployment

See Deployment for detailed instructions to deploy firmware to target hardware.

Coverage

See the code coverage here.

Waveforms

See Waveforms to view representative waveforms captured on target hardware.

License

Licensed under the MIT License; see LICENSE for details.