Shop OBEX P1 Docs P2 Docs Learn Events
Inter Propeller communication — Parallax Forums

Inter Propeller communication

JufraJufra Posts: 24
edited 2010-03-03 09:09 in Propeller 1
Hi all,

I've been searching a lot in the forum and on the web but couldn't find what I needed. So i do apologise if the question has been answered already, but I have been unable to find it.
Ok, my problem is this: I need to make 2 Prop chips talk to each other, the idea is that one chip collects readings from a variety of sensors and is supposed to send it to another prop for datalogging and interfacing with the internet etc...

So the prop looking after the sensors sends out a data sequence, starting with a certain pattern, then followed by the actual sensor readings, finally the sequnce is finished. I mucked around with the BS2 functions and the SERIN SEROUT commands, but I ended up having trouble with the handshaking/synchronisation. If the sensor prop pumps out the data with a little (100ms) pause between the different data bits, the other side picks it up, but the moment I introduce a handshaking mechanism (where the receiveing prop uses SEROUT to signal the receipt of the data and indicating it is ready for new data), it fails. It is maybe that I don't fully understand the SERIN/OUT routines and whether or not they wait for data.
I've tried using different pins for the data and acknowledge, and then also two different instances of the BS2 function object, to no avail. If it is unacknowledged, it works, but with handshaking, it doesn't

So my general question is this: How do I implement a simple protocol between two props where data can be requested, sent and acknowledged? I couldn't find anything in the OBEX. It really doesn't have to be fast, the data needs to be sent across every minute or so, so heaps of time.

I looked at this video here, but this might be a total overkill
http://www.parallax.com/Portals/0/Downloads/mm/video/Webinar/2009-03-17-9a-Webinar-[18].wmv

any help is much appreciated
Thanks
Frank

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2010-02-24 06:53
    There are lots and lots of ways to do this. The BS2 functions can be used or you could use any of several other serial drivers. Some of the serial input routines wait for data and some (like FullDuplexSerial) do not. Generally the best way to have two chips talk to each other is to make one of them the master and the other a slave. If you make the sensor Prop the master, it sends out a single unique character like a "!" maybe every 100ms until it gets a unique response from the slave. There's a timeout on the serial input call for this (on the master) and, if it times out, the master goes back to sending "!". Once the master gets a response from the slave, the master can send a data record. The details of that depend on the data to be transferred. Each data record gets a response from the slave ("I got it"). The final item from the master is an end of data message which is also acknowledged by the slave.

    If you want a robust protocol, you can add checksums and more timeouts.

    I recently posted an XModem receive routine here: http://forums.parallax.com/showthread.php?p=819353

    I don't have the corresponding transmit routine, but it would be simpler than the receive routine.
  • Cluso99Cluso99 Posts: 18,069
    edited 2010-02-24 07:09
    I presume you tried FullDuplexSerial? It will do 115,200 and has 16 byte buffers. If you want larger buffers use my modified version FullDuplexSerial_rr004.

    Beau has a version that communicates >8Mbps but IIRC it uses 2 cogs.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
    · Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
  • LeonLeon Posts: 7,620
    edited 2010-02-24 07:11
    There are ASCII codes that are intended specifically for that sort of thing, like ACK and NAK.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Leon Heller
    Amateur radio callsign: G1HSM
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2010-02-24 18:10
    Did you look at: Fast Inter-Propeller Communication?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    April, 2008: when I discovered the answers to all my micro-computational-botherations!

    Some of my objects:
    MCP3X0X ADC Driver - Programmable Schmitt inputs, frequency reading, and more!
    Simple Propeller-based Database - Making life easier and more readable for all your EEPROM storage needs.
    String Manipulation Library - Don't allow strings to be the bane of the Propeller, bend them to your will!
    Fast Inter-Propeller Comm - Fast communication between two propellers (1.37MB/s @100MHz)!
  • JufraJufra Posts: 24
    edited 2010-02-25 02:50
    Thanks for all your input, guys, much appreciated.

    So far I've only tried the BS2 functions as I wanted to keep it as simple as possible. But somehow it doesn't work. Mike, yes, I have set the 2 chips up as master/slave, and the general idea I had was to do it like you suggested, but here I'm running into trouble..

    Here's what I have (the initial bits of it, the principle)
    On the master side, I do this:
      repeat until (in_data <> 0)
        BS2[noparse][[/noparse]0].SEROUT_DEC(2,start_trans,9600,1,8)  ' start_trans is a value that indicates start of trnamission
        BS2[noparse][[/noparse]0].SEROUT_Char(2,13,9600,1,8)     ' CR to end
        wait_confirm
    
    PRI wait_confirm
      in_data := 0
      in_data := BS2.SERIN_DEC(3,9600,1,8)
    
    



    Slave does it like this:
    
          in_data := 0
          repeat until (in_data == 1)
             in_data := BS2[noparse][[/noparse]0].SERIN_DEC(2,9600,1,8)   
             BS2[noparse][[/noparse]0].DEBUG_DEC(in_data) 'print out data to terminal
             BS2[noparse][[/noparse]0].Debug_Str(string(13))            
             confirm_data
    
    PRI confirm_data
      BS2.SEROUT_DEC(3,1,9600,1,8)     ' just send "1" back as acknowledge
      BS2.SEROUT_Char(3,13,9600,1,8)     ' CR to end
      
    
    



    You can see that the master to slave communication uses pin 2, the confirm uses pin 3, both also use different BS2 objects. I thought that might help, but it didn't...
    The slave never receives anything

    There's more code there, but the general sequence starts like this. If I do this a bit different (without the acknowlegments), it seems to work, but then I get the master firing data at the slave w/o any feedback which is bound to cause trouble or lockups.

    And to answer the other questions, no, I haven't tried FullDuplexSerial or fast inter-prop communication yet, I was hoping to get away with BS2 functions. But hey, I will try those as well. With the fast IP comm, I read that the chips need to be runing off the same clock, is that right? My 2 Props are sitting on different boards, each with their own crystal...

    And yes, Mike, I will also look at the code you posted (the XModem stuff)...

    Thanks
    Cheers
    Frank

    smile.gif
  • pjvpjv Posts: 1,903
    edited 2010-02-25 17:11
    Hi Frank;

    I tried to put a small edit on my post of Feb 18 to bring it near the top of the present list so I could reference it for you in this post, but that did not seem to work. I don't know how to link to previous posts.

    Anyhow, if you take a peek at my post of Feb 18 titled "5Mbit/sec ASCII streaming from/to Hub RAM" , those pieces of code should do, or at least be very easily adapted to what you want. They can run on different boards, hence slightly different crystal frequencies.

    Enjoy.

    Cheers,

    Peter (pjv)
  • JufraJufra Posts: 24
    edited 2010-02-26 09:11
    Thanks Peter, will have a look. My situation is actually different to yours. You have a good handle on assembly language and need to go through a learning curve with spin, for me it's exactly the opposite, so there you go, ha...

    Thanks
    Frank
  • Cluso99Cluso99 Posts: 18,069
    edited 2010-02-28 10:44
    pjv: To add a link to a thread, use the POST REPLY section (after copying the web address) and select the link icon (with the chain icon) and paste your link into it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
    · Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
  • pjvpjv Posts: 1,903
    edited 2010-02-28 20:26
    Cluso;

    Thanks for the advice, I had often wondered how that was done.... i'll try that now, so here is that link.

    http://forums.parallax.com/showthread.php?p=882980

    Cheers,

    Peter (pjv)
    ·
  • Clock LoopClock Loop Posts: 2,069
    edited 2010-02-28 21:44
    I do 250Kbps prop to prop using the fullduplexserial obex object.

    http://forums.parallax.com/showthread.php?p=820293
    In this thread is my blackbox. If you look at the block diagram, you will see that 3 props are communicating to a central prop.
    This central prop is acting as a data hub that passes data back and forth. This central prop also programs all other props.

    Check it out, using the full duplex serial object is very easy.

    Just don't forget to put 10k pull down resistors on both serial lines. (speeds above 115.2Kbps won't work)
    (speeds above 300Kbps won't work for me, my prop to prop wires are 6in long)

    Post Edited (Clock Loop) : 2/28/2010 9:52:43 PM GMT
  • JufraJufra Posts: 24
    edited 2010-03-02 03:50
    Hi ClockLoop,

    bingo! This works well for me, thank so much! I downloaded the code and schematics, and yes, it seems very simple to run the FullDuplex Serial.

    There is one thing however I don't understand fully yet, maybe someone can help me with this little issue.

    The Master Prop sends a "transmission start" byte (255), to which the slave responds with a confirmation byte (254). So the code in the master looks like this:

    Repeat
    
      go := 0                             'reset cycle
      SerialComm[noparse][[/noparse]0].tx(start_trans)            'send transmission start 
      If SerialComm[noparse][[/noparse]0].rxtime(50) == confirm_dat
        SerialComm[noparse][[/noparse]0].tx(data1)                 'transmit data (there are 31 bytes following here)
       ...
      ...
    ...
    
    
    



    Slave:

    Repeat
       go := 0                             'reset cycle
    
      If SerialComm[noparse][[/noparse]0].rxtime(5) == start_trans
        SerialComm[noparse][[/noparse]0].tx(confirm_dat)            'confirm data
          Repeat until (go == 32)            'read 32 bytes of data from master
           data[noparse][[/noparse]go] := SerialComm[noparse][[/noparse]0].rx      'get data into byte array
           go++
    
    



    So the slave confirms after receiveing the start byte and then waits for reception of 32 data bytes. So far so good, but when I look at the data bytes that are stored in the array I find that the start_trans value (255) is stored in there a few times, and bytes are missing at the bottom of the array.
    This means that the master keeps sending start_trans in the repeat loop. This can only mean that the master does NOT wait at this line:
    If SerialComm[noparse][[/noparse]0].rxtime(50) == confirm_dat
    but that it races through and keeps retransmitting start_trans, which the slave receives in the data array.

    So I guess my question is why is the rxtime(50) not sitting there waiting for the confirm byte? My understanding is that this is the whole idea of it?

    I can work around it in the slave by ignoring multiple 255 (start_trans) values, but it's not nice to do it like that, and there should be a proper solution to this

    anyway, thanks again to everyone here for your brilliant support so far!!

    Cheers
    Frank
  • Clock LoopClock Loop Posts: 2,069
    edited 2010-03-02 04:19
    Jufra said...
    Hi ClockLoop,

    bingo! This works well for me, thank so much! I downloaded the code and schematics, and yes, it seems very simple to run the FullDuplex Serial.

    Repeat
    
      go := 0                             'reset cycle
      SerialComm[noparse][[/noparse]0].tx(start_trans)            'send transmission start 
      If SerialComm[noparse][[/noparse]0].rxtime(50) == confirm_dat
        SerialComm[noparse][[/noparse]0].tx(data1)                 'transmit data (there are 31 bytes following here)
       ...
      ...
    ...
    
    
    



    Slave:

    Repeat
       go := 0                             'reset cycle
    
      If SerialComm[noparse][[/noparse]0].rxtime(5) == start_trans
        SerialComm[noparse][[/noparse]0].tx(confirm_dat)            'confirm data
          Repeat until (go == 32)            'read 32 bytes of data from master
           data[noparse][[/noparse]go] := SerialComm[noparse][[/noparse]0].rx      'get data into byte array
           go++
    
    


    So I guess my question is why is the rxtime(50) not sitting there waiting for the confirm byte? My understanding is that this is the whole idea of it?

    You don't use a loop to push the data with the transmit like you are doing with the receive.

    Your tx loop should look like this. I added bold items. You were close.
    Repeat
    
      go := 0                             'reset cycle
      SerialComm[noparse][[/noparse]0].tx(start_trans)            'send transmission start 
      If SerialComm[noparse][[/noparse]0].rxtime(50) == confirm_dat
        [b]Repeat until (go == 32)[/b]    
          SerialComm[noparse][[/noparse]0].tx(data1[b][noparse][[/noparse]go][/b])                 'transmit data (there are 31 bytes following here)
          [b]go++[/b]
      ...
    ...
    
    
    

    Post Edited (Clock Loop) : 3/2/2010 4:24:12 AM GMT
  • JufraJufra Posts: 24
    edited 2010-03-02 23:35
    Thanks, but that wasn't he issue at all...

    If you read the comment on the last line, it says that there are 31 bytes following, so the full code looks like this:
    Repeat
    
      go := 0                             'reset cycle
      SerialComm[noparse][[/noparse]0].tx(start_trans)            'send transmission start 
      If SerialComm[noparse][[/noparse]0].rxtime(50) == confirm_dat
        SerialComm[noparse][[/noparse]0].tx(data1)                 'transmit data (there are 31 bytes following here)    
        SerialComm[noparse][[/noparse]0].tx(data2)                  
        SerialComm[noparse][[/noparse]0].tx(data3)              
        SerialComm[noparse][[/noparse]0].tx(data4)              
        SerialComm[noparse][[/noparse]0].tx(data5)              
        SerialComm[noparse][[/noparse]0].tx(data6)              
        SerialComm[noparse][[/noparse]0].tx(data7)              
        SerialComm[noparse][[/noparse]0].tx(data8)              
        SerialComm[noparse][[/noparse]0].tx(data9)              
        SerialComm[noparse][[/noparse]0].tx(data10)              
        SerialComm[noparse][[/noparse]0].tx(data11)              
        SerialComm[noparse][[/noparse]0].tx(data12)              
        SerialComm[noparse][[/noparse]0].tx(data13)              
        SerialComm[noparse][[/noparse]0].tx(data14)              
        SerialComm[noparse][[/noparse]0].tx(data15)              
        SerialComm[noparse][[/noparse]0].tx(data16)              
        SerialComm[noparse][[/noparse]0].tx(data17)              
        SerialComm[noparse][[/noparse]0].tx(data18)              
        SerialComm[noparse][[/noparse]0].tx(data19)              
        SerialComm[noparse][[/noparse]0].tx(data20)                            
       ...
      ...
    ...
    
    



    etc... I think you get what I mean. The code I psoted was abbreviated. Sorry, I didn't make myself clear enough, it does push out 32 bytes, which are also received
    My point is that the slave receives the start_trans (which has value 255) many times before it receives any of the data bytes.

    So in the receive array you see this
    data(0) = 255  (start_trans from master)
    data(1) = 255  (start_trans from master)
    data(2) = 255  (start_trans from master)
    data(3) = data1 (data1 from master)
    data(4) = data2 (data2 from master)
    data(5) = data3 (data3 from master)
    data(6) = data4 (data4 from master)
     and so on....
    
    


    This means that the master does not got into the IF statement and keeps sending start_trans. So in essence I believe that the rxtime is NOT waiting for the confirm from the slave, and this is the part that is not clear to me...
    there seems to be some sort of race condition.
    hope I make more sense now

    Thanks
    Frank
  • kuronekokuroneko Posts: 3,623
    edited 2010-03-03 03:04
    Jufra said...
    So in essence I believe that the rxtime is NOT waiting for the confirm from the slave, and this is the part that is not clear to me...
    Why should it wait? rxtime is rx + timeout behaviour. In your case if there isn't a reply for 50ms then the method returns -1 and the master subsequently sends new start transmission characters. I think you want the blocking version, i.e. rx.
  • JufraJufra Posts: 24
    edited 2010-03-03 09:03
    Thanks Kuroneko,
    Kurenko said...
    Why should it wait? rxtime is rx + timeout behaviour. In your case if there isn't a reply for 50ms then the method returns -1 and the master subsequently sends new start transmission characters. I think you want the blocking version, i.e. rx.

    well, that might be it... I do want the timeout behaviour to avoid cog lockups. I thought 50ms would be really long since the slave is doing nothing else but wait for the start and then immediately send the confirm. Wouldn't have thought it times out (clockLoop''s code only uses 5ms, and it seems to work fine...), So you might be right, I will test it with say 500ms..
  • kuronekokuroneko Posts: 3,623
    edited 2010-03-03 09:07
    Jufra said...
    I do want the timeout behaviour to avoid cog lockups.
    Fair enough. Then put in a check for timeout (return value) and deal with it appropriately [noparse]:)[/noparse]
  • JufraJufra Posts: 24
    edited 2010-03-03 09:09
    Yes, absolutely! Good point... will do

    Ta
Sign In or Register to comment.