带有 FreeRTOS 的 STM HAL,是/否/也许?

Posted

技术标签:

【中文标题】带有 FreeRTOS 的 STM HAL,是/否/也许?【英文标题】:STM HAL with FreeRTOS, yes/no/maybe? 【发布时间】:2021-08-21 00:29:51 【问题描述】:

我正在努力让我的程序稳定运行。我的程序运行时遇到硬故障。我在兜圈子。

我的项目:

Nucleo F446ze (STM32F446ze) 连接到 uart2 的 LTE 调制解调器 我的电脑连接到 uart3(仅用于记录)。 从 git 下载的 FreeRTOS,使用他们的 STM 端口 从 git 下载 LWIP 2.1.0

一些freertos配置

在免费 rtos 中启用了 configASSERT configCHECK_FOR_STACK_OVERFLOW 设置为 2 configUSE_MALLOC_FAILED_HOOK 设置为 1 configTOTAL_HEAP_SIZE 设置为 30k(我查询剩余堆大小时还剩 10k) INCLUDE_uxTaskGetStackHighWaterMark 设置为 1(所有任务都在堆栈限制内) SysTick 专用于 FreeRTOS。我在 1khz 上使用 TIM6 来增加 HAL 滴答声。 所有 NVIC 中断都设置为 5 或更高,并且再次启用了 configASSERT,因此非常确定涵盖了“中断管理”。

并使用定义将免费 rtos 中断处理程序映射到 CMSIS

#define vPortSVCHandler    SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

我的程序按顺序执行以下操作:

设置时钟和外设 启用中断 创建“StartLwIP”任务 启动 FreeRTOS 调度程序

然后“StartLwIP”会:

通过 uart2 向 LTE 调制解调器发送命令以启用数据模式 初始化 LwIP 堆栈(与对等方协商 ppp) 开始新的“测试”任务

“测试”任务:

打开与 Internet 上 TCP 服务器的连接 发送消息 关闭套接字 vTaskDelay [100|10|-] 重复

当我使用 vTaskDelay(100) 时,程序可以毫无问题地运行几个小时(运行一夜,没有问题)。

当我使用 vTaskDelay(10) 时,程序会运行一段时间(1 分钟到 5 分钟之间)。然后它会在硬故障处理程序中崩溃并挂断。

当我删除 vTaskDelay(这将是首选解决方案)时,它会崩溃得更快。同样,它会有所不同,但在几秒钟到一分钟内。

我 99% 确定问题与堆/堆栈无关。高水位标记和堆消耗看起来非常好。甚至没有接近到堆/堆栈之外。

内存管理是 LWIP 让我有些困惑,但由于我只是不断地打开和关闭连接,我不敢相信我在 LWIP 中用完了 PBUF。反正我把数字加长了。

我苦苦挣扎了几个星期,最终开始怀疑 STM HAL。然后我偶然发现了外围库中的__HAL_LOCK(在我的例子中是uart)。例如HAL_UART_Transmit_IT

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

  /* Check that a Tx process is not already ongoing */
  if (huart->gState == HAL_UART_STATE_READY)
  
    if ((pData == NULL) || (Size == 0U))
    
      return HAL_ERROR;
    

    /* Process Locked */
    __HAL_LOCK(huart);                         <<<<====== 

    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->gState = HAL_UART_STATE_BUSY_TX;

    /* Process Unlocked */
    __HAL_UNLOCK(huart);                       <<<<====== 

    /* Enable the UART Transmit data register empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_TXE);

    return HAL_OK;
  
  else
  
    return HAL_BUSY;
  

当我去锁定宏的定义时,我有点担心:

#if (USE_RTOS == 1U)
  /* Reserved for future use */
  #error "USE_RTOS should be 0 in the current HAL release"
#else
  #define __HAL_LOCK(__HANDLE__)                                           \

我已经阅读了几个关于此的主题。例如Here 和here。我还可以阅读许多关于锁定机制实现不佳且根本不是线程安全的主题。有趣的是,即使没有 RTOS,但使用中断也是一个潜在的问题。

我下载了 STMCube 最新版本,看看现在能不能解决这个问题。但它仍然处于相同的状态。 STM HAL 似乎对他们的 USE_RTOS marco 没有太大作用。

在我的程序中,我使用不同的任务在同一个 uart 实例上进行读写。 LWIP TCP 线程将发送数据,而 LWIP RX 线程将不断从 uart 读取数据。我的 uart 以中断模式接收数据(逐字节传递到环形缓冲区)。

最后是我的问题:

    这种锁定机制是否可能是我的硬故障的根本原因?我试图找到遇到同样问题的人,但在这个意义上找不到可以证实这一点的“证据”。所以也许“可怕的锁定机制”不是最好的实现,但不是我问题的根本原因。

    是否有“步骤”可以从硬故障中获取更多细节?我真的很想找到有问题的代码行。我找到了解释如何继续的this 页面,但我不知道如何获取 pc(我正在使用 VScode,我可以在 while(1) 循环中中断,但是然后...?)。

这里总是崩溃:

HardFault_Handler
prvPortStartFirstTask
xPortStartScheduler

很抱歉这个冗长的问题,但我想至少是彻底的,希望有人可以确认一些事情,或者甚至可以帮助我在正确的方向上解决这个问题......

非常感谢!

【问题讨论】:

你找到这个帖子了吗community.st.com/s/question/0D50X0000BOtfhnSQB/… ? 哦,我的...我现在有了。我要仔细阅读这篇文章。已经找到了我遇到的问题的一种解释。由于不是线程安全的锁定机制,Lwip 停止消费数据包。该问题针对以太网进行了解释,我假设这同样适用于我的 pppos 设置以进行 uart 外围锁定。谢谢这个链接! 【参考方案1】:

切换任务时出现 HF 的常见原因有以下三种:

    在 ISR 中使用非 ISR 函数。 堆栈溢出(在 freeRTOS 配置中启用堆栈溢出检查) 错误的互联网优先级 freeRTOS 文档中对这三者都有很好的解释。

我个人更喜欢在调度程序启动时在任务中进行初始化。它可以防止许多非常难以跟踪的代码问题。

我使用 freeRTOS 运行 HAL、LWIP、不同类型的网络连接没有任何问题。

【讨论】:

谢谢你的答案。 1)我只启用了2个中断,uart接收中断(prio=6)和timer6(增加hal tick,prio=15)。只有 uart 中断调用 freertos (xSemaphoreGiveFromISR)。 2)对于***,我编写了一个函数,该函数禁用所有中断并在高水位标记接近零的while循环中挂起(所以它应该更早关闭,这样我就不会冒堆栈溢出的风险,我看看后续伤害)。对于我经常重读文档的中断优先级,我按照书本做所有事情。 我还没有尝试过关于 freertos 的“如何分析硬故障”的建议。我想我将不得不深入研究。读取 PC 计数器并尝试将其映射到 bin/elf 文件。度过这个难关。除了你 atm,我没有人可以和你讨论其他事情:D。因此,当然不要指望您会释放您的议程,但是如果您能想到其他任何事情或有一些出色的见解可以帮助我走得更远,我们将不胜感激。如果你能看一眼,我很乐意分享我的代码。这是 99% 的库代码,所以“我的代码”并不多 到此为止,我可以在夜间毫无问题地运行我的“tcp 测试”(打开套接字、关闭套接字、永远重复),**只要我添加一个 vTaskDelay(100)”在循环中。在服务器端捕获wireshark数据也是完美的。没有重新传输或任何东西。当我在while循环中删除vTaskDelay(100)时,大约5-30秒后我会遇到一个硬故障。那种排除我的堆栈溢出。【参考方案2】:

我已经猜到了,问题出在我自己的代码中。我正在使用 std::vector 并且我认为由于 vector 完成的 malloc 导致堆碎片。

这个页面帮我排查了很多硬故障!

https://interrupt.memfault.com/blog/cortex-m-fault-debug

【讨论】:

以上是关于带有 FreeRTOS 的 STM HAL,是/否/也许?的主要内容,如果未能解决你的问题,请参考以下文章

CubeMX STM32 HAL + FreeRTOS

基于STM32与FreeRTOS的消息传递详解(HAL库)

基于STM32与FreeRTOS的消息传递详解(HAL库)

基于STM32与FreeRTOS的消息传递详解(HAL库)

HAL STM32F407ZGT6 FreeRTOS

使用HAL对STM32F407ZGT6单片机移植FreeRTOS(参考正点原子)