cancel
Showing results for 
Search instead for 
Did you mean: 

Note to ST: HAL & STM32CubeMX are awesome!!!

Code Wrangler
Associate III
Posted on September 18, 2017 at 19:27

To ST Microelectronics (especially the programmers who work on HAL & STM32CubeMX):

I see a lot of bellyaching on these forums (especially from knowledgeable grizzled veterans) complaining about the HAL (Hardware Abstraction Library) and the STM32CubeMX configurator program. Here is my counterpoint to that:

STM32CubeMX: This tool has saved me so much time. Being able to move a pin in secondsjust by making a few clicks and regenerating the code is a godsend. Not to mention having pin variable names auto-generated fromuser labels so that the code is nice and understandable.

But the best part is how many bugs I've manage to avoid by having the graphical tool prevent me from doing something stupid and/or impossible. I'll try to create a setting, for example setting the memory width and peripheral width to different values without the FIFO enabled and it won't let me - So I look in the datasheet and see that isn't allowed.

And don't even get me started on clock configuration. Not having to deal with weird clock divider and multiplier coefficients and formulasis priceless. And being warned that intermediate clocks are not acceptable (like for example the USB clock not being 48 MHz) saves much precious time and head-scratching trying to figure out why things don't work.

Pin layout is a breeze with Cube. The number of pin assignment permutations on a 208-pin chip with multiple possible functions on each pin is staggering. It makes my head hurt just to think about how much time I wasted in years past assigning and moving pins.

Using comment lines to delineateauto-generated code blocks from user code blocksis a genius idea. I don't understand the people who advocate running STM32CubeMX once and then doing all further customizations manually (i.e. not regenerating the code). I've run 'Generate Code' hundreds of times over the course of this project as I've added new functionality or needed to move pins or change settings. The amount of time savings is incredible. And being able to avoid bugs during each regeneration cycle via the rules built into the graphical tool has saved incalculable amounts of debugging time as well.

HAL (Hardware Abstraction Library): I previously used the SPL (Standard Peripheral Library) and it was better than raw register access, but I am really impressed with how much better the HAL is. The biggest complaint on these forums about HAL is that it is 'bloated'. Well, yeah, if you actually go into the source code, you see that it is bloated for a reason. The HAL interrupt handlers take care of hundreds of maddening corner cases that normally would cause subtle bugs and require hours of debugging. And no one is required to use them - If you think they are too bloated, take the boilerplate HAL code, strip out the parts you don't need, optimize the parts that you do need, and replace the existing HAL interrupt handler with your new custom handler above it like so:

void SPI1_IRQHandler(void) {  /* USER CODE BEGIN SPI1_IRQn 0 */   My_Special_Custom_SPI1_IRQ_Handler();  return;   // HAL interrupt handler below never gets called   /* USER CODE END SPI1_IRQn 0 */   HAL_SPI_IRQHandler(&hspi1);   /* USER CODE BEGIN SPI1_IRQn 1 */  /* USER CODE END SPI1_IRQn 1 */ }�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Having the boilerplate initialization code and program skeleton auto-generated again saves so much time. And much if not all of the initialization code is not time-critical, so who cares about an extra 10 milliseconds of startup time over hand-crafted C or assembly in exchange for saving tens or hundreds of hours of programmer time AND having clean and understandable initialization routines.

Of course, for highly time-critical routines, hand crafted C or assemblywith directregister accessis called for, but that usually constitutes a tiny fraction of the codebase.

Anyway, I just wanted to express my appreciation of your efforts. In my opinion, these tools (and the powerful STM32 chips) put ST head and shoulders over the competition.

#idiocracy

Note: this post was migrated and contained many threaded conversations, some content may be missing.
49 REPLIES 49
Posted on September 19, 2017 at 14:30

We are not using assembler to make our own mail software or text editor and so on.

We don't do mail clients or text editors on Cortex M microcontrollers.

We use Windows, or some clone, ...

We do not.

You are comparing apples with oranges.

But the reason I write is because I disagree on that HAL or any other API hides or prevents deeper knowledge.

But it does in no way encourage deeper knowledge.

The incentive must come from the user himself.

Most works do not need bit level work with settings.

Many companies/R&D departments strongly disagree on this assumption. Minimal resource usage and minimal costs are the ultimate goal.

And with a good starting point, API or what ever, you can always study more if there is need, but only if you want/need to.

True for some environments, but not others. Did you ever had to meet a deadline ?

Posted on September 20, 2017 at 01:31

Vasile Guta_Ciucur wrote:

Have you looked at the Low Level driver? It completes the ST-M package very well and is the best solution for the people complaining about HAL - it is for me.

Thanks for the suggestion. You know, I've been meaning to check out the LL library for a while now, but never got around to it. But your recommendation will push me to really do it.

I use HAL for my non-time critical stuff and like its readability, but I do direct register access in my interrupt handlers and time-critical code. Unfortunately, it produces some really ugly code like this:

Motor3_Direction_GPIO_Port->BSRR = (uint32_t)Motor3_Direction_Pin << 16U; // Low�?�?�?

I have to keep that comment on the end because if I don't look at the code for a while, I'll forget if it's a set or reset. I was thinking about writing some macros to hide all that stuff and put the code inline like this:

SetPin(Motor3_Direction_GPIO_Port, Motor3_Direction_Pin, SET);�?

But I have a feeling that's what the LL library does and I'd rather use a standard library than roll my own.

Posted on September 20, 2017 at 02:08

LL_GPIO_SetOutputPin(LED_Blue_GPIO_Port, LED_Blue_Pin);�?

Thanks man! Love it - So much cleaner.

Posted on September 20, 2017 at 13:33

Hmm. Just checked the disassembly and the compiler isn't inlining the LL functions at all. I need to figure out why if I want to keep using the LL driver library.

Posted on September 20, 2017 at 14:22

Do a test application in HAL and try the equivalent in LL. It will be smaller and faster. ST says that LL is for better performance. It is not completely implemented for all microcontrollers as CubeMX has some problems (though, LL drivers are complete and with a lot of example applications), as not generating the complete code, but it is work in progress and I think that LL is the future. If not, try to see if libopencm3 has complete support for your micro.

Posted on September 20, 2017 at 14:36

Realistically, I see Cube & HAL as a tool to attract casual hobbyists and especially students and prospective developers.

It doesn't have to be perfect or even ready for commercial operation, just allow an entry on a very superficial level.

The goal is to pull the future developers and deciders into the 'ST corner' - the same strategy other companies use when giving their expensive software to students for free (think MS Office, Autocad, etc.).

And as such, Cube seems to work quite well.

When the first steam engine operated railways were established more than 150 years ago, it was an awesome experience for people who were accustomed to walk ...

Posted on September 20, 2017 at 16:51

So it turns out that 'inline' doesn't really mean 'inline' to GCC. Rather, it is more like a hint that GCC is free to ignore. And does ignore in the default setting without optimizations (-O0).

Basically, if you want the LL driver library functions to be inlined (and thus actually improve the performance over HAL), you need to specify an optimization level (i.e. -O1, -O2, -O3, -Os, -Og). I recommend -Og for debug builds as it doesn't enable optimizations that break the ability to debug. It appears that any optimization level past -O0 will inline functions.

I will write a separate post about this. I only noticed this because I was switching all my direct register access code over to LL and looked at the disassembly window when I hit a breakpoint.

Posted on September 20, 2017 at 17:03

I always optimize for size, -Os (I generate the project for Makefile and edit it). The result is much smaller than a similar project with HAL.

######################################
# building variables
######################################
# debug build?
DEBUG = 0
# optimization
OPT = -Os�?�?�?�?�?�?�?

Posted on September 20, 2017 at 17:11

So it turns out that 'inline' doesn't really mean 'inline' to GCC. Rather, it is more like a hint [...]

Actually, it *is* a hint, and it is so according to the standard. C99 6.7.4#5

[...] Making a function an inline function suggests that calls to the function be as

fast as possible. 120) The extent to which such suggestions are effective is implementation-defined.

And gcc, as all C99-compliant compilers should,

https://gcc.gnu.org/onlinedocs/gcc/Hints-implementation.html#Hints-implementation

the behaviour also for this implementation-defined feature:

GCC will not inline any functions if the

-fno-inline

option is used or if

-O0

is used. Otherwise, GCC may still be unable to inline a function for many reasons; the

-Winline

option may be used to determine if a function has not been inlined and why not.

JW

PS. You might want to look also at the

always_inline

function attribute.
Posted on September 20, 2017 at 17:26

I'm already tired of repeating - the level of iron and the level of the program can not be confused. In a couple of months, we no longer remember how the engine physically turns on - a logical zero, or a logical unit. But you will be able to read a simple abbreviation, according to which the work of the engine is determined. The level of iron can partially migrate to a new project - in this case you will not help either HAL or LL.

However, if you initially use simple substitutions, then the work is much simpler.

// iron level

typedef enum

{

ON = 0,       // output voltage

OFF = 1,      

 // earth at the outlet

}Motor3_state;

// change values if there is an inversion on the motor current amplifier

♯ define Motor3_pin (uint16_t) 1<<5 // pin number (as an example)

♯ define Motor3_port GPIOB->BSRR // port name (as an example)

// simple function

static inline void Motor3 (Motor3_state form)

{ Motor3_port = (uint32_t) ((Motor3_pin << 16) | (Motor3_pin ^ (Motor3_pin * form))); };

// level of the program

Motor3(ON);

Motor3(OFF);