0
\$\begingroup\$

Please see my edit:

I asked this question stackoverflow and no one answered. In STM32CubeMX MSP stands for MCU Support Package and of all here is what it basically about:

MSPs are user callback functions to perform system level initializations such as (Clock, GPIOs, DMA, interrupts).

Now I'm looking at such a function used as:

HAL_TIM_MspPostInit(&htim2);

And when I open declaration it is found under stm32f3xx_hal_msp.c as:

void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(htim->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspPostInit 0 */

  /* USER CODE END TIM2_MspPostInit 0 */

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM2 GPIO Configuration
    PA0     ------> TIM2_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM2_MspPostInit 1 */

  /* USER CODE END TIM2_MspPostInit 1 */
  }

Now in C callback function is a function which its pointer is passed to another function. Here selected answer is an example.

My question is: What makes MSPs callback functions? They get structs passed as arguments not functions. And where are the callbacks in MSPs? I could not see the footprint of a callback function there. An example would help.

EDIT:

I still dont get it. Here is what CubeMX generates in main.c:

static void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 65535;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 5000;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.BreakFilter = 0;
  sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
  sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
  sBreakDeadTimeConfig.Break2Filter = 0;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */
  HAL_TIM_MspPostInit(&htim1);

}

Look at the last line above!:

It is: HAL_TIM_MspPostInit(&htim1);

This is obviously a function call from main.c to stm32f3xx_hal_msp.c library.

But almost all of the answers claims the following:

it is a callback from HAL to user code.

But to me it is a function call from the user code to HAL. Where am I wrong?

\$\endgroup\$
7
  • 1
    \$\begingroup\$ Regarding ST and their libs, they are very confused over existing computer science terminology in general and I wouldn't trust anything said in their docs. A real HAL is for example an abstraction around drivers, for the purpose of separating application logic from hardware details. A mere wrapper around code accessing hardware registers is not a HAL, because it is still way too hardware-specific to serve as abstraction - it's a driver not a HAL. Also note that ST has no interest in providing actual HAL libraries, because that would allow you to port your code base to their competitors... \$\endgroup\$
    – Lundin
    Mar 9, 2022 at 11:18
  • \$\begingroup\$ 1-) So what they call callback is not really a callback since none of those involve a function pointer? 2-) How does ST hide their libraries? Are they in compiled form? \$\endgroup\$
    – GNZ
    Mar 9, 2022 at 12:11
  • 2
    \$\begingroup\$ You'll have to ask ST what they were thinking when they wrote all these libs, because I have no interest in researching it. Kind of like troubleshooting the design of the square-wheeled bike... \$\endgroup\$
    – Lundin
    Mar 9, 2022 at 12:35
  • 1
    \$\begingroup\$ It's a callback because the ST HAL library is calling back into your application code. That's all there really is to it. There's no need to involve function pointers for something to be a callback - that's just one way of doing it which makes them run-time configurable. But run-time configurability is not a requirement for something to be a callback. \$\endgroup\$
    – brhans
    Mar 9, 2022 at 13:17
  • \$\begingroup\$ It may appear confusing at first because you've used CubeMX to generate this code and it doesn't feel like HAL_TIM_MspPostInit is your application code because you didn't write it - but there's no need to use CubeMX to generate code to use with the HAL, and had you just written it from scratch you would have then probably written your own HAL_TIM_MspPostInit function. \$\endgroup\$
    – brhans
    Mar 9, 2022 at 13:19

3 Answers 3

2
\$\begingroup\$

You have a misconception what a callback means. It just means a function that is called back from e.g. some library code, whether or not you provide the library with info what to call or not.

Maybe you are just used to the mechanism that when you do some kind of thing that requires a callback, you have been able to provide the pointer to callback function yourself. An example of this is the C sort() function which requires you to provide a callback function which can compare the two elements to be able to sort them.

But sometimes you can't provide a custom callback and you have to have a function with a specific name for the callback. It still is exactly the same callback mechanism, it does not change it in any way whether the callback can be set or if it is fixed.

\$\endgroup\$
5
  • \$\begingroup\$ Can you give an example? Is there any callback in my question? I cant see any function pointer as argument. Thats a must in C to be called a callback. \$\endgroup\$
    – GNZ
    Mar 9, 2022 at 12:14
  • 1
    \$\begingroup\$ I don't think C standard does not define what you can or cannot call a callback, so there is no strict definition for a callback. If C standard defines the term please mention where. In this case you have to implement the function that is specific to your platform/project and it is called by the generic HAL to init your board. Nobody else calls your function except the HAL. Thus it can be called a callback, even if you don't specify to the HAL which function you want to be called, as it is implicit. \$\endgroup\$
    – Justme
    Mar 9, 2022 at 13:10
  • \$\begingroup\$ "I don't think C standard does not define" or you wanted to say "I don't think C standard defines" ? \$\endgroup\$
    – GNZ
    Mar 9, 2022 at 13:33
  • \$\begingroup\$ Please see my edit. I tried to pinpoint my confusion. \$\endgroup\$
    – GNZ
    Mar 10, 2022 at 13:58
  • \$\begingroup\$ OK, the MX_TIM1_Init() is not HAL code, it is just user code generated for you, which simply calls the HAL to init the timer and finally calls HAL_TIM_MspPostInit() which is sort of HAL support code but pregenerated for you based on how you wanted the timer to be configured. I would not say it is a callback in this case, as it's not called back by the HAL. \$\endgroup\$
    – Justme
    Mar 10, 2022 at 14:27
2
\$\begingroup\$

Callback functions is a well-defined term meaning "function defined by my application but called by someone else". Someone else being a library or an OS.

Take for example the pthreads library where you upon creation hand the library a function pointer to your custom function, which is then called not by your application code but the underlying library/OS. The function definition resides in your code but the function call does not. Another example is the bsearch/qsort functions in the C standard lib taking a callback comparison function as parameter.

Callbacks are very similar to interrupt service routines (ISR) with the only distinction that an ISR is called by hardware, but a callback is called by some software library, like a driver or HAL.

HAL_TIM_MspPostInit(&htim2); is an explicit function call, so if this is the only way this function is called, it is not a callback function. Callback functions almost certainly involve a function pointer interface, similar to this:

void some_timer_init (void (*callback)(void), int interval);

Assume this is a HAL for some timer hardware peripheral. You want this lib to call a function toggling a LED every 100ms, so you come up with a function like:

void toggle_led (void)
{
  THE_LED ^= MASK;
}

In case the some_timer_init implements a timer ISR internally, it can then register your toggle_led function as a callback, to get called by the ISR every 100ms. You would register it by calling some_timer_init(toggle_led, 100);.

Basically every single sensible hardware timer peripheral HAL uses callbacks, so understanding them is crucial for any professional microcontroller programming project.

\$\endgroup\$
8
  • 1
    \$\begingroup\$ I was with you right up until "is an explicit function call, so if this is the only way this function is called, it is not a callback function". Imo your 1st paragraph is correct and self-contained and doesn't need any ifs, ands, or buts added on. There's no requirement to use a function pointer to call a function a callback - that only provides runtime configurability, which is not a requirement for something to be a callback. \$\endgroup\$
    – brhans
    Mar 9, 2022 at 13:23
  • \$\begingroup\$ @brhans Then make an example of the use of callbacks without using function pointers. Note that a header providing a function declaration to be implemented by the application and then calling that function is not really a callback, but a way to implement inheritance/polymorphism. \$\endgroup\$
    – Lundin
    Mar 9, 2022 at 15:59
  • \$\begingroup\$ The ST HAL libraries are that example already. The standard library code makes calls to BlahBlah_MSP_SomethingInit(), where the library contains an empty, weakly declared function with that name. Then the library's BlahBlah_SomethingInit() makes the call to BlahBlah_MSP_SomethingInit(), So now you create your own BlahBlah_MSP_SomethingInit() and in your application you then call BlahBlah_SomethingInit() which in turn calls back into your application code when it calls BlahBlah_MSP_SomethingInit(). So there you have a non-runtime-configurable callback. \$\endgroup\$
    – brhans
    Mar 9, 2022 at 16:34
  • \$\begingroup\$ Of course the HAL library does also have runtime-configurable callbacks which do use function pointers - but just because you can implement callbacks using function pointers doesn't mean you have to. \$\endgroup\$
    – brhans
    Mar 9, 2022 at 16:35
  • \$\begingroup\$ @brhans That's inheritance of an abstract base class. If you don't implement the function, then it will fail to link. Calling inheritance for "callbacks" isn't helpful, it's evidently just confusing people. \$\endgroup\$
    – Lundin
    Mar 9, 2022 at 16:40
0
\$\begingroup\$

"Callback" is not exactly what you think it is. Well, it kinda is, but not exactly. It's a poor name for the concept that confuses many people. It means "call at the back" (still confusing) or "function called after some other function" (disputed; your definition isn't wrong either). If you set function2() to be called at the end of function1(), then function2() is a callback function (and it is passed as an argument to function1()). Whenever function1() did its job, callback function function2() is called.

There is some fuzziness on the precise definition (as usual; depends on context of the discussion), such as the wikipedia article or top 2 stackoverflow answers to this question that I find good.


What makes the function you provided a callback one stands in its name - "postInit". It's called at the end of some initialization function. Simple as that.

\$\endgroup\$
8
  • \$\begingroup\$ So this definition does not hold in this context?: "In C, a callback function is a function that is called through a function pointer."? Because I cannot see any function pointer passed as an argument to another function. I don't see any footprint like: function1(int x, int (*function2)(void)); in MSPs. \$\endgroup\$
    – GNZ
    Mar 9, 2022 at 10:54
  • 3
    \$\begingroup\$ It does hold. The function you posted must be called by some other init function. The function you posted is a callback function, it doesn't call anything itself. It is called. Given its name is "postInit", I bet there is some init function that calls it \$\endgroup\$
    – Ilya
    Mar 9, 2022 at 10:57
  • \$\begingroup\$ Exactly. Any function might be used as a callback function. It doesn't need anything special to become a callback. It's whoever holds the function pointer, which makes this callback concept a reality. It's about the idea of passing a function pointer (it can hold any value, point to any function, and it can be changed at run time, etc.), compared to calling a hard-coded function instead. Maybe what confused you is the fact that you can pass some callback function as an argument when calling some other function. \$\endgroup\$
    – akwky
    Mar 9, 2022 at 11:05
  • \$\begingroup\$ @Ilya Lundin says postInit is not a callback but just a function call. But to you it is a callback. Are you sure? \$\endgroup\$
    – GNZ
    Mar 9, 2022 at 12:12
  • 2
    \$\begingroup\$ It's a function call, and since it is not called directly but by the HAL library when it needs it, it is a callback from HAL to user code. Why would it need to be called via a function pointer to be called a callback? \$\endgroup\$
    – Justme
    Mar 9, 2022 at 13:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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