HAL_Delay() 陷入无限循环

Posted

技术标签:

【中文标题】HAL_Delay() 陷入无限循环【英文标题】:HAL_Delay() stuck in a infinite loop 【发布时间】:2019-05-22 19:36:46 【问题描述】:

我被 HAL_Delay() 函数困住了。当我调用这个函数 HAL_Delay() 时,控制卡在无限循环中。 在搜索问题时,我发现了这个

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

在这个特别的评论中,我引用了“链接器文件有问题,请使用附加的那个。您需要分别映射两个内存组,因此首先是 SRAM1 96K,然后是 SRAM2 的 32K。我认为应该报告这作为 CubeMX 中的错误,因为它会生成错误的链接器文件。”并且有两个扩展名为 .ld 的文件。

我正在寻找的是如何在我的项目中使用这些文件或任何其他更好的选择来处理这个问题。

PS。我正在使用 stm32l476 发现板、Cube Mx 5.0.0 和 Attolic True Studio。

编辑

我的项目有一个 RS485 通信,我从那里获取数据,我对该数据有两个任务,将其显示在 MAX7219 显示器上并使用 sim800 gsm 模块将其发送到互联网。

控件卡住​​的代码。请注意,该函数仅在执行 GSM 任务时调用。

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

此函数在终端上写入In Delay,但不显示Out Delay。但我也有一个计时器,它每 2 秒调用一次以在 MAX72219 上显示数据。

下面的代码是

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;
    

控制卡住后,此功能始终在 2 秒后触发。因此得出的结论是,控件以某种方式卡在HAL_Delay() 中。

IMP THING

问题每次都会发生,但没有特定时间,即控件可能会在 5 分钟和 10 分钟或 15 分钟后卡住。它不会从特定功能中卡住。功能可能不同。即有时它可能会从函数名getIMEI() 卡住,或者有时它可能会卡在我get service provider

【问题讨论】:

什么不定式循环?是硬故障还是只是在等待计数器。精确 你是从中断处理程序中调用 HAL_Delay 吗? 我们如何调试这个问题?没有代码可以显示您实际编写的内容。请发minimal reproducible example,以便我们帮助您调试问题 确保systick的优先级高于你使用的定时器中断。 @P__J__ 我使用了HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);HAL_NVIC_SetPriority(TIM3_IRQn, 1, 1); 作为计时器,它似乎可以工作。但我们现在不要下结论。让我检查一个小时。我会让你知道结果 【参考方案1】:

修复:

总结: 提高SysTick_Handler NVIC 优先级(通过降低其 NVIC 数值,范围为 0 到 15)。

详情: @P__J__ 在他的回答 here 中所说的是正确的,我也怀疑这是你的问题。要解决此问题,您需要使您的 SysTick 中断的 NVIC(嵌套向量中断控制器)优先级高于任何其他可能依赖于系统刻度递增的 HAL 调用的中断。 这包括所有具有超时的 HAL 调用,例如,以及 HAL 延迟。较高的 NVIC 优先级意味着您必须将其设为较低的数值,因为默认配置下 STM32 芯片的最高 NVIC 优先级为 0,最低为 15。

要在 STM32CubeMX 5 中设置 NVIC 优先级,请转到 Pinout & Configuration --> System Core -->(单击小向上/向下箭头进入显示 NVIC 的页面),然后单击 NVIC -->将“抢占优先级”值降低到低于(高于)任何其他依赖 HAL 调用的 ISR。

这是一个屏幕截图。请注意,您也可以通过单击“Pinout view”旁边的“System view”按钮进入此屏幕,然后单击“System Core”部分下的“NVIC”。

截图:

更多信息HAL_IncTick();:

您将从“stm32f4xx_it.c”文件中看到,SysTick_Handler ISR 调用HAL_IncTick();

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

  HAL_IncTick();

如果您 Ctrl + 单击它(至少在 System Workbench/Eclipse 中)以跳转到 HAL_IncTick() 的实现,您将看到以下内容,这提供了对 cme​​ts 的一些额外见解:

/**
  * @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++;

HAL_IncTick() 函数位于文件“...STM32Cube_FW_F4_V1.19.0/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c”中,该文件还包含位于HAL_InitTick() 上方的HAL_InitTick() 函数。它的 cmets 非常有见地:

/**
  * @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;

特别注意:写着的部分:

如果从外围 ISR 进程调用 HAL_Delay() 必须小心, SysTick 中断必须具有更高的优先级(数值较低) 比外设中断。否则调用者 ISR 进程将被阻塞。

这正是我学到这一点的地方。

确保有时在代码中跳转并查看 ST 的 HAL 源代码本身中的函数和文档,以找到像这样隐藏的洞察力。当然,除了参考以下核心文档之外,还要这样做:

您的芯片的关键 STM32 文档,按优先顺序排列(最重要的在前):

    参考手册:RM0351 数据表:DS10198 UM1725 - Description of STM32F4 HAL and LL drivers 编程手册:PM0214

这些和其他重要手册可以在 ST 的网站 (https://www.st.com/en/microcontrollers/stm32l476vg.html) 上轻松找到,或者更方便:在 STM32CubeMX 中通过 Help --> Docs & Resources(快捷方式: Alt + D)。

【讨论】:

所以我正在尝试实现这个解决方案,但是我无法更改系统滴答计时器的抢占优先级,还有其他方法可以更改吗? 这可能需要一些调试。我建议您打开一个新问题,链接到此答案,并准确解释您尝试更改抢占优先级的内容以及您所看到的内容。您可能只是某个地方的设置错误。创建问题后,请在此处添加另一条评论并发布链接。 所以我围绕这个项目做了一些工作,最后我只是从头开始重新创建,这似乎解决了问题。我真的不知道出了什么问题,但我做了一些事情。 花了相当多的时间寻找这个错误,却发现由于从基于 FreeRTOS 的项目切换,SysTick ISR 从未生成,HAL_IncTick() 从未被调用。【参考方案2】:

所有延迟和超时 HAL 函数都依赖于在 SysTick 处理程序中递增的计数器。如果您在另一个中断中使用这些函数中的任何一个,您必须确保SysTick 中断具有比该中断更高的优先级。否则,SysTick 处理程序永远不会被调用,并且您将进入无限循环,因为计数器永远不会增加。

【讨论】:

以上是关于HAL_Delay() 陷入无限循环的主要内容,如果未能解决你的问题,请参考以下文章

Knight's Tour 代码陷入无限循环,无法解决

蝗虫负载测试陷入无限循环

C合并排序陷入无限循环

为啥这个函数不会陷入无限循环? [复制]

陷入无限循环(骑士之旅问题)

Bash参数解析逻辑陷入无限循环[重复]