Post

HAL and the Abstraction Layer for Register Access

As hardware vendors expose low-level functions to access device registers, we use those functions to port software to a board — for example to run Linux or FreeRTOS.
But drivers do not call vendor functions directly. Instead, there is a thin abstraction layer between drivers and the vendor HAL.

Short description
Vendors provide HAL primitives (register read/write, hal_i2c_write, SPI ops, clock/reset helpers). Driver authors use a small, generic API from the abstraction layer (e.g. i2c_transfer) and state what they want done. The abstraction layer maps that intent to the board-specific HAL call that actually touches registers.

How it feels for a driver writer
You don’t worry about vendor API names or register sequences — you call the generic API and handle results. The platform-specific mapping is handled elsewhere.

Simple request flow

  • Driver: calls i2c_transfer(request) — expresses intent (transfer data).
  • Abstraction layer: inspects board/hardware config and converts the request.
  • HAL: executes hal_i2c_write(...) (or equivalent) and performs register access.
  • Result flows back up to the driver.

Why this design

  • Reuse: same driver runs on multiple boards by swapping HAL implementations.
  • Isolation: hardware quirks and register details stay inside HAL.
  • Easier porting and maintenance: change HAL to support new board; drivers remain unchanged.

Quick notes

  • The abstraction layer is small but essential — it’s the glue between generic driver logic and vendor specifics.
  • For complex buses (I²C, SPI, MMIO) the layer may include setup, timing adjustments, and error mapping.
  • Keep driver code intent-focused and lightweight; push board-specific code into HAL.

HAL-in-Kernel

This post is licensed under CC BY 4.0 by the author.