Shop OBEX P1 Docs P2 Docs Learn Events
Full Duplex Serial: Simultaneous Read and Write — Parallax Forums

Full Duplex Serial: Simultaneous Read and Write

floflo Posts: 38
edited 2009-12-30 06:31 in Propeller 1
I'm having problems transmitting and receiving simultaneously on my propeller using the FullDuplexSerial.spin object.

My propeller has a few buttons wired to the I/O pins and is listening for command strings sent from the computer over the USB cable. I want the propeller to alert the computer when a button was pressed.

Right now I have 2 cogs running where Comm is just listening for strings and Comm2 is sending strings out:

Comm.start(31,30,0,9600)
Comm2.start(31,30,0,9600)

cogBtnScan := cognew(scanButtons,BtnScanStack)

repeat

    Comm.RxStr(@x)
    '....parses string and does stuff with it

PRI scanButtons

dira := 1

  repeat
    '...read button states; lets say button "a" was pressed, then:
    Comm2.str(string("a",13))
    waitcnt(cnt+8_000_000)





But this doesn't work. I'm not receiving anything on the computer side. I know my software on the computer works because I can simply echo back what's received and I can read it. It seems like the scanButtons cog is crashing.

Is it because I have 2 cogs trying to access the same I/O pins?

Comments

  • LeonLeon Posts: 7,620
    edited 2009-12-27 11:13
    It isn't a good idea to have two cogs using the same pins for I/O.

    Leon

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Amateur radio callsign: G1HSM
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2009-12-27 11:23
    It's called FullDuplex for a reason, you can send and receive at the same time plus as Leon said, using two cogs on the same pins will not work as the transmit will never go low while one cog holds it high. Just use the one cog as you are not trying to transmit from both tasks.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    *Peter*
  • floflo Posts: 38
    edited 2009-12-27 20:11
    Thanks for the responses Peter and Leon. Using your suggestions I'm running only one cog but it's crashing as soon as the scanButtons cog tries to call Comm.str(string("a",13))

    Comm.start(31,30,0,9600)
    
    cogBtnScan := cognew(scanButtons,BtnScanStack)
    
    repeat
    
        Comm.RxStr(@x)
        '....parses string and does stuff with it
    
    PRI scanButtons
    
      repeat
        '...read button states; lets say button "a" was pressed, then:
        Comm.str(string("a",13))
        waitcnt(cnt+8_000_000)
    



    Are objects only accessible to the cog that created them?
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-12-27 22:09
    Flo,

    if you ATTACH your COMPLETE code to a posting
    like shown in the picture, the community can give much better advise without guessing through the fog what MIGHT be
    around your quoted code.

    As a quick hint
    if two different cog call FullDuplexSerial at overlapping times the buffers were mixed up.
    What do you guess comes out if two people talk at the same time?

    best regards

    Stefan
  • floflo Posts: 38
    edited 2009-12-27 22:54
    Thanks Stefan, hopefully this will be much clearer for you guys!
    Stefan:38 said...

    As a quick hint
    if two different cog call FullDuplexSerial at overlapping times the buffers were mixed up.
    What do you guess comes out if two people talk at the same time?

    I looked through FullDuplexSerial and it has 2 buffers: tx and rx. I don't completely understand whats going on, but it doesn't look like rx_buffer is using tx_buffer and Vice Versa.

    Thanks for the help guys.
  • localrogerlocalroger Posts: 3,452
    edited 2009-12-27 23:11
    flo, FDXS's transmit and receive operations are completely independent and coexistent. It's actually a very robust object, I use it all the time in fairly high performance applications. It's good practice to group all of your FDXS operations in one cog's codestream so that the calls don't overlap, but not totally necessary. It's not clear why you launch a cog to scan buttons; button scanning tends to have a low computational price (you don't need to sample them a million times a second) so it's easy enough to include in the main loop of your application, with cog launching reserved for those functions that need actual high speed response. Without your code posted I can't be sure but I think you may be trying it the other way around, keeping your main loop fast while farming "low priority" functions out to cogs. You can do it that way and make it work but it's much harder.
  • floflo Posts: 38
    edited 2009-12-27 23:32
    The reason I put the button scanning in a different loop is because RxStr hangs the app until a string comes in and I was unable to get RxStrTime to work. I don't know how to check if it returned "-1" because it's returning strings... Anyone use it before?

    So if I understand localroger, you would do something like this in a single cog:

    scanButtons
    if buttons have changed -> send serial string out
    receive Serial Command in but with a timeout
    repeat

    I attached the zip archive to my previous post. Do you guys see it?
  • heaterheater Posts: 3,370
    edited 2009-12-27 23:49
    Presumably RxStrTime is returning a value which is the address in memory where received string is to be found. If there is no string received in the specified time it returns a value of -1 (not the string "-1") which cannot ever be a valid address and is used to indicate the "no string available" situation. So just check if the returned value == -1.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-12-28 07:19
    Hi Flo,

    first of all compliment about your formatting of the spin-file well done

    I downloaded your code and have several hints about bugs

    maybe it is working with 6 longs but

    the absolute minimum for stacksize is 9 longs. Better use 50 longs to have some extra space if parameters or function calls are added
    So the crash of the program is caused by the call of COBINED with the too small stack of 6 longs.

      Comm.str(string("a",13))       {{-------leaving this line uncommented out crashes the microcontroller}} 
    
    




    VAR
      byte x[noparse][[/noparse]8]
    
      long BtnScanStack[noparse][[/noparse]50]  '  long BtnScanStack[noparse][[/noparse]6]
    
    




    the at-operator "@" is missing

      cogBtnScan := cognew(scanButtons,[b]@[/b]BtnScanStack)  'cogBtnScan := cognew(scanButtons,BtnScanStack)
    
    



    You don't have to re-invent the wheel again. The RxStr-method is already able to receive a string (=bytesequence of 1-15 bytes terminated by the delimiter character

    As ExtFDS is running in its own cog. Just send the string up to 15 characters (plus delimitercharacter) are stored in the receivebuffer of ExtFDS and as long as you
    don't send any more characters these characters stay ready to read out in the buffer. Your program can do other things for hours and days. If more than 16 bytes are received
    the oldest bytes get overwritten by the newest bytes

    From these comments you can see how important it is to post your COMPLETE code

    best regards

    Stefan
  • floflo Posts: 38
    edited 2009-12-30 05:14
    Could someone post some example code of their serial out, if possible. I've been running in circles.

    
    if (Comm.RxStrTime(1,@x) <> -1)
            AppendChar(@x, 13)
            Comm.str(@x)
    
    
    



    Is this the correct way to check for -1? When I do this, it just sends empty strings to my computer.
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-12-30 06:31
    @heater: RxStrTime does NOT return a result value. So you caN'T check for -1

    flo,

    you are using RxStrTime to receive SINGLE bytes. RxStrTime is for receiving MULTIPLE bytes.
    To give you further advice please do me a favor and post how your COMPLETE data-exchange looks like.

    Especially how long is the longest command-string?

    How do you send the command-string? I mean this: let's assume your commandstring is "START"
    From the PC do you send the string "START"+CR at ONCE

    or do you send it as single characters?

    "S" then there is a pause of 3 seconds
    "T" then there is a pause of 0,1 seconds
    "A" then there is a pause of 5 seconds
    "R" then there is a pause of 1,2 seconds
    "T" then there is a pause of 40 seconds
    CR then there is a pause of 9 seconds (CR means the DELIMITER-character decimal value 13)

    If you send it at ONCE "START" CR
    you simply code a

      RxStrTime(1,@MyStr)
    
    



    If the boolean expression (MyStr[noparse][[/noparse]0] == 0) is true nothing was received
    otherwise you received the COMPLETE string

    YOU DON'T have to put together every char to a string. That's what RxStr and RxStrTime are doing already.

    If a string-receiving (=bytesequence) has started to come in,
    RxStrTime will receive all these characters at ONCE.
    So if MyByte[noparse][[/noparse]0] contains something NOT equal to zero it contains already the COMPLETE string, if the string is sended at ONCE

    So please post a DETAILED description of your data-exchance and archive and attach your COMPLETE project again

    best regards

    Stefan
Sign In or Register to comment.