如何在RTOS的Cortex-M3微控制器中以高频(> 100kHz)运行周期性线程?

时间:2019-07-20 08:40:19

标签: stm32 rtos cortex-m3 data-acquisition cmsis

我正在用STM32F107VC微控制器实现高频(> 100kHz)数据采集系统。它使用spi外设与高频ADC芯片通信。我必须使用RTOS。我该怎么办?

我尝试了FreeRTOS,但是它的最大刻度频率是1000Hz,所以我无法使用FreeRTOS每1us运行一次线程。我还尝试了Keil RTX5,它的滴答频率可以高达1MHz,但是我研究了不建议将滴答频率设置得很高的地方,因为它会增加整体上下文切换时间。所以我该怎么做? 谢谢。

4 个答案:

答案 0 :(得分:3)

您不想以此频率运行任务。如您所述,上下文切换会降低性能。这是非常低效的。

相反,您要使用缓冲,中断和DMA。由于它是高频ADC芯片,因此它可能具有自己的内部缓冲器。检查数据表。如果芯片具有16个采样缓冲区,则100kHz采样仅需要在6.25kHz处进行处理。现在,不要使用任务来处理6.25kHz的样本。在中断(定时器或某些信号)中进行接收,并且该中断应仅填充缓冲区,并在缓冲区已满时唤醒任务进行处理(并切换到另一个缓冲区,直到任务完成)。有了这个,您可以执行仅每10毫秒左右运行一次的任务。中断不是上下文切换。在Cortex-M3上,它将有大约12个周期的延迟,该延迟足够低,以至于在6.25kHz时可以忽略不计。
如果您的ADC芯片没有缓冲区(但我对此表示怀疑),则可以接受100kHz的中断,但请在其中放入尽可能少的代码。

如果您的MCU支持DMA,则更好的解决方案是使用DMA。例如,您可以将DMA设置为使用定时器作为请求生成器从SPI接收。视您的情况而定,配置可能不可行或比较棘手,但是有效的DMA意味着您可以接收大量样本缓冲区,而无需在MCU上运行任何代码。

答案 1 :(得分:2)

  

我必须使用RTOS。

不可能。如果老板或客户有此要求,请快速逃避该项目。如果无法做到,请在立即以书面形式传达您的担忧,以免您在讨论失败原因时避免后悔。如果是您的主意,请立即重新考虑。

STM32F107的最大系统时钟速度为36 MHz(如果有外部HSE石英,则为72),这意味着在100 kHz的滴答之间只有360至720个系统时钟周期。 RTX5警告是正确的,这将需要大量时间用于任务切换开销。

可能有一个100 kHz的计时器中断,并且可以在中断处理程序(don't even think about using HAL)中进行一些简单的处理,但是我建议首先研究是否真的需要每10μs运行一次代码,还是有可能将某些事情转移到DMA或计时器硬件上。

答案 2 :(得分:1)

无需设置RTOS刻度以匹配数据采集速率-两者无关。这样做将是一个非常糟糕且不明智的解决方案。

STM32具有包括SPI在内的大多数外设的DMA功能。您需要配置DMA和SPI,以将采样序列直接传输到内存。 DMA控制器具有 full half 传输中断,并且可以循环提供的缓冲区,以便在缓冲区满时从头重新开始。可以用来“双重缓冲”样品块。

例如,如果您使用256个样本的DMA缓冲区,并且采样率为100Ksps,则每隔1.28ms 独立 RTOS滴答中断和调度将获得DMA中断。在半传输中断时,前128个样本准备好进行处理;在全传输时,后128个样本可以进行处理,并且在1.28ms的间隔内,处理器可以自由地做有用的工作。

在中断处理程序中,而不是在中断处理程序中处理所有块数据-如果处理是不确定的或阻塞的,例如将其写入文件系统,则在任何情况下都是不可能的-示例通过消息队列将样本以块的形式发送到执行确定性较低的处理的任务上下文。

请注意,这都不依赖于RTOS时钟-如果任何中断调用了调度功能(例如发布到消息队列),则调度程序将在该中断后运行。将动作同步到与触发事件(即轮询)异步运行的RTOS时钟不是实现高度确定性实时响应的好方法,并且是一种特别差劲的信号采集方法,该方法需要无抖动的采样间隔来避免错误的伪像来自非周期性采样的信号。

您认为需要通过不合适的RTOS滴答频率来解决此问题的想法是误解了RTOS的操作,并且可能仅在处理器除了采样数据之外没有其他工作的情况下才起作用-在这种情况下,您可能完全不需要RTOS,但这并不是对处理器的有效利用。

答案 3 :(得分:0)

由于输入之间只有几百个周期(指令),所以典型的解决方案是使用中断来通知数据可用,然后中断处理程序将数据放在某个地方,以便您可以随意处理它们。当然,如果以这种速率连续输入数据,那么您可能会因为没有时间进行实际处理而遇到麻烦。根据传入的数据量和频率,一个简单的循环缓冲区就足够了。如果数据量相对较大(有多少是大容量?请考虑花费一个以上的CPU周期来进行一次内存访问,并且每个传入的数据需要2个内存访问),然后使用DMA作为@Elderbug建议是一个很好的解决方案,因为它消耗最少的CPU周期。