修正流式传输USB数据中的间隙

问题描述:

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

FTDI芯片有一个'繁忙'的引脚,它在等待个人电脑开展业务时处于高位。 FTDI和其他硬件上的缓冲区数量有限。

繁忙的线路比硬件缓冲时间长(50-100ms),因此我们正在丢失数据。为了避免我们重新设计硬件,我被要求“解决”这个问题!

我认为我的代码足够快,因为它运行速度高达15MB/s,因此会在某处留下IO瓶颈。我们是否仅仅期望PC/OS太多?

这是我的数据输入点。偶尔我们会得到一个丢失的位或字节。如果校验和无法计算,我会转换直到它结束。字节[]数据几乎总是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); 
    } 

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

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

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

成品;)

100ms的是大量的时间体面操作。我已经使用C#成功管理了每秒250,000个IO数据包(财务数据),而且没有出汗。

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

+1

我想一个简单的测试将是权力的范围,评论写作文件,并给它一个测试! – Tim 2010-07-27 15:39:51

+0

@Tim,这是答案。最重要的限制是“线程安全”要求。您将创建一个在两个线程之间共享的互斥锁,在队列被写入/读取时锁定。这里的技巧是在文件写入线程中,您应该锁定,将大块数据复制到本地缓冲区,然后解锁。不要再锁定任何时间,否则你的两个线程在一个线程上没有优势。 – 2010-07-27 15:41:36

+1

其实我使用NO mutx - 使用的方式太多了。我使用一个Spinlock(新的.NET 4.0),因为我的代码除了从队列中取出或放入其他东西外);最重要的是,如果你在每个项目上创建新的缓冲区(就像我一样),你真的只会锁定在插入/检索...没有复制操作。 – TomTom 2010-07-27 15:43:21

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

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

+0

我正在使用FTDI库中的'received data'事件。它调用我的函数并将它传递给byte []。它通常总是4k ...我会用一些代码更新这个问题... – Tim 2010-07-27 15:47:52

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

传统上,我已经编写了一系列带有OVERLAPPED结构和缓冲区数组的机制,并在它们空闲时立即将它们铲入ReadFile中。大约在5-6年前,我在USB2上做了40 MB/s的读取,所以现代PC肯定能够应付。

您(或您的驱动程序/库)不会进入“开始读取,完成读取,处理数据,开始另一个读取”循环,这是非常重要的,因为您会发现总线闲置着大量的时间。 USB分析仪会告诉你这是否发生。

我同意其他人,你应该下车线程的是读尽快发生的一切 - 不要阻挡FTDI事件处理程序,任何比在需要把缓冲到另一个队列更长。

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

所有校验和与其伴随的内存分配,垃圾收集等级连接都可以在PC的缓冲区时间/空间的潜在数百MB的缓冲区中完成。目前,您可能正在有效地询问您的FPGA /硬件缓冲区,以适应您花费大量时间完成各种繁重PC工作的时间。

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

+0

我们已经得到了大约10ms的缓冲区:-) – Tim 2010-07-27 16:53:29

+0

我仍然认为你可能会应付10ms,只要你不需要不必要地拖延阅读器。你在英国的哪个地方? – 2010-07-27 19:34:23