9

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

Devjeet Mandal
  • 345
  • 1
  • 4
  • 23
  • 1
    What infinitive loop? Is it a hard fault or it just waits for the counter. Be precise – 0___________ Dec 22 '18 at 23:39
  • 2
    Are you calling HAL_Delay from interrupt handler? – KamilCuk Dec 23 '18 at 01:16
  • how are we to debug this problem? there is no code to show what you actually wrote. Please post a [mcve] so we can help you debug the problem – user3629249 Dec 23 '18 at 08:26
  • @P__J__ I have timer interrupt which fires every 2 sec and display data on max7219. This interrupt is working. But other thing i.e the gsm part is not working. I have used serial monitor to see where is my control. So i wrote something before and after hal_delay() and i can see the before hal_delay is shown on serial monitor and then just timer interrupt is called – Devjeet Mandal Dec 23 '18 at 08:50
  • Check if the systick interrupt handler is invoked. – 0___________ Dec 23 '18 at 08:59
  • @P__J__ Yes `SysTick_Handler()` is invoked – Devjeet Mandal Dec 23 '18 at 09:09
  • `HAL_TIM_PeriodElapsedCallback` You are calling HAL_Delay from within the interrupt handler. Don't do that. Also you are trying to transfer uart data from interrupt handler. Don't do that. Divide interrupt handling in top half and bottom half. And never call blocking functions in an interrupt handler. You can get away with assigning interrupt priorities, and making the systick priority higher then timer, but I wouldn't recommend it. – KamilCuk Dec 23 '18 at 09:20
  • @KamilCuk `HAL_TIM_PeriodElapsedCallback` doesn't contain any `HAL_Delay`. And the UART_Transmit was written there cuz I was not sure where is the control is stuck. it was only written there after the problem occured – Devjeet Mandal Dec 23 '18 at 09:28
  • How do you think `HAL_UART_Transmit` measures the 1000ms timeout you give it? Hint: it's similar to `HAL_Delay()` - it get's the systick counter and compares. – KamilCuk Dec 23 '18 at 09:32
  • 1
    Make sure that the priority of the systick is higher than the timer interrupt you use. – 0___________ Dec 23 '18 at 10:07
  • As an experiment change the timeouts to zero. The HAL is using systick to measure the passing time – 0___________ Dec 23 '18 at 10:13
  • 1
    @P__J__ I have used `HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);` and `HAL_NVIC_SetPriority(TIM3_IRQn, 1, 1);` for timer and it seems to work. But let's not get to conclusion now. Let me check for an hour. And i will let you know the results – Devjeet Mandal Dec 23 '18 at 11:07
  • It is a very common problem. You need to know your hardware. – 0___________ Dec 23 '18 at 11:08
  • @P__J__ So what was happening inside? When i am calling `HAL_Delay()`, The timer interrupt is invoked inside `HAL_Delay()`. I wanted to know how timer interrupt is effecting hal delay? if timer interrupt is invoked, it should return to the place from where it has invoked. And continue executing hte next instruction. Then how HAL_Delay is getting effected. – Devjeet Mandal Dec 23 '18 at 11:13
  • Both are in use systick is incrementing the counter used in the delay function. Do not do any time consuming things in the interrupt routines – 0___________ Dec 23 '18 at 11:25

3 Answers3

18

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).

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
  • So I am trying to implement this solution, but I am unable to change the preemption priority of the system tick timer, is there another way to change it? – ajsmart Apr 28 '20 at 19:19
  • This could require some debugging. I suggest you open a new question, link to this answer, and explain exactly what you have tried to change the preemption priority and what you're seeing. You may just have a setting wrong somewhere. Once you create a question, add another comment here and post a link to it. – Gabriel Staples Apr 28 '20 at 19:23
  • So I did some work around the project, and I ended up just recreating from the ground up, and that seems to have fixed the problems. I really don't know what was messed up, but I did something. – ajsmart Apr 28 '20 at 21:15
  • Spent a decent amount of time looking for this error, only to find out that due to the switching from FreeRTOS-based project SysTick ISR was never generated and HAL_IncTick() was never called. – Roker Pivic May 08 '20 at 20:58
3

All delay and timeout HAL functions rely on a counter incremented in the SysTick handler. If you are using any of these functions in another interrupt, you have to make sure that the SysTick interrupt has a higher priority than that interrupt. Otherwise, the SysTick handler is never called and you will end up in an infinite loop, as the counter will never be increased.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
0___________
  • 60,014
  • 4
  • 34
  • 74
0

We need to increase the priority of SysTick_IRQn by lower number than other IRQs'priority.
For example: if we consider number 15 for other IRQs, we could assign 14 for SysTick_IRQn using HAL_NVIC_SetPriority(SysTick_IRQn,14.0) to assign an acceptable priority for SysTick.

Note: It is very important that you use HAL_NVIC_SetPriority function after SystemClock_Config(), as I show in the bellow picture.

enter image description here

PedPak
  • 157
  • 1
  • 3
  • At the begining, SysTick_IRQn priority is assigned in HAL_Init(), but after changing System Clock configuration (by calling SystemClock_Config() ) alot of things will be affected which SysTick is one of them and its priority requires to be reconfigured again. – PedPak Jan 05 '23 at 13:15