HAL_Delay() stuck in a infinite loop

Devjeet Mandal picture Devjeet Mandal · Dec 22, 2018 · Viewed 12.7k times · Source

I am stuck with HAL_Delay() function. When i call this function HAL_Delay() , control stuck in infinite loop. While searching for the problem, I found this

http://www.openstm32.org/forumthread2145#threadId2146

In this particular comment which states and i quote "There is problem with linker file please use the one attached. You need to map two banks of memory separately so first SRAM1 96K and then SRAM2 of 32K. I think this should be reported as bug in CubeMX as it generates bad linker file." and there are two files with .ld extension.

What i am looking is how to use this files within my project OR any other better option for dealing with this problem.

PS. I am using stm32l476 discovery board, Cube Mx 5.0.0 and Attolic True Studio.

EDIT

My project is having an RS485 communication where from where i take data and i have two task with that data, display it on MAX7219 display and send it to internet using sim800 gsm module.

The code where the control is stuck. note that this function is only called when it is doing GSM tasks.

void vMyDelay(uint16_t ms)
{
    HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", strlen("\r\n"), 1000);
    HAL_UART_Transmit(&huart2, (uint8_t*)"In Delay", strlen("In Delay"), 1000);
    HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", strlen("\r\n"), 1000);
    for (int i = 0; i < ms; i++ )       HAL_Delay(1);
    HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", strlen("\r\n"), 1000);
    HAL_UART_Transmit(&huart2, (uint8_t*)"Out Delay", strlen("Out Delay"), 1000);
    HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", strlen("\r\n"), 1000);
}

This function writes In Delay on the terminal but Out Delay is not displayed. But i am also having a timer which invokes every 2 sec to display the data on MAX72219.

The following code is

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", strlen("\r\n"), 1000);
    HAL_UART_Transmit(&huart2, (uint8_t*)"HAL_TIM_PeriodElapsedCallback()", strlen("vRS485_CollectInverterData()"), 1000);
    HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", strlen("\r\n"), 1000);
    if (htim->Instance == htim3.Instance)
    {
        vMax7219_ClearDisplay();
        switch (uiMax7219Index)
        {
            case 0: vMax7219_SendNumberToString(ucFreq7219,1);      break;
            case 1: vMax7219_SendNumberToString(ucInVolt7219,1);    break;
            case 2: vMax7219_SendNumberToString(ucOutVolt7219,1);   break;
            case 3: vMax7219_SendNumberToString(ucOutCurr7219,1);   break;
            case 4: vMax7219_SendNumberToString(ucLoadSpd7219,1);   break;
            case 5: vMax7219_SendNumberToString(ucOutPwr7219,1);    break;
        }
        uiMax7219Index++;
        if (uiMax7219Index > 5) uiMax7219Index = 0;
    }
}

After the control stuck, this function is always fires after 2 sec. An thus the conclusion that somehow the control is stuck in HAL_Delay().

IMP THING

the problem happens everytime but there is no specific time i.e the control might stuck after 5mins and 10 mins or 15mins. It doesnt stuck from a specific function. The functions might be different. i.e sometimes it might get stuck from function name getIMEI() or sometime it might me get service provider

Answer

Gabriel Staples picture Gabriel Staples · Dec 23, 2018

The fix:

Summary:
Increase the SysTick_Handler NVIC priority (by decreasing its NVIC numerical value, which has a range of 0 to 15).

Details:
What @P__J__ says in his answer here is correct, and I too suspect that is your problem. To fix it, you need to make your SysTick interrupt have an NVIC (Nested Vectored Interrupt Controller) priority higher than any other interrupts that make HAL calls which might rely on the system tick incrementing. This includes all HAL calls which have timeouts, for instance, as well as HAL delays. A higher NVIC priority means you must make it a lower numerical value, as the highest NVIC priority is 0 and the lowest is 15 for the STM32 chips in default configuration.

To set your NVIC priorities in STM32CubeMX 5, go to Pinout & Configuration --> System Core --> (click the tiny little up/down arrow to get on the page that shows NVIC), then click NVIC --> Reduce the "Preemption Priority" value to be lower than (higher priority than) any other ISRs relying on HAL calls.

Here's a screenshot. Note that you can also get to this screen by clicking the "System view" button next to the "Pinout view", then clicking on "NVIC" under the "System Core" section.

Screenshot:

enter image description here

More info on HAL_IncTick();:

You'll see here from your "stm32f4xx_it.c" file, that the SysTick_Handler ISR calls HAL_IncTick();:

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
  HAL_IncTick();
}

If you Ctrl + Click on it (in System Workbench/Eclipse at least) to jump to the implementation of HAL_IncTick(), you'll see the following, which provides some additional insight in the comments:

/**
  * @brief This function is called to increment  a global variable "uwTick"
  *        used as application time base.
  * @note In the default implementation, this variable is incremented each 1ms
  *       in Systick ISR.
  * @note This function is declared as __weak to be overwritten in case of other 
  *      implementations in user file.
  * @retval None
  */
__weak void HAL_IncTick(void)
{
  uwTick++;
}

This HAL_IncTick() function is found inside the file "...STM32Cube_FW_F4_V1.19.0/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c", which also contains the HAL_InitTick() function just above HAL_IncTick(). Its comments are very insightful:

/**
  * @brief This function configures the source of the time base.
  *        The time source is configured  to have 1ms time base with a dedicated 
  *        Tick interrupt priority.
  * @note This function is called  automatically at the beginning of program after
  *       reset by HAL_Init() or at any time when clock is reconfigured  by HAL_RCC_ClockConfig().
  * @note In the default implementation, SysTick timer is the source of time base. 
  *       It is used to generate interrupts at regular time intervals. 
  *       Care must be taken if HAL_Delay() is called from a peripheral ISR process, 
  *       The SysTick interrupt must have higher priority (numerically lower)
  *       than the peripheral interrupt. Otherwise the caller ISR process will be blocked.
  *       The function is declared as __weak  to be overwritten  in case of other
  *       implementation  in user file.
  * @param TickPriority Tick interrupt priority.
  * @retval HAL status
  */
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /* Configure the SysTick to have interrupt in 1ms time basis*/
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  {
    return HAL_ERROR;
  }

  /* Configure the SysTick IRQ priority */
  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  {
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  {
    return HAL_ERROR;
  }

  /* Return function status */
  return HAL_OK;
}

Notice especially: the part which says:

Care must be taken if HAL_Delay() is called from a peripheral ISR process,
The SysTick interrupt must have higher priority (numerically lower)
than the peripheral interrupt. Otherwise the caller ISR process will be blocked.

That's exactly the location where I learned this.

Make sure to jump around the code and look at functions and documentation inside ST's HAL source code itself sometimes, to find hidden insight like this. Do that, of course, in addition to referencing the following core documents:

Key STM32 documents for your chip, in order of precedence (most important first):

  1. Reference Manual: RM0351
  2. Datasheet: DS10198
  3. UM1725 - Description of STM32F4 HAL and LL drivers
  4. Programming Manual: PM0214

These and other critical manuals are easily found on ST's website (https://www.st.com/en/microcontrollers/stm32l476vg.html), or, even more convenient: inside STM32CubeMX via Help --> Docs & Resources (shortcut: Alt + D).