I use CUBE IDE to configure the cpu pin out and assign peripherals before layout. I generate functional self test for the initial board bring up before the software guys are even bothered with new projects. We have done this for many boards with no issues. Our programmers are very talented and wasting their time optimizing and bitching about the style of STs HAL or LL code because it can be better makes no sense to me. There is always plenty of functional code to write and debug that can be written anyway the talented programmers find productive. Reinventing the drivers and init code because it can be better and faster makes no sense if it works the way it is. Design cycles are too short to rewrite the ton of code ST has already provided for free.
Personally I am amazed at the huge effort ST has in maintaining Cube considering the number of different CPUs they have in production.
https://www.eevblog.com/forum/microcontrollers/stm32h7b3-warning-cubeide-1-3-all-projects-are-in-a-broken-state/msg3099437/#msg3099437Then you have to read about H7 story as example, where this particular board wont pass such functional self-test in Cube, because you got "old generation" cpu, that got significant changes, but no changes in part number, so even ST own HAL fail to work with it.
Also, check libopencm3, which is really amazing, and where guys managed to keep relatively unified API for several different ARM vendors and processors.
While Cube get fixes for one MCU, and intentionally wont get same fix for another, without any reasonable explanation.
ST has really great MCUs till now, and Cube was(and probably still) cool about looking to idea how things should work, configure peripherals and clocks, but not more.
Moreover, i suspect this messy code in it helping to hide serious problems.
For example, recent find that at least some STM32L0 have issues with SPI and it needs "to be set specific I/O configuration".
It is mentioned VERY indirectly in 2.6.3 in ES0255 (Errata Sheets, STM32L052x6/8 device limitations).
Cube also does solve this "automagically", without any comments or reference:
initStruct.Mode = GPIO_MODE_AF_PP;
initStruct.Pull = GPIO_NOPULL ;
initStruct.Speed = GPIO_SPEED_HIGH;
initStruct.Alternate = SPI1_AF ;
HW_GPIO_Init(RADIO_SCLK_PORT, RADIO_SCLK_PIN, &initStruct);
HW_GPIO_Init(RADIO_MISO_PORT, RADIO_MISO_PIN, &initStruct);
HW_GPIO_Init(RADIO_MOSI_PORT, RADIO_MOSI_PIN, &initStruct);
Without this "magic", their own ST branded boards not working properly and getting data corrupted.
So seems many , embedded developers run a bunch of code and have no idea what this code does and why.
And actually they have no choice. Either copy unreliable pieces of initialization code from Cube (and get bugs like mentioned before, like malloc), or get such undocumented problems with hardware.
After what i experienced, these examples, i would really think that it is bad idea to use cube code for anything meaningful, even self-tests.
More than that, when i got used to high quality code in opensource, where any strange tricks are commented and documented, seeing this pile of poorly documented magic mixed with .a binaries dumped on github is far from something that should be praised.
It's cool to reuse code like libopencm3, if license permits, but cube? Hell no, it's ticking bomb.