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

Comments on What exactly is a HAL and how would I write my own?

Parent

What exactly is a HAL and how would I write my own?

+2
−0

When I program STM32 microcontrollers I use ST's toolchain which provides all the tools necessary in order to build (and flash) the application binary. The toolchain also comes with ST's own library (source and header files) that allows me to control the micro's peripherals by using their functions. They group these files under a common name, "HAL", which stands for Hardware Abstraction Layer.

Looking into, for example, the gpio hal I see code like this.

/* stm32f4xx_hal_gpio.c */
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  uint32_t odr;
  assert_param(IS_GPIO_PIN(GPIO_Pin));

  /* get current Output Data Register value */
  odr = GPIOx->ODR;

  /* Set selected pins that were at low level, and reset ones that were high */
  GPIOx->BSRR = ((odr & GPIO_Pin) << GPIO_NUMBER) | (~odr & GPIO_Pin);
}

So in this function they set/reset some register bits (alter the hardware) and the result of setting these bits is that a pin is toggled (on a higher abstraction layer).

So is a HAL really just a collection of functions that when called set/reset specific register bits for my specific microcontroller? If so, is it really necessary to call it a HAL?

History

0 comment threads

Post
+1
−0

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:

  1. 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.
  2. 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.

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.

Added in response to comments to Lundin's answer

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:

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?

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 Embed dspic 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.

History

1 comment thread

Response to edit (2 comments)
Response to edit
Carl‭ wrote 23 days ago

Thank you for the update and response Olin. But I wonder, isn't this directly contradicting what @Lundin wrote here in his answer?: "

/* Check which port that was selected */
  volatile Can* can_port = port;
  if(can_port != CAN0 && can_port != CAN1)
  {
    return CAN_ERR_INIT_HW;                      // port parameter is wrong
  }

(...) What's nice from here is that I may use can_port->register_name to setup all registers so that can_init_port sets up the relevant port only and can be called several times for each existing port. This is a common trick when writing any form of driver code when more than one specific peripheral should be supported."

I was more or less trying to do what he explained in his answer. I 100% agree that which port to use, the baud rate etc. should be known at compile time.

Lundin‭ wrote 23 days ago · edited 23 days ago

Carl‭ My version used a struct Can which comes from Microchip's bloat lib register maps below their own would-be HAL called ASF/Harmony, which is very similar to the ST flavour. As I replied to in the comment in my answer is that if you roll out the register map yourself, then you ought to do something like this:

#define UART1 ((volatile uint8_t*)0x1234U) ... #define UART_SR(base) (*(base + 1u)) ... #define UART_DR(base) (*(base + 2u))

Which is the same remark as Olin did - this will probably get resolved at compile time, not run-time as in your example. Although volatile itself might prevent various optimizations so you have to check what code it boils down to. Maybe base should just be the raw register address - that would be fine too.