HAL_Delay() 陷入无限循环

Dev*_*dal 6 c linker hal stm32 infinite-loop

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

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

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

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

附注。我正在使用 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);
}
Run Code Online (Sandbox Code Playgroud)

该函数写入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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

小东西

问题每次都会发生,但没有特定的时间,即控件可能会在 5 分钟和 10 分钟或 15 分钟后卡住。它不会停留在特定的功能上。功能可能不一样。即有时它可能会被函数名称卡住,有时它可能会卡住getIMEI()get service provider

Gab*_*les 13

修复:

总结:
增加SysTick_HandlerNVIC优先级(通过减少其NVIC数值,范围为0到15)。

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

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

这是一个屏幕截图。请注意,您也可以通过单击“引脚视图”旁边的“系统视图”按钮,然后单击“系统核心”部分下的“NVIC”来进入此屏幕。

截屏:

在此处输入图片说明

更多信息HAL_IncTick();

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

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

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

/**
  * @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++;
}
Run Code Online (Sandbox Code Playgroud)

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

/**
  * @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;
}
Run Code Online (Sandbox Code Playgroud)

特别注意:这部分说:

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

这正是我学到的地方。

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

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

  1. 参考手册:RM0351
  2. 数据表:DS10198
  3. UM1725 - STM32F4 HAL 和 LL 驱动程序说明
  4. 编程手册:PM0214

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


P__*_*J__ 3

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