Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Losing incoming (hi-speed) USB data

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?

like image 820
Greg Avatar asked Feb 23 '12 01:02

Greg


1 Answers

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.

like image 195
Yimin Rong Avatar answered Sep 30 '22 20:09

Yimin Rong