cancel
Showing results for 
Search instead for 
Did you mean: 

Benefits of HAL over LL for simple peripherals

dfrejek
Associate II

Hi guys,

I am wondering, if there is any “real” benefit in using the HAL over the LL for simple peripherals like GPIO, ADCs or Timers.

So far it looked to me like the HAL does not make the user code more compact or readable. Instead, it just gets more bulky and harder to debug since you have to deal with the HAL code as well.

Just as an example, look at the two functions which both do the same. They do a blocking ADC conversion on a given channel. In this case, the LL variant is actually shorter.

static uint16_t read_adc_chn_LL(uint32_t chn)
{
	LL_ADC_REG_SetSequencerChannels(ADC1, chn);
	LL_ADC_REG_StartConversion(ADC1);
	while (LL_ADC_REG_IsConversionOngoing(ADC1));
	return LL_ADC_REG_ReadConversionData12(ADC1);
}

static uint16_t read_adc_chn_HAL(uint32_t chn)
{
	ADC_ChannelConfTypeDef sConfig = {0};
	sConfig.Channel = chn;
	sConfig.Rank = 1;
	sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES;
	HAL_ADC_ConfigChannel(&hadc1, &sConfig);
	
	HAL_ADC_Start(&hadc1);
	HAL_ADC_PollForConversion(&hadc1, 1000);
	return HAL_ADC_GetValue(&hadc1);
}

A similar thing is also true for timers. I get the benefits of the HAL for more complex peripherals like I2C or UART since the HAL offers some convenient functions for this, but I fail to see the benefit of using the HAL in these simple cases.

Am I missing something important here?

 

Cheers,

D.Frejek

1 ACCEPTED SOLUTION

Accepted Solutions
Andrew Neil
Evangelist III

The big difference between your 2 examples is that the LL one relies on a whole bunch of defaults, whereas the HAL one does a complete config.

A common problem seen on forums like this is of the form, "my code works once, but not after that", and a common reason for that is relying on default conditions which no longer apply after the first time...

 

EDIT:

Another example just now where defaults can catch you out:

https://community.st.com/t5/stm32-mcus-products/h7-migration-send-spi-without-using-hal/m-p/701807/highlight/true#M256154

 

View solution in original post

6 REPLIES 6
Andrew Neil
Evangelist III

The big difference between your 2 examples is that the LL one relies on a whole bunch of defaults, whereas the HAL one does a complete config.

A common problem seen on forums like this is of the form, "my code works once, but not after that", and a common reason for that is relying on default conditions which no longer apply after the first time...

 

EDIT:

Another example just now where defaults can catch you out:

https://community.st.com/t5/stm32-mcus-products/h7-migration-send-spi-without-using-hal/m-p/701807/highlight/true#M256154

 

TDK
Guru

HAL is generally more robust and easier to work with. It takes care of many gotchas that you would otherwise have to learn the hard way.

But ultimately it's your choice. They can both work. The best tool is often the one you're most familiar with.

I strongly recommend direct register access over the LL library, which tends to obfuscate things with no real benefit.

If you feel a post has answered your question, please click "Accept as Solution".
Pavel A.
Evangelist III

 if there is any “real” benefit in using the HAL over the LL for simple peripherals

Is readability of code a real benefit? Imagine that you post a code snippet here, and most of readers understand it, without digging in the manuals.

As Tim wrote - the LL library is unfortunate, it was intended to replace direct register access with more meaningful methods - but for some reasons it has not succeeded much. So, "tends to obfuscate things with no real benefit". Unless, again, readability counts as benefit.

 

dfrejek
Associate II

Thanks for all the replies,

Never thought about LL obfuscating the code, but guess it just changes the names of things without off-loading any of the complexity. Hence, it makes it harder to actually understand what’s going on, even if you have the datasheet open on the side. That being said, I still think its nicer to read than direct register access 🙂

 

I’m not sure if I would call HAL code more readable though. On this forum maybe, since HAL is the default. But, in general I think the HAL functions are still way too hardware specific for code to be easily understandable without prior knowledge of the ecosystem / hardware.
In the end, it really only depends how familiar you are with something.

 

So far, I rarely had the issue to initialize hardware on the fly, since I mostly used the CubeMX code generator to do that for me. In this scenario, the complete initialization is done by generated code anyway, therefore it is hard to miss some important, hardware-specific thing. But yes, the SPI issues in the thread Andrew linked clearly show that there might be other pitfalls.

So, thanks again!

Cheers,

D.Frejek

Nikita91
Lead II

An important feature of HAL is that it is generic: it handles all possible cases for a whole family of MCUs, and sometimes more.

Example: A UART can have several clock sources, and with HAL you just have to tell it the desired baud rate. HAL manages to determine which clock is configured for this UART (with big switch instructions) and configures the register.

If you know which clock is used (because you configured it anyway), you only need a division and a register write to do the same thing. Gain for just this register ~800 bytes and execution time.

It is easy to use HAL when you have a lot of resources available (FLASH and execution time). Otherwise you have to use register access, and LL which is often more readable (LL gives names to each bit group of registers, which CMSIS does not do).

See for example:
https://community.st.com/t5/stm32-mcus-products/stm32-with-small-flash-hal-debug-no-optimization/td-p/700981 

Personally I only use direct register access and LL. And I don't consider a UART as a complicated peripheral. But STM's I2C is complicated!

LCE
Principal

Let's have a look at the naming: Hardware Abstraction Layer

IMO, HAL has some good points:

- as starting point, esp. for (STM32-) beginners

- for software people who want to get something quickly without bothering about hardware registers (and then failing when it gets into details)

- many HAL parts are compatible over several STM32 types

 

On the other hand:

- because of its bazillions of options and compatibilities it's blown up like crazy, which makes it hard to read, understand and debug - and takes tons of flash

- an electronics engineer should be a "control freak" and exactly know what's going on in a device (-> direct register access), and with HAL you're giving away lots of this

- new HAL versions might create incompatibilities anyway (hello to ETH)

 

LL stuff is somewhere in-between, IMO still too far from 100% control.