代码之家  ›  专栏  ›  技术社区  ›  Tim

修复USB数据流中的间隙

  •  6
  • Tim  · 技术社区  · 14 年前

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

    FTDI芯片有一个“忙碌”的pin,当它等待PC完成它的业务时,pin会变高。在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 回复  |  直到 14 年前
        1
  •  4
  •   p.campbell    14 年前

    提示:不要写入文件。。。。排队。

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

    • 另一个线程从队列中读取数据并将其写入一个文件(可能是缓冲的)。

    已完成;)

    100毫秒是一个体面的操作时间很多。我已经成功地使用C#管理了每秒约25万个IO数据包(财务数据),毫不费力。

        2
  •  2
  •   Will Dean    14 年前

    为了在Windows on USB上获得良好的读吞吐量,通常需要将多个异步读(或非常大的读,这通常不太方便)排队到USB设备堆栈上。我不太清楚FTDI驱动程序/库在这方面的内部功能。

    传统上,我用一组重叠的结构和一组缓冲区来编写机制,一有空就把它们塞进ReadFile。大约5-6年前,我在USB2上读40+MB/s的数据,所以现代的pc肯定能应付。

    我同意其他人的观点,即您应该尽快脱离正在进行读取的线程—不要阻塞FTDI事件处理程序的时间超过将缓冲区放入另一个队列所需的时间。

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

    不过,我很乐观——如果你真的能在硬件上缓冲100毫秒的数据,你应该能够让它可靠地工作。我希望我能说服我所有的客户允许这么多。。。

        3
  •  0
  •   Ian Mercer    14 年前

    那么你的接收代码是什么样的呢?您是否有一个以高优先级运行的线程专门负责捕获数据并以非阻塞的方式将其在内存中传递给另一个线程?您是否以提升的优先级运行进程本身?

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