Hello,
I think I have confused other users and myself, so let me step back and try to summarize what I understand from recent posts about how to optimize SerialUSB()
data transfers. Then at the end of this post I will try to refocus my questions.
In my post:
http://forums.leaflabs.com/topic.php?id=639#post-3629
I was wrong to focus on how to send just five 12-bit analog reads, because I incorrectly thought that sending five 12-bit values was the most one could fit into a single USB 64-byte packet. In my hurried and faulty logic I got my bits and bytes confused. Obviously, 60-bits is a lot smaller than 64-bytes. Forty (40) 12-bit values acquired using analogRead()
should fit into a single USB 64-bit packet.
For the moment, let's just stick with the goal to efficiently send five 12-bit values using SerialUSB()
.
I feel like I am missing something really fundamental in my reading of gbulmers Maple code (http://forums.leaflabs.com/topic.php?id=639#post-3660) which he said was compiled but not tested.
I believe the five 12-bit values are first combined into a single variable (res
). res
is then broken down into pieces and each char is sent to the host using SerialUSB()
.
I understand the line from gbulmer's code:
long long res = (a[4]<<48) | (a[3]<<36) | (a[2]<<24) | (a[1]<<12) | a[0];
This uses bitshifting and ORs to combine the five 12-bit values into a single variable of type long long
.
However, I am confused about gbulmer's for loop:
for (int i=0; i<8; i=i+1) {
unsigned char c = res & 0xff;
res = res >> 8;
SerialUSB.print(c, BYTE);
}
This code uses a mask to strip the higher bits. Then to prepare the variable res
for the next cycle of the loop bitshifting (res = res >> 8
) is used before the value of c is sent via SerialUSB.print(c, BYTE)
.
The loop is executed eight times for a total of 64 bytes transferred.
Why are multiple SerialUSB.print()
statements used if the goal is to send the five 12-bit values in a single USB 64-byte packet?
My assumption is that each time (for a total of eight) SerialUSB.print()
is called the data is transferred over USB even if the 64 byte packet is mostly empty (not filled with data).
If this assumption is wrong, does the USB system wait until the eighth SerialUSB.print(c, BYTE)
command before a single, completely filled, 64-byte packet is sent?
Why is it not possible to send the entire variable res
using a single SerialUSB.print()
command? For example, SerialUSB.print(ser, LONG LONG).
In the host routine, the process is reversed. Eight SerialUSB.read()
s are used to fetch each 8-bit value, the variable res is shifted by eight bits to prepare for the use of OR. This combines eight 8-bit reads into a single long long
.
In the host code, should the line:
a[j] = res & 0x0fff;
instead be:
a[j] = res & 0xff;
Here are my refocused questions:
Goal (present): I want to use my Maple to acquire 12-bit data via analogRead()
as quickly as possible and to send the data to the host via USB as quickly as possible (without any data being dropped). A higher data transfer rate will let me apply software filters to the data set (for example, to remove 60 Hz noise from the data). I do not know if I will use the Maple to do the filtering or use the host. I will be happy to shift the filtering to the host if this maximizes the data transfer rate.
A transfer rate of 20,000 data points a second (where each data point is a 12-bit analogRead()
value) should be sufficient for my long term goals. However, a rate which is 10X slower will make me happy in the short term and will keep me plugging away.
Goal (future): DMA will speed up the data transfer between the Maple and a host system, but I think for my purposes DMA is not needed.
I may be wrong to minimize this task, but at the moment, the exact rate of analog reads is not that important to me. That can be a problem for another day.
I appreciate that two bytes are wasted using SerialUSB().println()
, but I was using
SerialUSB.println()
, to see the boundaries between analogRead() values when I debugging.
mbolivar, in your comment from:
http://code.google.com/p/leaflabs/issues/detail?id=10
Can you please share the code you used to determine the current SerialUSB()
rate to be about 150KB/second (using the February 2011 snapshot)?
I understand that at most five 12-bit values fit into one long long
(using the line from gbulmer's bitshifting code). A long long
is eight bytes, so at most forty (40) 12-bit numbers fit into 64 bytes.
Therefore, in the absence of data compression/expansion a single USB 64-byte packet can transfer forty (40) 12-bit values (acquired using analogRead()
).
My next question is: "How do I combine eight long long
values into a buffer which I can efficiently send in a single 64-byte USB packet using SerialUSB.write(buffer, 64)
"?
I assume it will be necessary to flush before calling SerialUSB.write(buffer, 64)
:
http://forums.leaflabs.com/topic.php?id=575
Thanks and sorry for any confusion caused!
Stephen from NYC