HWA - HardWare Abstractor

Document created by Christophe Duparquet on Feb 25, 2018Last modified by Christophe Duparquet on May 6, 2018
Version 4Show Document
  • View in full screen mode

About this project

HWA is a low-level hardware abstraction layer that makes hardware-related code much easier to read and write without impacting efficiency.


Project info

Type : software.

Progress : support of STM32 just started, support of a few Atmel AVRs almost complete.

Difficulty : don't be afraid!

License : free software.


The Team

Myself. Volunteers welcome!


Things used in this project

Software Tools

Gnu GCC. Any C11 compatible C compiler should work.



I started this project a few years ago as I was tired of having to dig into the documentation to find the configuration bits I needed to play with my Atmel microcontrollers. Besides, I do not like the way traditional libraries address this issue, being often too much verbose and consuming cycles and memory.


HWA provides generic instructions that accept mandatory and optional symbolic arguments, made of key-value pairs, to act on hardware objects. These instructions make the code very concise, much more easier to write, read, modify, and to port between different targets, and the resulting binary is the same as if one had himself written optimized accesses to the hardware registers.


Though the implementation of the object-oriented mechanisms relies heavily on C macro definitions, errors are handled so that the compiler displays helpful messages.



Although the support of STM32 is barely started, the following example will give you a sight of what using HWA is about (more advanced examples are provided for Atmel devices in which you can see among other things how configuring a timer is a simple task with HWA).

This program configures the clocks of a STM32F103RBT6 to use the internal HSI oscillator and the PLL, and then blinks a LED using the SysTick timer exception:

/*  Include HWA definitions

#include <hwa/stm32f103rbt6.h>

/*  The pin at which the LED is connected. The target device name indicates its
*  package, then pin numbers can be used as well as pin names.

#define LED             pa2

#define SYSHZ           36*1000*1000    // Desired frequency for the SYSCLK signal
#define AHBHZ           9*1000*1000     // Desired frequency for the core (and systick)
#define PERIOD          0.5             // Blinking period

/*  The IRQ is used only to wake the core up.

HW_ISR( systick ) {}

int main ( )
  /*  Create a context to gather the following actions.
   *  Assume RESET values.


  /* Configure the PLL source and multiplier (must be done before it is enabled).
   * Prepare the connection of the sysclk to the pll. The hardware will wait for
   * the PLL to be locked before actually switching.

  hwa( configure,  pll,
       source,     hsi/2,
       multiplier, SYSHZ/(HW_DEVICE_HSIHZ/2) );
  hwa( connect, sysclk, pll );

  /*  Apply the actions on the hardware.


  /*  Turn the PLL on.

  hwa( turn, pll, on );

  /* Wait for the PLL to be locked.

  while ( ! hw(stat,pll).ready ) {}

  /*  Configure the AHB.

  hwa( configure, ahb,
       clock,     sysclk,
       prescaler, SYSHZ/AHBHZ );

  /*  Configure the GPIO pin.

  hwa( power, HW_RELATIVE(LED1,port), on );

  hwa( configure, LED1,
       mode,      digital,
       direction, output,
       frequency, 50MHz );

  /*  Configure the system tick timer.
   *  Use the 'onems' factory-loaded register.

  uint32_t onems = hw(read, HW_REGISTER(systick,onems));
  hwa( configure, systick,
       clock,     ahb,
       reload,    ((uint32_t)(PERIOD/2 / 0.001)*onems - 1) & 0xFFFFFF );
  hwa( turn, systick, on );
  hwa( turn, HW_IRQ(systick), on );

  /*  Toggle the LED between sleeps.

  for(;;) {
    hw_sleep_until_irq();       // hw_sleep_until_event() is OK too.
    hw( toggle, LED );