HAL designing, part 1

By waterproofman

Hardware Abstraction Layer is a part of software that (almost) allows you to forget about hardware you’re working with. In perfect case you can use the same software on different hardware just by changing the hardware layer.

Clean and well designed HAL hides hardware differences and separates software layer responsible for hardware managing from main application functionality.

There are some issues to consider before designing and coding HAL…

Memory and time…

Simple example below. We need some text debug output working on rs232 in our application.

C_Debug class uses pointer to C_Uart object. C_Uart is an abstract class, part of Hardware Abstraction Layer. Because Send and Receive are pure virtual methods C_Debug class doesn’t know what is the exact uart peripheral. If you implement your own C_Uart<microcontroller_name> class with Send method, you will not have to rewrite software which uses C_Debug.

Of course it’s not so perfect. Virtual methods aren’t so cheap – when you call virtual method there has to be information about exact implementation that should be used. Calling Send method by C_Debug (on pointer pUart) is in fact executing some extra code before executing proper method. Choosing right method is done by checking the virtual table, which should be placed in flash memory.

Of course above uart example is very simple, but imagine bigger HAL with many peripherals – it may cost much memory (vitables) and it may make difficult executing fast functions with exact timing. There are (of course) methods to avoid delays but most of them are more like workarounds then clean solutions.

In Uart example (from this blog) you may see two namespaces – Devs and Periphs. Lets pretend ( :) ) that Devices uses objects from Periphs namespace. The easiest and cheapest way to get portable, HAL alike solution is to cut periphs.h with defines.

#include "uprocdefs.h"
#ifdef UPROC_ATMEGA88
    #include "HAL/ATMega88/uart.h"
#else
    #ifdef UPROC_HC11
        #include "HAL/HC11/uart.h"
    #else
        #error No microcontroller definition!
    #endif
#endif
namespace Periphs
{
    /// UART peripheral.
    extern C_UART UART0;
};

Of course there must be definition of C_UART class in both files and you’ll have to compile proper .cpp file in your project. It could be done in Makefile.
From now on you may use UART0 object from namespace Periphs. There is no virtual methods, C_UART classes from HC11 and ATMega88 directories don’t even need same base class. If C_Debug class uses Send method and this method (same name, parameters and return value type) is implemented in both files this example will work.

Leave a Reply