It's been a while since I've been here, but I am wondering how to send data from a computer to the Maple over USB. I'd simply like to tell it an angle to set a servo motor to and I want something more accurate than a potentiometer. If necessary, I can use a potentiometer and display its output in degrees and fine tune it, but I'd rather just be able to send integers to the Maple. I know it can read chars to a variable, but I haven't seen a way to parse it as an int or just read as an int. Thanks!
Sending data over USB
(26 posts) (8 voices)-
Posted 4 years ago #
-
So what you probably want to do is send the data to the Maple already in binary format. How you do this somewhat depends on where youre sending the data from (python, C, java, whatever). In that case, you can just cast every consecutive 4 bytes as a single integer like so:
union bytes_to_int {
uint8 bytes[4];
int integer;
} buf;SerialUSB.read((void*)(&buf), 4);
int x = buf.integer;bytes sent over the serial pipe should be treated as big endian, that is, the most significant byte of a 4 byte integer is sent first.
If you are trying to send integers in ascii, using the IDE or hyperterminal, then what you want is to convert strings to integers. This is fairly easy to do, ask google for some sample c code.
Posted 4 years ago # -
I should mention that the reverse direction just works, thanks for SerialUSB.print() which is overloaded depending on if you send it a char*, int, float, etc. It will convert the number to an ascii string for you.
Posted 4 years ago # -
Hello,
I was happy to read that the SerialUSB problems are being solved (February 11):
http://code.google.com/p/leaflabs/issues/detail?id=10
I am sorry that I have not been able to help much, beyond describing a few months ago my code which works with an Arduino Duemilanove, but seems to have problems with SerialUSB (using a Rev 3 Maple 2010 summer board).
Having a working bandwidth of 150Kbytes/sec would make me very happy! How does this compare to maximum Arduino transfer rates?
I have a question about how to merge multiple 12-bit analog reads into a single int (or a long long?) before transferring the result from the Maple via SerialUSB to the system (to make the most efficient use of the USB packet transfer).
How is the merge accomplished? If five 12-bit analog reads are combined does this use 60-bits?
I understand that little/big Endian relates to whether the least/most significant digits are first, but what are the implications when several 12-bit ints are merged?
At the system end, how do I "decode" the 64-byte packet back into the five separate ints?
Once I have the digits separated, I can easily convert a string of numbers to a number (eg. an int). That much I can do using C.
Now, I wish I had taken a computer science class during college.
If you do not have time to write a full explanation a list of useful google keywords will also be useful to me.
Sorry for being so much of a newbie. The first step of learning is to acknowledge how much one knows (or does not understand). Thanks for your help.
Stephen from NYC
PS. I am using Win XP SP3 and IDE 0.0.9, but for this question I do not think this is relevant.
Posted 4 years ago # -
I have a question about how to merge multiple 12-bit analog reads into a single int (or a long long?) before transferring the result from the Maple via SerialUSB to the system (to make the most efficient use of the USB packet transfer).
How is the merge accomplished? If five 12-bit analog reads are combined does this use 60-bits?
Yes, it would use 60 bits.
There are a bunch of ways to do this.
One way which makes sense is just to pack the 5 12-bit values into a 64 bit long long, like this:
void loop() { uint16 a[5]; a[0] = analogRead(0); a[1] = analogRead(1); a[2] = analogRead(2); a[3] = analogRead(3); a[4] = analogRead(4); long long res = (a[4]<<48) | (a[3]<<36) | (a[2]<<24) | (a[1]<<12) | a[0]; for (int i=0; i<8; i=i+1) { unsigned char c = res & 0xff; res = res >> 8; SerialUSB.print(c, BYTE); } }
Then receive it with something like this:
/* pseudo-host code - create the equivalent in the language of your choice */ void host(unsigned int a[]) { unsigned int c; long long res = 0L; for (int i=0; i<8; i=i+1) { c = SerialUSB.read(); res = res << 8; res = res | (c & 0xff); } for (int j=0; j<5; j=j+1) { a[j] = res & 0x0fff; res = res >> 12; } }
Warning this code has been compiled but not tested
I've used a[] for the data values to (hopefully) make it easier to see the relationship between the sender and receiver.
If you really want to get efficient use of USB bandwidth you might want to look at data compression using something loss-less (e.g. using delta encoding).
(Edit - it appears that the 'code' tag uses back tick quotes BUT ALSO p and br tags, defeating the point of 'code' - IMHO utter rubbish - anyway I've edited the post, so it should read okay]
Posted 4 years ago # -
attempting to use backtick code escaping:
void host(unsigned int a[]) { unsigned int c; long long res = 0L; for (int i=0; i<8; i=i+1) { c = SerialUSB.read(); res = res << 8; res = res | (c & 0xff); } for (int j=0; j<5; j=j+1) { a[j] = res & 0x0fff; res = res >> 12; } }
Posted 4 years ago # -
void loop() { uint16 a[5]; a[0] = analogRead(0); a[1] = analogRead(1); a[2] = analogRead(2); a[3] = analogRead(3); a[4] = analogRead(4); long long res = (a[4]<<48) | (a[3]<<36) | (a[2]<<24) | (a[1]<<12) | a[0]; for (int i=0; i<8; i=i+1) { unsigned char c = res & 0xff; res = res >> 8; SerialUSB.print(c, BYTE); } }
yup, it seems to work. put code in between backtick (`) characters, and you get the right formatting.
Posted 4 years ago # -
by the way, in the current implementation, you'll get increased efficiency if you do all your transfers in blocks of 64 bytes.
Posted 4 years ago # -
Friday, February 18, 2011
Hello all,
My weekend just began, so I plan to spend the new few hours working with the updated IDE snapshot. I downloaded it a few days ago, but have not had a chance to work with it.
Many thanks to poslathian, gbulmer, and mbolivar for the bit-shifting (?) code snippets needed to merge five 12-bit analog reads into a single variable of type uint16 and the code to split and parse data on the host end to recreate the original 12-bit data.
Here is my "aha" question for today.
I appreciate that transfers of 64 bytes is the most efficient, since that is the block size used by the USB implementation. If there are 8 bits/byte and therefore 512 bits per 64 bytes, does this mean the maple can transfer forty-two (42) 12-bit analog reads in a single USB write? 42 X 12 bits = 504 bits (wasting 8 bits or one byte).
I will post if I get interesting results with the updated IDE snapshot software.
Thanks again for the help!
Stephen from NYC
Posted 4 years ago # -
You can see USB.c - because two mode - one one-byte transfer and packet transfer (you need make a flush at end). not sure that it's implement in libmaple - but it absolutly available in ST chip
Posted 4 years ago # -
in the snapshot implementation, sends are blocking ("do the stupidest thing that could possibly work"). because of that, if you send one byte, libmaple will just wait until the host asks for any data it has, then send over that single byte. only then will it return and allow you to send more data.
attempting to be more clever about this in the past led to bugs, and we really wanted to get some code out there that behaved well, even if it was slow, to replace the broken implementation we had previously released.
Posted 4 years ago # -
Stephen,
Yes, you could pack the data that way, although you'd have to be careful to get the details right, since the readings would cross byte boundaries in an uneven way.
Posted 4 years ago # -
StephenFromNYC
code snippets needed to merge five 12-bit analog reads into a single variable of type uint16
This is probably just a slip of the pen/finger but the five 12 bit values are merged into a
long long
, not auint16
The unpacked values are returned in an array ofuint16
values.Posted 4 years ago # -
Hello,
gbulmer, yes, I got my variable types switched. Thanks for the careful read.
long long
is what is needed.Here is a "hopefully someone can quickly answer this question, because I am too lazy to figure this one out" question.
What is the largest number of 12-bit numbers which can be combined into a single long long which is then efficiently transferred in a single 64 byte block using
SerialUSB.println()
? Thirty two? If I want to useprintln()
instead ofprint()
is thirty one the largest number which should be combined?I understand that avoiding cross byte boundary errors (pointed out by mbolivar) would be easiest at the maple end and also the host ends by bit-shifting in increments of 12 (assuming the goal is to combine 12-bit analog read data). I believe this wastes 4-bits per number, but it makes decoding on the host end easier.
Thanks!
Stephen from NYC
Posted 4 years ago # -
StephenFromNYC - You could send the 12-bit values as simple two byte values.
That would be very easy to do.But, you need to pack them into a 64-byte packet anyway, so it isn't hugely simpler.
The code above packs 5 12-bit numbers (60 bits) into 1
long long
.A
long long
is 8 bytes, so they are easy to pack into 64 bytes.5 12-bit number/
long long
gives
5 12-bit number x 8long long
number / 64 bytes
= 40 12-bit numbersuse similar code (to above) to transfer the data.
Don't use println, it is a waste of two bytes ("\r\n").
Don't try to write thelong long
as a single value because that will transform the number to a sequence of ASCII characters, which will drop the transfer efficiency from 8 bits to approximately 3.3 bits/byte, defeating the entire effort.
Use SerialUSB.write(buffer, 64) to send the whole packet in one unit.Posted 4 years ago #
Reply »
You must log in to post.