Initializing the MCU clock and memory system, is about 20-30 lines of assembly, or 5 to 10 lines in C, directly accessing the registers or about 5 commands by a StdPeriph library. Means for the simplier devices, F439 like-ones are a bit complicated, but nothing impossible to do "manually".
Why the hell would somene like to use standardized CMSIS? It only adds ballast and unnecessary overhead for the intended functionality.
What is so complicated on setting up an ARM Cortex MCU? Only set the desired FLASH wait states (number found in a documentation) - that means single write to a register, start needed clock sources (eg external crystal oscillator, which is called HSE //high speed external// on STM32), wait for stabilization of the clock source - flipping and polling a single bit. Setup the PLL (if needed) clock source, divide and multiply ratios, start PLL and wait for its lock. Then switch the system clock source t the PLL output and check the success.
Sounded difficult? If yes, programming ARM MCU's wasn't a good choice then. There is hell of a lot much more complicated stuff, then setting a clock source and distribution system on the chip. And its cost is only to open the manual (which you must do if you want or not) and learn, how the clock system works. Otherwise it is better to choose simpler MCU, than ARM.
Here a small minimalistic example how to setup F051 via registers, also with a SysTick timer. Using registers.
void SystemInit() {
RCC->CFGR = 0x00280000; //0b0000 0000 0010 1000 0000 0000 0000 0000
RCC->CR |= RCC_CR_PLLON; //set PLL ON
while (! RCC->CR2 & RCC_CR_PLLRDY); //wait for PLL to lock
FLASH->ACR = FLASH_ACR_PRFTBE | 0x01; //FLASH prefetch enabled, 1 WaitState
RCC->CFGR |= RCC_CFGR_SW_1; //switching clock source to PLL output
//SysTick configuration
SysTick->LOAD = 48000-1; //Reload value (48000-1) -> 1ms
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
NVIC_EnableIRQ(SysTick_IRQn);
}
Yes, it is not as transparent and not done absolutely properly, but that was my absolute first try on ARM. And after a one or two afternoons, it worked.
If someone tells you, that for a beginner, this is way too hard... He lies. And note that the MCU also works with the clock system in its default state. Will be slow, won't be ideal (arduino is not ideal at all), so where's the problem to start that way?
And that's an proper init of F103, using StdPeriph (again, no timeouts or error handling, but for simple educational purposes)
void SystemInit()
{
/* Set 2 wait states for FLASH */
FLASH_SetLatency(FLASH_Latency_2);
/* enable prefetch buffer */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* start HSI (internal high speed oscillator), it should be running default, but to be sure */
RCC_HSICmd(ENABLE);
/* wait for the oscillator to start */
while (!RCC_GetFlagStatus(RCC_FLAG_HSIRDY));
/* Set the clock source as HSI/2 for the PLL, multiply by 16 */
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16);
/* Enable the PLL */
RCC_PLLCmd(ENABLE);
/* Wait for PLL to lock */
while (!RCC_GetFlagStatus(RCC_FLAG_PLLRDY));
/* Set the prescalers for the AHB and APB buses */
RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB = 64MHz
RCC_PCLK1Config(RCC_HCLK_Div2); //APB1 = 32MHz
RCC_PCLK2Config(RCC_HCLK_Div1); //APB2 = 64MHz
/* now we switch system clock to the PLL's output */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* check it is switched to the requested source */
while (RCC_GetSYSCLKSource() != 0x08);
}
Now you've seen some code examples, how simple the basic init is. I don't see there any need to rely on 3rd party libraries.
Now I expect someone starts bitching me out, that I am too much vintage style or I am not using libraries, or I hate multiplatform-stuff, etc... I get it, but he will not change my opinion. If he wants to use libraries, especially HAL, good luck using them (respectively hacking them to be usable) for advanced applications or to even fit devices without megabytes of flash.
And to be exact, the init in the HAL is also made quite wrongly. Sometimes, HAL just tries to start LSE, if there is not even connected any crystal, or starts it, then shuts it down, so sometimes it can take a few seconds to start the MCU.
So you can make a decision yourself, which way will you go. I don't want to obtrude anybody, to learn anything... So shouldn't you tell me that this knowledge is useless. (It is useful as you wouldn't beleive maybe)
As a standard "it depends"... on many things. Hope my little insight into this topic was helpful for you.
//So what kind of application will you do? STM32 only or must be easily portable to other vendors' chips? - These and like so are the questions you must ask yourself. Based on that you can make a decision, what is suitable for you.
//By the way - if you are brave enough to throw away HAL, I woul'd suggest doing the same with CMSIS.