【发布时间】:2017-03-22 06:55:30
【问题描述】:
悬崖笔记版 TI F28377S 有两个 CPU,一个主 CPU 和一个辅助 CPU(CLA,一次只能执行一项任务,任务不中断)——它们共享 RAM 的消息区域。当快速向 CLA 发出的大约 15 个字节(最大 32 个队列长度)的队列提供数据时,有时几个字节将永远不会被传输。我认为 CPU 中断存在一些问题,导致单个字节在将它们交给缓冲区时偶尔会“丢失”。
完整版 (这里使用的是 TI F28377S,其主 CPU 主频为 200 MHz,辅助独立 CLA 以相同速度运行,但一次只能执行一项任务。它们可以共享单向可写变量)。
我对如何执行这个涉及 CLA 和队列的更复杂的任务感到有些困惑。
一些快速背景知识:我有两个主要的 CLA 任务,第一个 (Task1) 由 ADC 转换结束触发(它本身由 Timer0 在 100 kHz 触发),第二个 (Task2) 由 Timer0 本身触发(这是经过大量实验和调整后得出的,因为每当我让 Task2 比 ADC 任务运行得更频繁时,ADC 任务永远不会启动 - 所以我将它们设置为使用相同的间隔,只是交错)。 Task1 完美运行,将 ADC 结果存储在一个简单的环形缓冲区中,并在 Task1 完成后 ISR 中执行简单的计算。第二个主要工作。
Task2 用于切换一些 GPIO 引脚以与外部设备通信。因为代码的总长度大约为 100 微秒,所以我没有延迟,而是在每个触发器上使用一个简单的 case 结构来确定它是否应该:什么都不做,打开代码引脚,打开频闪引脚,关闭频闪引脚,关闭代码引脚。这样每次调用任务时,它几乎立即完成,输出代码的长度适合外部设备。该任务每次处理一个代码,一旦完成,就会尝试从队列中获取另一个代码。如果没有,它会继续直接通过。
现在,棘手的部分。我有两个要求:1)我可以比任务消耗它们更快地向队列末尾添加字节(在理论上和实践中都非常容易)和 2)我可以在队列的前面添加一个字节(不是替换当前正在传输的字节,就在队列的前面)。第一个能力是发送中短消息(2-20 个字符)。这第二种能力对于发送有关任何外部中断的单个字节是必要的 - 尽可能快,甚至在传输消息的过程中也是如此。我已将其设置为任务每 500 微秒发送 1 个字节(约 300 个“开”和约 200 个“关”)。这样,如果有中断消息进来,将保证收到少于 1 个发生后的毫秒数。
目前的工作是:CPU 上的一个函数,它接收传入的字节(一次一个)并将它们添加到 CPU2CLA 缓冲区并增加 CPU2CLA 长度计数器。每次运行 Task2 时,它都会检查此队列并从 CLAonly 缓冲区的前面获取一个字节,增加它自己的缓冲区长度,并标记一个字节已被消耗。当 Task2 任务后 ISR 运行时,它会检查一个字节是否被消耗,并从 CPU2CLA 缓冲区中删除第一个字节。目前这个双缓冲系统没有添加到前面的标志,所以它不处理中断情况。
我之前尝试的是创建一个 Task3,它占用一个通过 CPU2CLA 的字节,并使用 Task3andWait 从 CPU 运行它。虽然这种方法理论上应该同时满足这两个要求,但大约有一半的时间,一两个字节的消息永远不会被传输(一个字节总是被发送)。
CLA 任务永远不会被中断,但 CPU 任务可以。这就是为什么我试图让队列的所有修改只发生在 CLA 中,这样就永远不会有可能中断队列修改的不确定状态。
【问题讨论】:
-
TL:博士。如果您“可以比任务消耗它们更快的速度将字节添加到队列末尾”,您将需要阻止输入。如果这是需要您将字节发布到队列前面的基本问题,那么您肯定会对传入的字节做出值判断:因此,您的函数执行的处理超出了应有的处理,因此是瓶颈。
-
队列现在只有 32 字节长(已修复)。我的传入函数会简单检查长度是否 == max_length,退出(即删除字节)。
-
那么你在什么前提下将字节发布到队列的前面?数据的必要性如何?你能承受失去它吗?如果是这样,当您无法足够快地处理传入数据时,只需重置缓冲区。
-
相同的功能(带有用于前/后的布尔标志)。如果已满,请忽略。如果不是,则将所有字节移回 1 位,并将新字节放在前面。我应该补充一点,到目前为止,测试用例从未超过 15 个字节,并且总是附加到末尾。
-
请用不到 100 个字来定义您的问题,并以示例 Minimal, Complete, and Verifiable example 说明问题。
标签: c queue embedded message-queue