7

背景资料:

我目前有一个连接到 USB 端口的硬件设备。硬件设备负责将精确的周期性消息发送到它反过来连接的各种网络上。在硬件设备内部,我有几个 Microchip dsPIC。有两种操作模式。

一种情况是将简单的“作业”发送到 dsPIC,而 dsPIC 又可以以 0.001 毫秒的精度发送精确的消息。这种架构对于更复杂的消息传递并不理想,我们需要发送一个周期性数据包,该数据包会根据 PC 应用程序中发生的事件而变化。因此,我们有第二种操作模式,我们的 PC 应用程序将发送周期性消息,而 dsPIC 只需转换和发送响应。顺便说一下,所有这些对于我们软件的最终用户来说都是透明的。我们的硬件设备是用于汽车领域的测试工具。

目前,我们使用 FTDI 的 USB 转串行芯片和 FTDI Windows 驱动程序将硬件连接到我们的 PC 软件。

问题在于,在我们从 PC 发送消息的模式 2 中,我们能够达到的最佳效果是平均硬件范围约为 1 毫秒。我们受到 Windows 内核抢占。我尝试了许多“技巧”来改进,例如:

  1. 尽可能确保我们的读取器和写入器线程存在于单独的 CPU 关联上。
  2. 增加写入器的线程优先级,同时降低读取器的线程优先级。
  3. 通知用户在使用我们的软件时关闭屏幕保护程序和其他应用程序。
  4. 用 CreateTimerQueueTimer 调用替换 createthread 调用。

我们所有的软件都是用 C/C++ 编写的。我对高级 Windows 编程非常熟悉和熟悉;比如IO Completions、Overlapped I/O、无锁线程队列(真的是一种设计策略)、sockets、线程、信号量等等……

但是,我对 Windows 驱动程序开发一无所知。我已经阅读了一些关于 KMDF、UDMF 和 WDM 的论文。

我希望经验丰富的 Windows 内核模式驱动程序开发人员会在这里做出回应......

下一个版本。我们的硬件可以选择替换 FTDI 芯片并使用 dsPIC 的 USB 接口,或者可能将开源 Linux FTDI 东西移植到 Windows 并继续在我们的自定义驱动程序中使用 FTDI 芯片。我认为通过访问 PC 端的内核模式驱动程序,我可以建立一个内核驱动程序,它可以以更精确的间隔发送周期性消息,而无需抢占和/或可能利用 DMA。

我们的业务中有一个竞争对手,我认为他的工具与他们的工具完全相似。据我所知,用户空间应用程序调度线程的时间不能超过 1 毫秒。我们目前在一个线程中使用 timeGetTime。我已经体验过定时器队列(通过 CreateTimerQueueTimer),但没有真正的改进。

WDM 是实现更精确时序的正确方法吗?

我们的竞争对手如何实现从 Windows 驱动的信号到他们的硬件的非常精确的时序,他们确实加载了一个内核驱动程序 (.sys),他们的设备和我们的一样在 USB2.0 上运行。

如果 WDM 是要走的路,我可以就我应该研究哪些内核函数来设置时序获得一些建议吗?谢谢阅读

4

3 回答 3

5

在内核模式下,您可以在不处理中断的情况下以 100 纳秒间隔的倍数触发 DPC。DPC 不能被抢占(又名被线程调度程序中断),因为线程调度程序也是一个 DPC。但是,中断仍然可以抢占 DPC。因此,间隔值 10 应该可以让您以最精确的方式进行回调。

但是,您无法访问许多功能,例如分页内存或 DPC 级别的特定线程的内存空间,因为它们在任意上下文中运行。使用可以访问更多功能的 APC 将处理推迟到您自己的用户模式进程的上下文可能很有用。

内核线程在优先级方面没有得到任何特殊处理。从调度程序的角度来看,它们与用户线程相同。内核线程可以获得更多更高优先级的级别,但通常没有内核线程使用它们中的任何一个。我不认为你的瓶颈是线程优先级。不管你的优先级有多大,只有一个高于其他人就足以让你成为获得最高优先级的“神线”。拥有最高优先级并不意味着你会得到持续的关注。操作系统仍会暂停您的线程以运行其他线程,因此不会发生量子饥饿。

关于 Windows 抢占行为的另一个注意事项:当线程由异步事件(GUI 单击、计时器触发器、I/O 完成)发出信号时,平衡集管理器会暂时提高线程的优先级,以允许完成代码以较少的抢占来完成它的处理。使用异步计时器处理程序应该提供足够的提升,以防止至少在一个量程内抢占。我想知道为什么你的代码没有落入那个窗口。但是,似乎您并不是唯一一个遇到计时器精度问题的人:http: //www.virtualdub.org/blog/pivot/entry.php?id=272

我同意保罗关于驱动程序开发复杂性的观点,但只要你有充分的理由,这不是火箭科学,只是更多的努力。

于 2012-01-23T20:18:25.180 回答
1

您对驱动程序和内核性能的关注错过了树木的森林。房间里的大象是全速 USB 2 总线帧以 1ms 周期发生的事实。高速 USB 2 微帧每 1/8 毫秒发生一次。

当您通过全速 USB 发送数据时(就像大多数 FTDI 芯片一样),您的应用程序可以希望的最好结果是数据将在下一个时间到达设备框架。对于未加载的 USB 总线,传输将在非常接近帧开始时发生。您会以 1ms 的粒度观察它,随机偏差很小。这正是您所看到的,而且还不错。例如,由于连接到同一主机的所有 USB 设备将同时看到帧,因此这是一种以优于微秒精度同步多个设备时钟的简单方法。您的应用程序可以做的只是发送一条消息,该消息不仅包含数据,而且在不久的将来的某个时间应该发送出去。USB 的另一个问题是无法保证何时会满足您的数据传输请求。毕竟,您正在与其他设备共享总线。

我认为您需要重新设计您的系统,而不是依赖于 PC 端的任何时间安排。应该假设在 PC 上运行的应用程序在时间上受限于与之交互的人的性能。任何需要保证实时性能的东西都必须在您的 dsPIC 器件上。即使是 USB 总线也无法解决问题,因为您根本无法保证您的请求将在多长时间内被安排在总线上。

基本上,如果您想在 Windows 上保证实时性能,那么必须不涉及用户模式——它必须全部在内核模式下运行,并且您必须使用专供您使用的通信通道(或者您让他们采取行动)方式,例如通过在 USB 主机顶部进行过滤)。

于 2013-02-17T04:44:51.757 回答
1

这是 Windows 内核的基本设计方面之一 - 在被动级别运行的代码(=> 所有用户模式代码)受 DPC 和中断占用时间的影响,如果你想要 1us 精度,你可能不会将使用 UMDF 或用户模式驱动程序来获取它。

然而,编写内核驱动程序并不是一件轻而易举的事情,甚至编写起来都非常困难,而且要确保它可以在客户的机器上运行(需要进行大量测试)。把它做好会花费你大量的工程资源。

作为权宜之计,我会研究> = Vista的MMCSS(http://msdn.microsoft.com/en-us/library/windows/desktop/ms684247(v=vs.85).aspx),它可能会给你有足够的优先权,你可以满意。

如果你真的想进入兔子洞,KMDF 是你应该使用的。KMDF 是 WDM 之上的一个框架,代表了许多适用于驱动程序的编码最佳实践。除非您绝对被迫,否则 KMDF始终是驾驶员的最佳选择。老实说,您几乎肯定会想要与 OSR (http://www.osr.com) 签订合同,或者聘请有编写 Windows 驱动程序经验的人(几个人?)。

于 2011-12-26T22:03:01.360 回答