Shop OBEX P1 Docs P2 Docs Learn Events
Prop 2 Prop Communication Which way should I go? — Parallax Forums

Prop 2 Prop Communication Which way should I go?

ShawnaShawna Posts: 508
edited 2015-03-03 19:40 in Propeller 1
I have been reading the forums for the last couple of hours and cannot decide which direction to go.

I have 2 propellers that I want to hook together. I am thinking a master and slave configuration will work. I want the master to request data from the slave once a second at max. The amount of data will probably be around 100 longs max. The master will also have to be able to write data to the slave. The props will be on 2 different boards tied together with a 6 inch ribbon cable. It doesn't need to be a master slave configuration, but I think a master slave combo might be easier to do.

What is the simplest way to do this. I looked at Beau's High Speed demo but I think that it is over kill, and to be honest I don't fully understand it.
Should I use the full duplex object or should I use I2C.
Also memory on my master prop is about maxed out and I am already using 4 cogs.
If someone could point me in a direction that would be awesome.
Thanks
Shawn

Comments

  • kwinnkwinn Posts: 8,697
    edited 2015-02-25 18:50
    For 400 bytes once a second I would suggest using the four port serial object. It provides four full duplex ports, runs at 115Kb/sec or more, uses one cog, needs only a common ground and two wire connections between the propellers. That leaves you with 3 ports for other uses.
  • ShawnaShawna Posts: 508
    edited 2015-02-25 19:21
    I will look into that thanks kwinn
  • ChrisGaddChrisGadd Posts: 310
    edited 2015-02-25 19:30
    I have an I2C slave object in the obex if you want to explore that option. As written, it only provides access to 32 byte-sized registers, but it shouldn't be too difficult to modify for 100 longs.
  • ShawnaShawna Posts: 508
    edited 2015-02-25 20:29
    It looks like the I2C object has a smaller footprint than the FullDuplex4port object, I mean the code space required. I have used the master code before also, I think I am going to to play with it first.

    I guess 1 other difference would be that I need 4 pins for the I2C and 2 for the full duplex object. I think I have plenty of pins left over.

    Thanks for the input guys.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-25 20:41
    Shawna wrote: »
    I have been reading the forums for the last couple of hours and cannot decide which direction to go.

    I have 2 propellers that I want to hook together. I am thinking a master and slave configuration will work. I want the master to request data from the slave once a second at max. The amount of data will probably be around 100 longs max. The master will also have to be able to write data to the slave. The props will be on 2 different boards tied together with a 6 inch ribbon cable. It doesn't need to be a master slave configuration, but I think a master slave combo might be easier to do.

    What is the simplest way to do this. I looked at Beau's High Speed demo but I think that it is over kill, and to be honest I don't fully understand it.
    Should I use the full duplex object or should I use I2C.
    Also memory on my master prop is about maxed out and I am already using 4 cogs.
    If someone could point me in a direction that would be awesome.
    Thanks
    Shawn

    You can get by quite fine with a single half-duplex asynch line. The slave cog will always be listening so that could just be simple Spin code which btw will take up a lot less memory than a PASM object. The master can have a bit of simple Spin code to transmit the command and then switch to Spin code to receive the response. The beauty about this is that it takes very little memory. Of course you can get as complicated as you like with multi-port objects and buffers and such but really a single I/O and a bit of Spin code is all you need. If you take this course it will be functional in no time and then if you want you can consider other options later.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-02-25 21:35
    I'm with Peter: half-duplex serial connection is easy and reliable. Add a pull-up to the line and use open-drain mode. Easy-peasy.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-25 23:33
    JonnyMac wrote: »
    I'm with Peter: half-duplex serial connection is easy and reliable. Add a pull-up to the line and use open-drain mode. Easy-peasy.

    Or just leave a series resistor in of at least 100R and it doesn't matter if there is one at either end so you don't even have to worry about switching to open-drain because open-drain on a Prop is never really open-drain. So this pin could also source current due to a software glitch perhaps in which case you want to current limit either way.

    @Shawna
    But yes, don't try to over think it, half-duplex is all that really happens on most full-duplex lines due to operation of master/slave software in that the slave is always listening and when the master talks it responds then and there only - so half-duplex is all that is ever needed. It does all you need and it's KISS. (don't make the beginner's mistake of thinking that the more complicated solution is the best, or that it's needed just in case).
  • Cluso99Cluso99 Posts: 18,069
    edited 2015-02-26 00:34
    Yes, don't overthink the problem. Half Duplex or Full Duplex will be fine at 115,200 baud. You can even make this slower if you wish.
    IMHO I2C is overkill.
  • ShawnaShawna Posts: 508
    edited 2015-02-26 04:59
    Ok, so I was looking through the obex and this is the only half dupex object I can find.

    http://obex.parallax.com/object/266

    Is this the one you guys would recommend.

    I agree I don't need anything too fancy, I would like something that runs fairly quickly, does its thing and moves on.
    I need easy and small. The only reason I am running 2 Props is because the first props code space is full.

    I appreciate all your advice guys, I don't want to over kill this task but it is nice to see all the options available.

    Thanks
    Shawn
  • wmosscropwmosscrop Posts: 409
    edited 2015-02-26 05:36
    Shawna wrote: »
    I guess 1 other difference would be that I need 4 pins for the I2C and 2 for the full duplex object.

    Shawna, I'm not sure why you would need 4 pins for I2C. On the Propeller, pin 28 is SCL and pin 29 is SDA (the prop uses I2C to access the EEPROM, if present).

    You could reuse these pins since I2C devices are individually addressed. Unless, of course, you're using them for some other (non-I2C) purpose after boot.

    Walter
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-26 05:43
    Shawna wrote: »
    Ok, so I was looking through the obex and this is the only half dupex object I can find.

    http://obex.parallax.com/object/266

    Is this the one you guys would recommend.

    I agree I don't need anything too fancy, I would like something that runs fairly quickly, does its thing and moves on.
    I need easy and small. The only reason I am running 2 Props is because the first props code space is full.

    I appreciate all your advice guys, I don't want to over kill this task but it is nice to see all the options available.

    Thanks
    Shawn

    Seems that object only goes up to 19.2k baud (and @96MHz!) so if that is fast enough for you then fine. I looked back in my old files and I have half duplex PASM drivers, so that means they will consume a cog but they do run at megabaud rates. At those speeds you can get a response back a lot faster too so that there is no waiting around if that's what your software would be doing.

    I know in Tachyon I can get 250k baud rates with the equivalent of the simple Spin object so neither requires a dedicated PASM cog, but I am always surprised at how slow Spin is when it comes to bit-banging.

    Let me know if you want a PASM driver as I can dress it up before posting. While it's possible to use FDS for this kind of thing you don't really need it to buffer the transmit because when you operate at high speed it's better to bang it out right there and then after which you can switch the line around back to receive.

    But by all means try out Kye's driver first, it only consumes 84 longs total.
  • ShawnaShawna Posts: 508
    edited 2015-02-26 06:45
    Peter,
    That would be awesome if you could post a PASM version. I was hoping to run it as fast as possible. I will probably play with Kyes example. I have 4 extra cogs available on the Prop that is about out of code space. Spin is great but not when you need speed, I was hoping to get speeds of at least 115K baud. Faster would be great to, if the ribbon cable can handle it.


    Thanks
    Shawn
  • ShawnaShawna Posts: 508
    edited 2015-02-26 06:48
    wmosscrop,
    Your right, about the 2 pin thing on I2C, Im not sure what I was thinking about. Does SPI use 4 pins?
  • BaggersBaggers Posts: 3,019
    edited 2015-02-26 06:48
    As you have 4 cogs left on the master, you could have one cog for reading and one for writing, it'd be tight as it wouldn't have to swap back and forth for in and out, have a small buffer for in.

    Is the data you need to send from the master created or pre-defined strings? if it's pre-defined you wouldn't need an out buffer either that would also help save ram space since you are almost maxed out.

    I wouldn't overcomplicate it with any other protocol, serial is probably the smallest codewise, would probably get it smaller than 84 longs and that's including two 100 byte buffers. :D

    That's assuming you don't have a lot of space left to use Kye's driver or even the simple serial driver.
  • wmosscropwmosscrop Posts: 409
    edited 2015-02-26 10:54
    Shawna wrote: »
    wmosscrop,
    Your right, about the 2 pin thing on I2C, Im not sure what I was thinking about. Does SPI use 4 pins?

    Yes, SPI uses 4 pins. That's probably what you were thinking about.

    Walter
  • jmgjmg Posts: 15,173
    edited 2015-02-26 11:12
    Shawna wrote: »
    That would be awesome if you could post a PASM version. I was hoping to run it as fast as possible. I will probably play with Kyes example. I have 4 extra cogs available on the Prop that is about out of code space. Spin is great but not when you need speed, I was hoping to get speeds of at least 115K baud. Faster would be great to, if the ribbon cable can handle it.
    Also keep in mind if chasing Size and Speed that with a Prop at each end with a crystal, you do not have to use 8 bit Async.(Half Duplex)
    That's just a loop counter, and as long as both ends agree, you can use something more useful, like 18* or 19 etc
    *18 would allow a single message to load S and D fields of an opcode, as a jmp-adr & param.
    That allows the Host to call procedures in the slave, and they echo-when-done.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-02-26 15:03
    FullDuplexSerial (and most of its derivatives) can be setup for half-duplex mode. This is right out an EFX-TEK product that uses open-drain, half-duplex serial comms.
    serial.start(SIO, SIO, %1100, BAUD)
    
  • ShawnaShawna Posts: 508
    edited 2015-02-27 06:43
    I was reading through this thread last night and I came up with an idea. I haven't had time this week to really try anything I have just been brainstorming. My master prop is running the w5200 Server object that I have modified, this object already has the pst object in it, could I just use that? Right now the PST is sending info to the parallax terminal window. I want to keep that part of the functionality for debugging purposes but couldn't I just change the rx and tx pin numbers while the program is going through its loop. That way I could use it for debugging and talking to another Prop.

    Maybe PST would no be acceptable for Prop to Prop communication anyways.
    Or maybe I should change the w5200 server object to use a different serial object.
  • kwinnkwinn Posts: 8,697
    edited 2015-02-27 07:32
    PST seems to be a slightly modified version of FullDuplexSerial that is set up to work with the PST program on your PC, but there is no reason you cannot use it for communicating between propellers as well. It would be a little trickier to use it for both prop to prop communication and debugging at the same time though. This was one of the reasons I suggested the four port object.

    You could substitute the four port object for the PST serial object, use port 0 for debugging on P30/31 and one of the 3 remaining ports for prop to prop communications. This is what I do, and why I use the four port object as the default choice. Don't forget to put resistors on all the serial pins as suggested in a previous post. That way you will not risk damaging them with a program or wiring mistake. You can also reduce the size of the spin portion of the code by removing unused subroutines as well.

    BTW, half duplex serial would be fine for a master/slave setup, but full duplex is better for peer/peer communications. If the props have to share some data there may be times when having them capable of sending and receiving simultaneously will be necessary.
  • ShawnaShawna Posts: 508
    edited 2015-02-27 07:49
    This is great guys, thanks for all of the comments. I am going to start playing with the different serial programs this weekend. Since the master already has PST in it, I think it might be wise to pull pst out and put in the full duplex object. I haven't looked at the size of the full duplex object yet, but I will. Thanks for the suggestion kwinn. I really need to figure out this prop to prop communication thing. I ran into problems with my quad project and needed a second prop, it kind of derailed the project because I didn't know where to go with it. I guess that wasn't the only reason though.:)

    Thanks Again Guys
    Shawn
  • Ray0665Ray0665 Posts: 231
    edited 2015-02-28 06:17
    Here is code I ripped from my Robot this morning I thought you might use for you project.
    It uses the four port serial object and implements packet style communications
    I actually use it to communicate between a raspberry pi and the prop
    It compiles without errors and I am sure you could modify it quite easily for your own use
  • ShawnaShawna Posts: 508
    edited 2015-02-28 08:29
    Thanks Ray I will play with your example.

    Is this the four duplex serial you use in your example?

    http://obex.parallax.com/object/248
  • Ray0665Ray0665 Posts: 231
    edited 2015-02-28 09:58
    It is close enough, I think I used the original that this is based on.
    The mods I made to the object just added things like ShoText(Port,Row,Col,StrPtr)
    Which combined positioning and text display. You should be able to drop it in and go.

    I quite literally spent five minutes removing it from a much larger routine and making sure it compiles ok.
    Ill attach my fourportserial object here for you to use.
  • ShawnaShawna Posts: 508
    edited 2015-03-01 17:44
    I have been playing with the full duplex serial example today. I have made a little progress. I looked at Rays example also, but at this point its over my head. I understand the gist of it but some of the syntax I don't understand. Anyways I wrote a short program to pass a single word from 1 cog to another cog, then display it in the parallax terminal window. I actually got it to work, but I still have one major problem that I haven't figure out. I thought that variables in spin were all signed integers. If I try to pass a negative number from 1 cog to the other I get the wrong value. Can you guys look at my code and tell me what I am missing. I am still fighting my way through it, but this seems like a dumb problem.
    CON 
      _clkmode  = xtal1 + pll16x
      _xinfreq  = 5_000_000
    
    OBJ
            Master :  "FullDuplexSerial"
            Slave  :  "FullDuplexSerial"
            Debug  :  "FullDuplexSerial"
    VAR
    long okay,cog
    long stack[140]
    word mastertoken[100]
    word slavetoken[100]
    
    PUB Main
        pause(5000)
        
        Debug.start(31,30,0,115200)
        Debug.tx(16)
        Debug.str(string("Debug Cog Started.",13))
    
        okay := cog := cognew(MasterLoop,@stack[0])
        okay := cog := cognew(SlaveLoop,@stack[20])
        
        Repeat
          pause(10)
    
    PUB MasterLoop
      Master.start(0,1,0,115200)
      mastertoken[0] := -29000
    
      Repeat
        pause(1000)
        'Master.tx(mastertoken[0])
        Master.tx(byte[@mastertoken + 0])
        Master.tx(byte[@mastertoken + 1])  
        
    PUB SlaveLoop
      Slave.start(2,3,0,115200)
    
      Repeat
        pause(1000)
        byte[@slavetoken + 0] := Slave.rx
        byte[@slavetoken + 1] := Slave.rx
        Debug.tx(16)
        Debug.dec(slavetoken[0])
       
         
    PRI pause(Duration)
      waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
      return
    
    

    Thanks
    Shawn
  • ShawnaShawna Posts: 508
    edited 2015-03-01 18:02
    I guess I figured it out.

    I changed this line from this.
    Debug.dec(slavetoken[0])

    To this.
    Debug.dec(~~slavetoken[0])

    I think I only need to do this for the terminal display, I have never had to do this before.
  • ShawnaShawna Posts: 508
    edited 2015-03-01 18:07
    I think if I was using longs instead of word sized variables I would not have had to add the ~~.
  • ShawnaShawna Posts: 508
    edited 2015-03-01 20:42
    Well, this seems to work. Its kind of sloppy but its a start. It passes 100 word variables from a master cog to a slave cog. I had to add handshaking lines. I tried adjusting the buffer size of the full duplex serial object, but if I chang the buffer size the object does not function.
    CON 
      _clkmode  = xtal1 + pll16x
      _xinfreq  = 5_000_000
    
    OBJ
            Master :  "FullDuplexSerial"
            Slave  :  "FullDuplexSerial"
            Debug  :  "FullDuplexSerial"
    VAR
    long okay,cog
    long stack[40]
    word mastertoken[100]
    word slavetoken[100]
    
    PUB Main
        pause(2000)
        
        Debug.start(31,30,0,115200)
        Debug.tx(16)
        Debug.str(string("Debug Cog Started.",13))
    
        okay := cog := cognew(MasterLoop,@stack[0])
        okay := cog := cognew(SlaveLoop,@stack[20])
        
        Repeat
          pause(1000)
    PUB MasterLoop | idx
      Master.start(0,1,0,115200)
    
      repeat idx from 0 to 99
        mastertoken[idx] := idx * -100
    
      DIRA[13]~~    'output
      DIRA[12]~     'input
      OUTA[13] := 0
      Repeat
        
        IF INA[12] == 0
          OUTA[13] := 1
          repeat until INA[12] == 1
          repeat   idx from 0 to 199 
            Master.tx(byte[@mastertoken + idx])
          OUTA[13] := 0           
    PUB SlaveLoop | idx
      Slave.start(2,3,0,115200)
      DIRA[15]~      'input
      DIRA[14]~~     'output
      OUTA[14] := 0
      
      Repeat  
        If INA[15] == 1
          OUTA[14] := 1
          repeat idx from 0 to 199
            byte[@slavetoken + idx] := Slave.rx
          OutA[14] := 0
          repeat idx from 0 to 99
            Debug.tx(13)
            Debug.dec(~~slavetoken[idx])
    PRI pause(Duration)
      waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
      return
    
    
    
  • ShawnaShawna Posts: 508
    edited 2015-03-03 19:40
    Hey guys, I thought I had this code working but something is wrong. I have been banging my head against the wall for the last 4 hours and I am stuck. So I thought I would post some code and see what you guys think.

    This code does work. When I send a byte from the slave to the master the master receives the proper value.
    CON 
      _clkmode  = xtal1 + pll16x
      _xinfreq  = 5_000_000
    
    
    OBJ
            Master :  "FullDuplexSerial"
            Slave  :  "FullDuplexSerial"
            Debug  :  "FullDuplexSerial"
    VAR
    long okay,cog
    long stack[200]
    word mastertoken[100]
    word slavetoken[100]
    
    PUB Main | idx
        pause(2000)
    
        Debug.start(31,30,0,9600)
        Debug.tx(16)
        Debug.str(string("Debug Cog Started.",13))
    
        slavetoken[0] := -265
        Mastertoken[0] := -610
    
        Debug.dec(~~SlaveToken[0])
        Debug.tx(13)
        Debug.dec(~~Mastertoken[0])
        Debug.tx(13)
        
        cognew(MasterLoop,@stack[0])
        cognew(SlaveLoop,@stack[100])
        
        Repeat
          pause(2000)
    PUB MasterLoop
      Master.start(1,0,0,115200)
                               
      repeat
    
          master.tx(byte[@mastertoken + 0])
          master.tx(byte[@mastertoken + 1])
        
        pause(10)  
      
    PUB SlaveLoop 
      Slave.start(3,2,0,115200)
      
      repeat
     
        byte[@slavetoken + 0] := slave.rx
        byte[@slavetoken + 1] := slave.rx
    
        debug.dec(~~slavetoken[0])
        debug.tx(13)
    
        pause(10)
     
    PRI pause(Duration)
      waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
      return
    

    When I try to transmit with the slave cog instead of receive, I get garbage.
    CON 
      _clkmode  = xtal1 + pll16x
      _xinfreq  = 5_000_000
    
    
    OBJ
            Master :  "FullDuplexSerial"
            Slave  :  "FullDuplexSerial"
            Debug  :  "FullDuplexSerial"
    VAR
    long okay,cog
    long stack[200]
    word mastertoken[100]
    word slavetoken[100]
    
    PUB Main | idx
        pause(2000)
    
        Debug.start(31,30,0,9600)
        Debug.tx(16)
        Debug.str(string("Debug Cog Started.",13))
    
        slavetoken[0] := -265
        Mastertoken[0] := -610
    
        Debug.dec(~~SlaveToken[0])
        Debug.tx(13)
        Debug.dec(~~Mastertoken[0])
        Debug.tx(13)
        
        cognew(MasterLoop,@stack[0])
        cognew(SlaveLoop,@stack[100])
        
        Repeat
          pause(2000)
    PUB MasterLoop
      Master.start(1,0,0,115200)
                               
      repeat
    
        
          byte[@mastertoken + 0] := master.rx
          byte[@mastertoken + 1] := master.rx
          
        debug.dec(~~mastertoken[0])
        debug.tx(13)
        
        pause(10)  
      
    PUB SlaveLoop 
      Slave.start(3,2,0,115200)
      
      repeat
     
        slave.tx(byte[@slavetoken + 0])
        slave.tx(byte[@slavetoken + 1])
    
        pause(10)
     
    PRI pause(Duration)
      waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
      return
    

    Pins 1 and 2 are tied together with a 330 ohm resistor and pins 0 and 3 are tied together with a 330 ohm resistor. I don't have any pull-up or pull-down resistors attached. I believe I am using the original fullduplexserial object.

    Thanks
    Shawn
Sign In or Register to comment.