4
\$\begingroup\$

I'm learning to use STM32 microcontrollers using CubeMX to generate a project. I've noticed that CubeMX generates two basic stages of initialization for nearly every peripheral:

(A) Within the stm32fxxxx_hap_msp.c file, it defines a number of callbacks of the form HAL_XXX_MspInit().

(B) Within main.c, it defines a number of functions of the form MX_XXX_Init().

Sometimes a given peripheral's HAL_XYZ_Init() function is called from within (A) as it is with the ADC and RTC. Other times a given peripheral's HAL_XYZ_Init() function is called from within (B) as it is done with GPIO.

Both sets of functions call __HAL_RCC_xxxx macros extensively.

I can't make heads or tails of the usage pattern and neither the HAL guide nor reference manual give much direction here.

So, questions:

  1. I suspect that the callback format provided by (A) has something to do with the uC waking from low-power modes, but I am not positive about this. Is this correct, or what is the purpose of the HAL_XXX_MspInit callback format?

  2. I noticed that (A) contains more user-definition block comments indicating room for my code to cohabit the functions generated by CubeMX. But why, for instance, would it be wrong to move code from (B) into the space of (A) in order to keep my initialization sequence clear and easy to read?

\$\endgroup\$
4
\$\begingroup\$

I was able to answer my own question.

The HAL_XXX_MspInit() functions are called by their respective HAL_XXX_Init() functions. As an example, when main() calls its MX_I2C_Init(), this prepares a global structure (defined in main.c) for initializing the I2C peripheral.

The call stack goes (roughly, with omissions):

main() [written by CubeMX]
MX_I2C_Init() [written by CubeMX]
HAL_I2C_Init() [provided by HAL Drivers, copied into project's source tree by CubeMX]
HAL_I2C_MspInit() [empty weak version provided by HAL Drivers, overrided by CubeMX in system_stm32fxxxx.c]

Note that this means that you can call the _MspInit() and _MspDeinit() functions during your code's runtime. You may choose to do this, for example, to change low-level resource state before or after a change in power modes.

This answer (and other details concerning HAL call flow) is only hinted at by the Description of HAL and LL Drivers document, and are best confirmed by checking the HAL source code. This code is quite a bit more friendly than you might expect, and is located under your project tree under HAL_Drivers for any CubeMX project.

\$\endgroup\$
  • 1
    \$\begingroup\$ The code in system_stm32fxxxx.c is typically called before int main(void) and any linker injected loading code. It can be required to have the clock tree and external memory accessible before calling main() or to speed up the linker-loading. \$\endgroup\$ – Jeroen3 Nov 1 '18 at 20:35
  • \$\begingroup\$ There is even more initialisation code. Look at the startup directory and the .s file. \$\endgroup\$ – P__J__ Nov 2 '18 at 19:01

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.