【发布时间】: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
很抱歉这个冗长的问题,但我想至少是彻底的,希望有人可以确认一些事情,或者甚至可以帮助我在正确的方向上解决这个问题......
非常感谢!
【问题讨论】:
-
哦,我的...我现在有了。我要仔细阅读这篇文章。已经找到了我遇到的问题的一种解释。由于不是线程安全的锁定机制,Lwip 停止消费数据包。该问题针对以太网进行了解释,我假设这同样适用于我的 pppos 设置以进行 uart 外围锁定。谢谢这个链接!
标签: stm32 microcontroller freertos