修复流式USB数据的差距

时间:2010-07-27 15:35:12

标签: c# .net usb

我们有一个带有一些FPGA和一个FTDI USB控制器的硬件系统。通过USB的硬件流数据以大约5MB / s的速度传输到PC,软件的任务是保持同步,检查CRC并将数据写入文件。

FTDI芯片有一个“忙”的引脚,当它等待PC开展业务时它会变高。 FTDI和其他硬件上的缓冲量有限。

忙线的持续时间比硬件缓冲时间长(50-100ms),所以我们正在丢失数据。为了避免我们重新设计硬件,我被要求“修复”这个问题!

我认为我的代码足够快,因为我们的代码运行速度高达15MB / s,因此在某个地方留下了IO瓶颈。我们只是期望PC / OS过多吗?

这是我的数据录入点。偶尔我们会得到一个丢弃的位或字节。如果校验和不计算,我会一直移动直到它完成。 byte []数据几乎总是4k。

    void ftdi_OnData(byte[] data)
    {
        List<byte> buffer = new List<byte>(data.Length);
        int index = 0;

        while ((index + rawFile.Header.PacketLength + 1) < data.Length)
        {
            if (CheckSum.CRC16(data, index, rawFile.Header.PacketLength + 2)) // <- packet length + 2 for 16bit checksum
            {
                buffer.AddRange(data.SubArray<byte>(index, rawFile.Header.PacketLength));                 
                index += rawFile.Header.PacketLength + 2; // <- skip the two checksums, we dont want to save them...
            }
            else
            {
                index++; // shift through
            }
        }

        rawFile.AddData(buffer.ToArray(), 0, buffer.Count);
    }

3 个答案:

答案 0 :(得分:4)

提示:不要写入文件....队列。

现代计算机有多个处理器。如果您想尽可能快地使用某些东西,请使用多个处理器。

  • 线程处理USB数据,检查校验和等。它将结果排队(仅)到线程安全队列。
  • 另一个线程从队列中读取数据并将其写入文件,可能是缓冲的。

完成;)

100ms是体面操作的大量时间。我已经成功地使用C#每秒管理大约250,000个IO数据包(财务数据),而且不费吹灰之力。

基本上,确保您的IO线程仅执行此操作并将内部存储器用作缓冲区。特别是在一端处理硬件时,执行此操作的线程应该只执行此操作,如果需要,则可能以高优先级运行。

答案 1 :(得分:2)

要在USB上获得良好的Windows读取吞吐量,通常需要将多个异步读取(或非常大的读取,这通常不太方便)排队到USB设备堆栈上。我不太确定FTDI驱动程序/库在这方面做了什么。

传统上我编写了一系列OVERLAPPED结构和一系列缓冲区的机制,并且只要它们空闲就一直将它们拖入ReadFile。大约5 - 6年前,我在USB2上做了40 + MB / s的读取,因此现代PC应该能够应付。

非常重要的是你(或你的驱动程序/库)没有进入“开始读取,完成读取,处理数据,开始另一个读取”循环,因为你会发现总线是闲逛了很长一段时间。 USB分析仪会显示是否发生这种情况。

我同意其他人的意见,你应该尽快找到正在进行读取的线程 - 不要阻塞FTDI事件处理程序超过将缓冲区放入另一个队列的时间。

我预先分配一个循环的缓冲区队列,选择下一个空闲缓冲区并将接收到的数据放入其中,然后尽快完成事件处理。

所有校验和连接与其伴随的内存分配,垃圾收集等,可以在PC上可能100个MB的缓冲时间/空间的另一侧完成。目前,您可能会有效地要求您的FPGA /硬件缓冲区适应您所需的时间来完成各种笨重的PC工作,这些工作可以在以后完成。

我很乐观 - 如果你真的可以在硬件上缓冲100ms的数据,你应该能够可靠地工作。我希望我能说服我的所有客户这么多......

答案 2 :(得分:0)

那么您的接收代码是什么样的?您是否有一个以高优先级运行的线程,仅负责捕获数据并以非阻塞方式将其传递到内存中的另一个线程?您是否以更高的优先级运行流程?

您是否设计了其余代码以避免更昂贵的第二代垃圾收集?缓冲区有多大,它们是否在大对象堆上?你有效地重复使用它们吗?