【问题标题】:Android - Losing incoming (hi-speed) USB dataAndroid - 丢失传入(高速)USB 数据
【发布时间】:2012-02-23 01:07:12
【问题描述】:

在使用 Android 时,我丢失了传入 USB 数据流上的数据,而在 Windows 中读取同一设备/流时我不会丢失这些数据。 (我知道 Android 不是实时操作系统,但 Windows 也不是,而且 Windows 在“跟上”数据方面没有问题。)

我使用具有内置 4K 缓冲区的 FTDI 2232H 芯片以大约 3.5MB/秒的速度输入数据。 libusb 中的 bulk_transfer 调用一次可以请求 16K,因此 Android 需要每 4ms 左右获取 USB 缓冲区的内容。

我尝试过:用 Java 和 C 编写,将线程(和/或进程)优先级提高到最高,同步和异步例程,我什至为每个 USB 读取传递一个单独的缓冲区,所以我什至不必须在连续读取之间复制数据。 (传输过程中不会进行垃圾收集。)我只需要缓冲 20MB 的数据,所以都到 RAM。

不过,Android 对 USB 数据“没有绕过”,有时读取之间的等待时间长达 12 毫秒,导致大量数据丢失。

有人有什么想法吗? DMA?对内核的某种“实时”请求?

【问题讨论】:

  • 你的手机是什么类型的,安卓版本是什么等
  • 两台平板电脑,一台 Toshiba Thrive 和一台 ASUS Transformer,均运行 Android 3.2.1,均已植根。 (对不起,我忘了在原帖中提到这一点。)
  • @Greg 我有完全相同的问题 (stackoverflow.com/questions/10889461/…)。你找到解决办法了吗?
  • @REACHUS - 经过数周的尝试,我终于确定 Android 平台根本无法跟上高速、“固定速率”的 USB 数据流。我放弃并在我的设计中添加了一个硬件 FIFO 缓冲区以进行补偿,这使我能够以 Android 的最大速率输出数据(具有讽刺意味的是,这比我想要的整体速度要快,但在我假设系统是间歇性间隙的情况下困扰着我只是“处理其他事件”。)
  • 我尝试了我能想到的一切(当我试图在软件中解决这个问题时)。我最终通过向设备添加一个 8MB FIFO 来解决这个问题,这使我能够以“Android 速度”提取数据。我记得,我没有“流水线”任何东西,我只是在完成一个请求后立即提出另一个请求(当时的设备有一个 4K 缓冲区,所以我期待/希望 Android 总是准备好迎接下一个缓冲区填充之前的数据包 - 它成功地完成了 99% 的时间)。如果我有机会尝试管道,我会在此处发布结果。

标签: android usb real-time


【解决方案1】:

我以前遇到过这种问题。忘记使用 Java,在后台它正在做无数的事情来阻止实时访问,例如垃圾收集,线程处理。还要忘记使用事件驱动编程,即使在高优先级线程中,也可能需要很长时间才能处理事件并且您可能会丢失数据。

我修复它的方法是编写“不友好”的代码!使用 C 或汇编,并编写了一个这样的轮询函数(在类似 C 的伪代码中):

#define PAUSE 2 /* Check twice as often as the packet rate */
#define TIMEOUT (500 / PAUSE) /* Abort if half a second of no data */

/* Provide handle, data buffer and size of buffer
   Returns TRUE if full buffer read, FALSE if not, data unread in size
*/ 
BOOL real_time_read(HANDLE handle, BYTE *data, size_t *size)
{
    BOOL result = FALSE;
    int timeout = TIMEOUT;

    set_thread_priority(REALTIME);

    while (is_handle_valid(handle))
    {
        if (is_data_pending(handle))
        {
            size_t count = get_data(handle, data, size);
            data += count;
            *size -= count;
            if (!*size)
            {
                result = TRUE;
                break;
            }
        }
        else if (!--timeout)
            break;

        /* Give a tiny time slice to other processes */
        usleep(PAUSE);
    }

    return result;
}

您提到您尝试过 C,因此将其转换为实际函数应该很简单。避免使用便利功能的诱惑,您希望尽可能接近金属。例如。如果一个 O/S 函数 Read() 又调用 read() 又调用 _read(),那么你想使用 _read()。 在此过程中,设备会明显变慢,但这是实时访问的权衡。

【讨论】:

  • 我不敢相信我没有尝试“实时”——文档让我相信最高优先级设置是“紧急音频”(-19 而不是 -20)。自从在硬件中解决了这个问题后,我可能没有机会尝试“实时”,但如果我这样做了,我会把结果发回这里。 (见上文对“dragonroot”的回复。)
  • 因为我也将尝试以这种方式解决my problem,您能否详细说明一下这个解决方案?您的完整解决方案中有多少是用 C 编写的(除了您引用的函数和它使用的函数之外,还有其他函数)?您以后使用 NDK 将它与您的 Java 应用程序连接是否有任何问题?
  • 您使用什么设备进行测试?
  • 基本上,您可以根据需要在 C 中实现,但仅此而已 - 这取决于硬件、操作系统和您在后台运行的内容。对于 Java,我使用 carray 来传递数组。我只需要一个访问低级 I/O 的 C 函数就可以了。
猜你喜欢
  • 1970-01-01
  • 2012-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多