Two Propeller Communication
hylee101001
Posts: 48
in Propeller 1
Is there anyone tried sort of i2c between two propellers? Since I can't just wait for prop2, I was wondering if sort of i2c can make two prop1s communicate. Since I need them to exchange lots of data with fast speed, I was planning to design one cog for each prop1 send and read while another cog for each can read and send. Would that be waste of cogs?
Also, is there a way I can attach an extra eeprom ? - What i'm trying is using machinne learning algorithm that needs lots of data....
Please let me know if you have any related thoughts..
Also, is there a way I can attach an extra eeprom ? - What i'm trying is using machinne learning algorithm that needs lots of data....
Please let me know if you have any related thoughts..
Comments
Some people have written special protocols for prop-to-prop communication with transfer rates on the order of megabytes per second. I can't remember who, though, and have never needed one.
I think you might be able to (ab)use the FullDuplexSerial driver or anything based off of it and set the baud to something ridiculously high (say, clkfreq) on both propellers. They'll both go as fast as they can, and if the maximum receive speed is the same as the maximum transmit speed, and I think they are the same because of how FullDuplexSerial and descendents use coroutines, it will work.
If you need to store lots of data, I'd recommend an SD card instead of an EEPROM. But you can easily attach another EEPROM if you really want to: attach it to the same pins, but don't connect the A2, A1, and A0 lines all to 0 (GND), and use i2c#EEPROM | %xyz, where xyz are the values you connected A2, A1, and A0 to. Since there are 8 possible values for 3 bits, you can connect up to 8 EEPROMS like this.
EDIT: I'm really good at loading pages, not looking at them for 15 minutes, and then replying.
Numbers always help, what exactly is " lots of data" and "fast speed" ??
and what size Packets work best ?
Do you need handshake built into the link ?
Do you really need full duplex, or is half duplex OK ?
Oh, never mind. I put waitcnt and it works. Thanks.
====================================================================================
Okay, I have tried with uart with 115200 baud rate because after comparing the prop commnication object, it looks the speed is not that different and uart can send and receive data with one a cog. - let me know if I'm not precise.
Anyway, I tried some message receive and transmit. But, the parsing is little tricky. My set up is using characters. For example when I send Euler angle,
repeat i from 0 to 2
com.str(String("c"))
if (long[eAnglePtr] =>0)
axis := 2*i + 1
else
axis := 2*i + 2
com.dec(axis)
if (||(long[eAnglePtr]) < 10)
com.str(String("0000"))
elseif (||(long[eAnglePtr]) < 100)
com.str(String("000"))
elseif (||(long[eAnglePtr]) < 1_000)
com.str(String("00"))
elseif (||(long[eAnglePtr]) < 10_000)
com.str(String("0"))
com.dec(||(long[eAnglePtr]))
And another prop receives:
0M11200M21200M31200M41200M51200M61200c100487c400494c517930M11200M21200M31200M41200M51200M61200c100487c400494c517930M11200M21200M31200M41200M51200M61200c100487c400493c517930M11200M21200M31200M41200M51200M6
(There's another message M1 from M6 that is all positive 1200)
The reason why I used this rather than binary is because the order of message can be changed without updating receiver's code if I add or modify message.
Anyway, to parse the message, I used the same code as I parsed message from pc to prop.
PUB communicate
repeat
if com.RxCount
readCharArray_prop
com.RxFlush
else
sendCtrlRef
PRI char2ASCII(charVar) ' currently not used
result := byte[charVar]
' Don't know how, but this returns ascii code of char
PRI ASCII2Dec(ASCII)
result := ASCII - 48
PRI readCharArray_prop | newPWM, newPidProperty, newRequest, newMode
varChar2 := varchar
varChar := com.CharIn
if (48=<varChar AND varChar=<57) 'btw 0-9
newValue := newValue*10 + ASCII2Dec(varChar)
elseif(varChar == 77) ' M -> motor
type := 1 'next 5 digits are (motornumber & pwm)
elseif(varChar == 99) ' c -> comp filter
type := 2 ' next 5 digits are mode types
if (type==1)
if 11099 < newValue AND newValue < 63000
motorNumber := newValue/10000
newPWM := newValue//10000
case motorNumber
1: long[pulsePtr][0] := newPWM
2: long[pulsePtr][1] := newPWM
3: long[pulsePtr][2] := newPWM
4: long[pulsePtr][3] := newPWM
5: long[pulsePtr][4] := newPWM
6: long[pulsePtr][5] := newPWM
type := 0
newValue := 0
elseif (type == 2)
if 1_00000 =< newValue AND newValue =< 6_18100
axisNumber := newValue/100_000
value := newValue//100_000
case axisNumber
1: long[eAnglePtr][0] := value
2: long[eAnglePtr][0] := -value
3: long[eAnglePtr][1] := value
4: long[eAnglePtr][1] := -value
5: long[eAnglePtr][2] := value
6: long[eAnglePtr][2] := -value
type := 0
newValue := 0
value := 0
axisNumber := 0
But, somehow it doesn't parse it well unlike that it parsed ok message from pc. It says all zero.. Would it be because, from pc, the message doesn't keep coming into prop, but this one has continuously incoming message?
Can anyone notice any bugs? If you have an idea about how to communicate better and efficient, please let me know
As we say here in Hollywood... for your consideration. Note that the process is divided into small (atomic) chunks.
The only "problem" with my approach is that it requires a separator between fields. Since you're going with human readable text, you might consider adding this (space or comma) as it will help you manually debug strings.
I actually have a question. If human-readability is not considered, does this still require some separators btw the tokens? Actually, when I send the msg with my previous codes, it didn't work well if there's no waitcnt(cnt +clkfreq/10) from the sender-side. In this case, I guess the waitcnt worked as sort of separator. So, what happens to prop buffer if there's no separator? - I thought, "M" and "C" are working as separator as well as "starter" of the token.
Yes. You'll note in the get_dec() method a non-digit character will cause an early exit. If this is M or C it will be lost to the stream using this strategy. By inserting a field separator, this problem goes way.
The way I've structured the code it does processing on-the-fly, but you may want to check the size of your RX buffer for if you're blasting out a very long command string.
Exactly.
This allows you to not lose characters on early exit. For example, "M01C2;" will set motor[0] to 1 and filter to 2, even though both numbers were too short. As JonnyMac said, his code would drop the "C2" if you sent it that. (The semicolon in my example is to terminate the get_dec after the 2. Otherwise, it would just sit there waiting for more characters. You could have another command instead of the semicolon if you had more commands to send, or you could send all 5 expected digits. You could also use a newline or any other character that doesn't do anything else.)
It does this by holding the last-received character in k, and only accepting another character when it found a use for the previous one. So, if get_dec gets a "C" and doesn't know what to do with it, it returns without consuming the "C". When control gets back to the main loop, it consumes the "C" and then calls get_comp_filter.
You could remove the argument to get_dec and make it go until it got an invalid character, if you wanted to.
Something like this parser (a very simple recursive ascent parser) can be used to parse pretty much anything. More advanced ones have more helper functions (like get_motor and get_comp_filter) that call each other. In fact, I'm pretty sure that Prop Tool's compiler uses a recursive ascent parser, although it's more complicated in that it operates on whole tokens at a time and not just single characters.
com.str(String("c"))
com.dec(x)
com.str(String("d"))
com.dec(y)
...
In that way, I guess the buffer is only filled with a byte, "c" and send, then the buffer is filled with a long, x and send and so on.
So, I wonder how I can concatenate all characters and longs together..?
Also, is there a specific time for the sender to wait so that the receiver buffer shouldn't be overwritten? If so, how much time do I need to pause?
It is able to handle more then one P1 but needs basically 2 Cogs per Prop. One is a sender, the other the receiver.
So the data will be send around and around like in a loop. You basically create a shared HUB ram area between the Cogs and can share Mailboxes like done on one Prop, but with multiple Props.
The interesting part here is that you do not need to write a parser for your data stream or create a communication protocol at all. So you can use most of the standard objects without change. But all Props loose two Cogs and two pins and the amount of hub ram to hold the shared data.
How you use the shared hub buffer is up to you. Its just hub-ram accessible from Spin or Pasm, but identically on all Props.
Sadly there is no support for locks over multiple Props, so you have to take care of that by yourself.
Worth looking at it.
here some links:
http://forums.parallax.com/discussion/99222/propeller-demo-14-5-meg-baud-high-speed-prop-to-prop-serial-communication
http://forums.parallax.com/discussion/comment/694610#Comment_694610
http://forums.parallax.com/discussion/134641/demo-high-speed-multi-prop-to-prop-communication
Enjoy!
Mike
Pretty much a ready made solution for providing cog/IO expansion.
For all, I have a question about my code. I think the parse algorithm works well with "Parallax Serial Terminal.spin". But when I tried with 4fullduplexseiral.spin" negative values becomes to zero - especially for 'a' , and 'b' for less often times. I think the parser cog works fine but debugging code is not working well. Just for test case, each object has only one connection for now. Can anyone notice a possible bug? - Odd thing is that if only ParallaxSerialTerminal objects are used, there was no issue at all..
For sure, the incoming value format is a#;b#;c#;d#;a#b#;c#; .. and so on.
where # are any integers between -18000 to 18000
Thank you.
"I really like Beau Schwabe's High Speed communication. (12mbit?) ... It is able to handle more then one P1 but needs basically 2 Cogs per Prop" .... No, only ONE cog is required to maintain background communication.
If you only have two Props connected, then one needs to be a "sender" while the other needs to be a "receiver"
If you have three or more Props only ONE needs to be a "sender" while all of the others are "receivers" ... This is just to initiate the communication flow. The "buffer" can be updated by any Propeller at any time thus no need to have a sender and receiver per Propeller.
Since the Forum upgrade most of my code that I wrote simply seems to be gone.
Even the OBEX is void of any code I provided.
It's been almost two years since I was let go from Parallax and the Propeller is no longer my processor of choice. Consequently my heart and head aren't there anymore.
Beau,
Most, if not all, the code you wrote while working for Parallax is now under the author "Parallax Inc" in the OBEX.
This is the latest I have.
VSS is ground. The Propeller should be powered from 3.3 volts.
"Most, if not all, the code you wrote while working for Parallax is now under the author "Parallax Inc" in the OBEX" ... and WHY is that exactly? ... It makes any updates impossible to manage.
Just a note to say that my little game console (in the signature) uses that high speed serial driver to share the video ram between the two propellers, one way only (from CPU to GPU), in case some of you are looking for another practical application.
My messy bread board