FreeRTOS 卡在 osDelay 中

Posted

技术标签:

【中文标题】FreeRTOS 卡在 osDelay 中【英文标题】:FreeRTOS stuck in osDelay 【发布时间】:2019-09-22 22:15:45 【问题描述】:

我正在使用 STM32F446 和使用 STM32CubeMX 创建的样板进行一个项目(用于外围设备初始化和中间件,例如具有 CMSIS-V1 接口的 FreeRTOS)。 我有两个使用邮箱进行通信的线程,但我遇到了一个问题:其中一个线程主体是

void StartDispatcherTask(void const * argument)

    mailCommand *commandData = NULL;
    mailCommandResponse *commandResponse = NULL;
    osEvent event;
    for(;;)
           
        event = osMailGet(commandMailHandle, osWaitForever);
        commandData = (mailCommand *)event.value.p;

        // Here is the problem
        osDelay(5000);
    

它会延迟但永远不会出来。使用邮箱和延迟在同一个线程有问题吗?我也尝试在for(;;) 之前带来延迟,它可以工作。

编辑:我想我可以尝试为问题添加更多细节。第一个线程发送某种类型的邮件,然后等待另一种类型的邮件;我遇到问题的线程接收邮件进入第一种类型并根据它接收到的内容执行一些代码,然后将结果作为第二种类型的邮件发送;有时它必须使用 osDelay 等待它停止工作但没有进入任何故障处理程序

【问题讨论】:

延迟完成的可能性更大,它进入osMailGet(),在那里它会永远等待(或至少直到有东西发送消息或它)。 是的,我的意思是邮件是正确的,然后它会延迟但永远不会再次到达 osMailGet 我的意思是你是如何确定的?您的代码在该循环中没有执行任何外部可观察的操作,因此您必须使用调试器和断点来确定 - 您没有提到。从外部看,除了它分配给commandData 的一小段时间之外,它总是会出现“阻塞”(并且什么都不做)。 是的,我实际上是在使用 Keil v5 进行调试;我在osDelay 上设置了一个断点并到达了它,但是如果我让它再次运行,我可以看到它卡在prvCheckTasksWaitingTermination 函数中 “编辑”中描述的代码听起来不像是同一个代码。您是否已验证问题中显示的代码是否以与“根据收到的内容执行一些代码”的代码相同的方式失败? SYSTICK 正在运行吗? SYSTICK 中断处理程序是否正在执行?关于prvCheckTasksWaitingTermination 的内容应该出现在问题中——它可能是相关的。在实时系统中删除任务应该被认为是“不寻常的”——显示的代码没有显示你可能在哪里或为什么这样做。 【参考方案1】:

我宁愿使用标准的 freeRTOS API。 ARM CMSIS 包装器是垃圾。

顺便说一句,我更怀疑osMailGet(commandMailHandle, osWaitForever);

在这种情况下根本不需要延迟。如果等待数据处于 BLOCKED 状态,则任务不会消耗任何处理能力

如果另一个猜测是:

    你正在 HF 着陆 您被堆叠在上下文切换中(错误的中断优先级)

使用您的调试器,看看发生了什么。

【讨论】:

第一行是一个意见,最好作为评论发布,因为它不是答案的一部分。可能它是“垃圾”是为什么有一个 v2 API,但 freeRTOS 并没有更好,而且主观上更糟(IMO)。 @ArenaLor 连接调试器,看看它卡在哪里。可能在我写的上下文切换中。 但是 opinion 在答案中没有位置(就像意见问题在 SO 问题中没有位置一样)。使用它的原因可能是需要(例如代码的可移植性) 所以,除了不应该有基于意见的答案之外,对我来说这并不是完全垃圾,因为我可以在没有深入了解 freeRTOS API 和 @ Clifford 说,代码的可移植性(例如,我可以随时切换到 Keil RTX) @ArenaLor : P__J__ 有一点关于延迟的观点,但是这是一个糟糕的设计;如果发送任务发布消息的速度超过 5000 个滴答间隔,则队列将填满,发送者将阻塞。通常消息应该“实时”处理,你应该“信任”调度程序而不是事后猜测它。如果需要,您至少应该在进入延迟之前循环处理所有排队的消息。【参考方案2】:

osStatus osDelay (uint32_t millisec)

毫秒值指定计时器滴答数。

确切的时间延迟取决于自上次计时器滴答以来经过的实际时间。

如果值为 1,系统会一直等待,直到 下一个计时器滴答声发生

=> 你必须检查计时器是否在运行。

检查这个link

【讨论】:

【参考方案3】:

正如 P__J__ 在较早的答案中指出的那样,您不应在循环中使用 osDelay() 调用1 因为您的任务循环将在osMailGet() 呼叫等待下一个请求/邮件,直到它到达为止。 但是这个提示让我注意到你观察的另一个可能原因,所以我打开这个新答案:2

由于循环执行被 5000 个滴答声的延迟中断 - 是不是邮件的生产者填充邮箱的速度快于任务消耗邮件的速度?然后,您应该检查是否在生产者上下文中检测/处理了这种情况。

如果生产者忽略“队列已满”返回值并在邮件传输之前丢弃邮件,系统将仅处理每 5000 个时钟周期的几封邮件(或者在第一次填充后可能会丢失除少数邮件之外的所有邮件)邮箱,如果您的示例中的生产者仅填充邮箱队列一次)。 这可能看起来像是消费者任务被卡住了,即使主要问题是关于生产者上下文(任务/ISR)。


1 如果请求邮件的生成速度快于任务处理它们的速度,那么osDelay() 调用只能帮助您避免在 5000 个时钟周期内处理另一封邮件。 但是,你会遇到一个不同的问题,你应该打开一个不同的问题......

2编辑:我刚刚注意到克利福德已经在他的一个问题中提到了这个选项。我认为这个选项必须包含在答案中。

【讨论】:

以上是关于FreeRTOS 卡在 osDelay 中的主要内容,如果未能解决你的问题,请参考以下文章

osDelay() 等待时间不够

LUA解析器和系统 FREERTOS 兼容吗

FreeRTOS STM32 集成

一初识FreeRTOS之FreeRTOS简介

一初识FreeRTOS之FreeRTOS简介

FreeRTOS入门(04):中断内存追踪与调试