Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Post History

60%
+1 −0
Q&A What exactly is a HAL and how would I write my own?

A HAL (hardware abstraction layer) tries to present a common software interface to different underlying hardware. This is done by re-writing the HAL to each specific hardware it supports. In a se...

posted 27d ago by Olin Lathrop‭  ·  edited 23d ago by Olin Lathrop‭

Answer
#2: Post edited by user avatar Olin Lathrop‭ · 2026-08-24T21:04:46Z (23 days ago)
  • A HAL (hardware abstraction layer) tries to present a common software interface to different underlying hardware. This is done by re-writing the HAL to each specific hardware it supports. In a sense, a HAL is really a specification for a software interface applications can use to manipulate hardware.
  • The advantage to the application developer is that you can write your application to call HAL functions instead of directly accessing the hardware, which then allows the app to be easily ported to different hardware also supported by the same HAL. The disadvantage is that the common interface presented by the HAL may not provide access to every detailed feature of all underlying hardware. The application interface to the HAL has to be generalized somewhat, so may not always allow applications to use the most efficient method, or not access all hardware capabilities.
  • No, a HAL is never required, but it can be a good idea to use one because:<ol>
  • <li>If you ever want to port your app to different hardware that is also supported by the HAL you used, then in theory, no changes to the app are required other than linking to the HAL version specific to the new target hardware.
  • <li>Some peripherals can be rather complicated to use. Presumably the HAL designers are intimately familiar with the specific hardware versions that are targeted, and have already done the detailed setting up and managing of those target hardwares.
  • </ol>
  • On the other hand, if you want to use an exotic feature of a particular hardware version, are sure you will never want to port the app, or are interested in learning the hardware details, then you can write directly to the hardware registers.
  • A HAL (hardware abstraction layer) tries to present a common software interface to different underlying hardware. This is done by re-writing the HAL to each specific hardware it supports. In a sense, a HAL is really a specification for a software interface applications can use to manipulate hardware.
  • The advantage to the application developer is that you can write your application to call HAL functions instead of directly accessing the hardware, which then allows the app to be easily ported to different hardware also supported by the same HAL. The disadvantage is that the common interface presented by the HAL may not provide access to every detailed feature of all underlying hardware. The application interface to the HAL has to be generalized somewhat, so may not always allow applications to use the most efficient method, or not access all hardware capabilities.
  • No, a HAL is never required, but it can be a good idea to use one because:<ol>
  • <li>If you ever want to port your app to different hardware that is also supported by the HAL you used, then in theory, no changes to the app are required other than linking to the HAL version specific to the new target hardware.
  • <li>Some peripherals can be rather complicated to use. Presumably the HAL designers are intimately familiar with the specific hardware versions that are targeted, and have already done the detailed setting up and managing of those target hardwares.
  • </ol>
  • On the other hand, if you want to use an exotic feature of a particular hardware version, are sure you will never want to port the app, or are interested in learning the hardware details, then you can write directly to the hardware registers.
  • <h2>Added in response to comments to Lundin's answer</h2>
  • This is really a response to Carl's comment to Lundin's answer, but ended up being too much for a comment. Besides, this is real content that shouldn't be buried in a comment.
  • Carl wrote: <blockquote>
  • With regards to the init function, there is a way to infer all the necessary registers from just the port parameter. For the microcontroller I'm using, the USART registers for port 0 are UCSR0A (0xC0), UCSR0B (0xC1), UCSR0C (0xC2). USART port 1 shows same 1 byte offset in memory, so I thought of something like this for the init function:
  • usart_status_t usart_init_port(volatile void* port, ...)
  • {
  • volatile uint8_t* usart_port = port;
  • if(usart_port != &UCSR0A && usart_port != &UCSR1A)
  • {
  • return USART_ERR;
  • }
  • volatile uint8_t* ucsrna_ptr = usart_port;
  • volatile uint8_t* ucsrnb_ptr = ucsrna_ptr + 1u;
  • volatile uint8_t* ucsrnc_ptr = ucsrna_ptr + 2u;
  • uint8_t ucsrna = *ucsrna_ptr;
  • uint8_t ucsrnb = *ucsrnb_ptr;
  • uint8_t ucsrnc = *ucsrnc_ptr;
  • /* Set up temporary "register" variables below ... */
  • //Assign values to hardware registers
  • *ucsrna_ptr = ucsrna;
  • *ucsrnb_ptr = ucsrnb;
  • *ucsrnc_ptr = ucsrnc;
  • }
  • Pointer arithmetic is not MISRA compliant though. Is this a good idea?</blockquote>
  • No, it is not. This does at run time what should be done at build time. You know which UART you are using at build time. The run time code shouldn't be determining which registers it uses. All the information is available at build time. That's when the registers should be resolved, with the runtime code writing directly to those registers.
  • This is what preprocessors are for. Take a look at my UART_MODBUS.INS.DSPIC file (driver or HAL for a dsPIC UART with additional capabilities to support Modbus). in the <a href="https://github.com/EmbedInc/dspic">Embed dspic</a> repository on GitHub. Up to line 311 is all preprocessor computations. In particular look at the PICK block starting on line 226. This does exactly what you are asking for, which is to find which registers are used by the specific UART. It also identifies fields in other system registers, like the interrupt mask bit, enable bit, and priority.
  • See also the file QQQ_UART_MODBUS.DSPIC. That is the template file that is copied and modified for each application. The application writer selects all the features by setting the appropriate constant values, then the previous file is included which derives everything else from those constants.
  • This example is implemented with my PIC and dsPIC assembler preprocessor, PREPIC. PREPIC is in turn implemented on the Embed scripter, ESCR. However, the concept applies to pre-processing in general.
#1: Initial revision by user avatar Olin Lathrop‭ · 2026-08-21T00:35:29Z (27 days ago)
A HAL (hardware abstraction layer) tries to present a common software interface to different underlying hardware.  This is done by re-writing the HAL to each specific hardware it supports.  In a sense, a HAL is really a specification for a software interface applications can use to manipulate hardware.

The advantage to the application developer is that you can write your application to call HAL functions instead of directly accessing the hardware, which then allows the app to be easily ported to different hardware also supported by the same HAL.  The disadvantage is that the common interface presented by the HAL may not provide access to every detailed feature of all underlying hardware.  The application interface to the HAL has to be generalized somewhat, so may not always allow applications to use the most efficient method, or not access all hardware capabilities.

No, a HAL is never required, but it can be a good idea to use one because:<ol>

<li>If you ever want to port your app to different hardware that is also supported by the HAL you used, then in theory, no changes to the app are required other than linking to the HAL version specific to the new target hardware.

<li>Some peripherals can be rather complicated to use.  Presumably the HAL designers are intimately familiar with the specific hardware versions that are targeted, and have already done the detailed setting up and managing of those target hardwares.

</ol>

On the other hand, if you want to use an exotic feature of a particular hardware version, are sure you will never want to port the app, or are interested in learning the hardware details, then you can write directly to the hardware registers.