Android - 丢失传入(高速)USB 数据

发布于 2025-01-07 20:44:23 字数 499 浏览 2 评论 0原文

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

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

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

尽管如此,Android 并没有“回避”USB 数据,有时在读取之间等待长达 12 毫秒,导致大量数据丢失。

有人有什么想法吗?直接存储器存取?对内核的某种“实时”请求?

When using Android, I'm losing data on an incoming USB data stream that I do not lose when reading the same device/stream in Windows. (I know that Android is not a real-time OS, but neither is Windows, and Windows is having no problem 'keeping up' with the data.)

I have data coming in at about 3.5MB/sec using an FTDI 2232H chip which has a built in 4K buffer. The bulk_transfer calls in libusb can ask for 16K at a time, so Android needs to reap the contents of the USB buffer every 4ms or so.

I have tried: writing in Java and in C, raising the thread (and/or process) priority to it's highest, sync and async routines, and I even pass a separate buffer for each USB read so I don't even have to copy data between successive reads. (There is no garbage collection going on during the transfer.) I only need to buffer 20MB of data, so it's all to RAM.

Still, Android is 'not getting around' to the USB data, sometimes waiting as long as 12ms between reads, causing a bunch of data to be lost.

Does anyone have any ideas? DMA? Some sort of 'real-time' request to the kernel?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

掀纱窥君容 2025-01-14 20:44:23

我以前也遇到过这样的问题。忘记使用 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,因此将其转换为实际函数应该很简单。避免使用便利功能的诱惑,您希望尽可能接近金属。例如,如果操作系统函数 Read() 依次调用 read(),而 read() 又调用 _read(),则您希望使用_read()
在此过程中,设备的速度会明显变慢,但这是实时访问的权衡。

I've encountered this kind of problem before. Forget using Java, in the background it's doing untold number of things that prevent realtime access, e.g. garbage collection, thread processing. Also forget using event-driven programming, even in high priority threads, it can take a long time before the event is processed and you can lose data.

The way I fixed it was to write "unfriendly" code! Used C or assembly, and wrote a polling function like this (in C-like pseudo-code):

#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;
}

You mentioned you tried C, so it should be straightforward to convert this to real functions. Avoid the temptation to use convenience functions, you want as close to the metal as possible. E.g. if an O/S function Read() in turn calls read() which in turn calls _read(), you want to be using _read().
The device will be noticeably slower while this is going on, but that's the tradeoff of real-time access.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文