Shop OBEX P1 Docs P2 Docs Learn Events
Error with FullDuplexSerial.Spin object — Parallax Forums

Error with FullDuplexSerial.Spin object

SamMishalSamMishal Posts: 468
edited 2009-07-15 09:01 in Propeller 1
HELP freaked.gif

I think I have found a problem with the FullDuplexSerial.Spin library object.

Look at this code:
Con
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000
OBJ
  Debug[noparse][[/noparse]2] : "FullDuplexSerial"
  
PUB Main | x
  Debug[noparse][[/noparse]0].Start(31,30,0,115200)               ' Start the Debug Terminal Cog
  'Debug[noparse][[/noparse]1].Start(31,30,0,115200)               ' Start the second Debug Terminal Cog
  waitcnt(clkfreq*3+cnt)
  repeat x from 1 to 3
     Debug[noparse][[/noparse]0].Dec(x)
  waitcnt(clkfreq+cnt)
  repeat x from 4 to 8
     Debug[noparse][[/noparse]1].Dec(x)
    

If you run this code you will get 123 on the PST......HOWEVER.....if you uncomment the line Debug[noparse][[/noparse]1].Start(....)
the program stops working and may even spew out garbage some times.


The program is just to demo the problem. The real problem arises if multiple objects need to have access to
FullDuplexSerial and declare their own instances then the same problem occurs.....the multiple instances seem
to interfere with each other.......I am thinking that the various cogs are driving the TX and RX pins continously
and therefore are stopping the other cogs from doing their own transmissions.......I am not very up to par with
PASM and maybe someone with more knowledge than mine can help...e.g. Chip Gracey, Jeff Martin..... PLEASE.

But even if we manage to solve the problem......the sample programs below illustrate another problem.

The program does not work as given due to the problem mentioned above. BUT....Also please read on for ANOTHER problem....

{
    Top_Object.Spin
}
Con
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000
 
OBJ
  Debug : "FullDuplexSerial"
  ObjB  : "B_Object"

 
PUB Main|NumSongs,i,x
  Debug.Start(31,30,0,115200)               ' Start the Debug Terminal Cog
                                            ' if you comment this out then the
                                            ' ObjB.Print works
  ObjB.Init                                 ' Start Object B
  waitcnt(clkfreq*2+cnt)
  Debug.Tx(Debug#Cls)                       ' Clear SerialTerminal screen
  Debug.Dec(12)                       
  Debug.Tx(13)
  ObjB.Print(34)

{
   B_Object.Spin
}
OBJ
  Debug : "FullDuplexSerial"

PUB Init
  Debug.Start(31,30,0,115200)               ' Start the Debug Terminal Cog
                                            ' if you comment this line out then the
                                            ' Top object Debug works
Pub Print(val)
  Debug.Dec(val)
  Debug.Tx(13)
 

The other problem is in the scenario of the top_object program, there would be two cogs (even if they did not interfer with each other) running
the serial I/O. This is wasteful.

So how would one provide Serial I/O to multiple objects without having multiple cogs (which actually does not work any way
as shown above)????????????

I hope someone whith DEEP knowledge of all this stuff can help


Samuel


Post Edited (SamMishal) : 7/9/2009 8:12:39 PM GMT

Comments

  • rokickirokicki Posts: 1,000
    edited 2009-07-09 20:03
    This is straightforward. You need a singleton version of FullDuplexSerial, and if you want to drive them
    from distinct cogs, you also need to add locking.

    This is a well-known and well-understood problem.
  • Mike GreenMike Green Posts: 23,101
    edited 2009-07-09 20:07
    You can't use FullDuplexSerial this way. Each Serial.start call starts up a cog to do the actual I/O and, since you've asked them to both use the same I/O pins, they interfere with each other. You have to very specifically design an object to be called from several objects. Look at the "SerialMirror" object in the Object Exchange for a serial driver designed to be called from multiple objects.

    You will have to add your own locks to "Serial Mirror" if you plan to call it from several different cogs. It's not hard to do.

    There's not very much call for the sort of serial driver you're asking for. Most of the time FullDuplexSerial or Simple_Serial will do the trick. That's why no one has bothered to contribute one (other than Mirror and that one doesn't have locking).

    Post Edited (Mike Green) : 7/9/2009 8:19:36 PM GMT
  • SamMishalSamMishal Posts: 468
    edited 2009-07-09 20:08
    rokicki said...
    This is a well-known and well-understood problem.
    OK.....so has anyone solved it???? is there a singleton version of the FullDuplexSerial.Spin......that also implements
    locking and that also gets around the waste of having multiple cogs running it but still enabling multiple objects to have
    access to serial I/O...??


    I would like to see Chip Gracey's and·Jeff Martin's input on this.....PLEASE....


    Sam
    ·
  • SamMishalSamMishal Posts: 468
    edited 2009-07-09 20:13
    Mike Green said...
    You can't use FullDuplexSerial this way. Each Serial.start call starts up a cog to do the actual I/O and, since you've asked them to both use the same I/O pins, they interfere with each other. You have to very specifically design an object to be called from several objects. Look at the "SerialMirror" object in the Object Exchange for a serial driver designed to be called from multiple objects.
    Thanks Mike......I suspected thusly......

    do you have a link for the SerialMirro object....I am trying to find it.....

    Regards

    Samuel
    ·
  • edited 2009-07-09 20:28
    SamMishal said: that also implements locking and that also gets around the waste of having multiple cogs running it but still enabling multiple objects to have access to serial I/O...??

    There is an object on obex.parallax.com that takes a step toward this functionality by using a DAT block for variables instead of a VAR block. It's called SerialMirror:

    http://obex.parallax.com/objects/189/

    Also on obex, you can find MultiCogSerialDebug, which extends the DAT block approach and applies locks.

    http://obex.parallax.com/objects/232/

    This example puts the onus on the parent object for using locks. An alternate approach might be to build the locks into the object's methods. I started experimenting with methods that shunt strings into holding pens so that the parent object doesn't have to worry about getting locked out of its own task list, but I haven't worked the kinks out yet.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Andy Lindsay

    Education Department
    Parallax, Inc.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-07-09 20:29
    As you already mentioned it simply makes no sense to have two different FullDuplex objects running for a single pair of serial I/O lines! So, from my point of view this is an error in the usage and not in the object ;o)

    It should be possible to modify this object so that it matches with your needs. I don't know the object in detail, but I have the following ideas:
    1. If the TX/RX buffer is in the var section, then shift it to the DAT section
    2. Have a variable in the DAT section, which shows whether the PASM has already been started
    3. Modify the start function to use the right buffers and only start a new COG if not yet started
    4. RX and TX functions should be synchronized with locks if you plan to use the object in parallel from different COGs

    Then you can use the object in every other object and it does not waste HUB-RAM, because the same object is never copied in HUB-RAM. Only the VAR section is duplicated per instance of the object.

    Hope that helps.


    PS: Ups ... needed far to long for my reply ;o)
  • SamMishalSamMishal Posts: 468
    edited 2009-07-09 20:31
    THANKS Guys.....yeah.gif

    I found the SerialMirror.Spin and IT WORKS.....GREAT.....it is exactly what I needed....





    THANKS again



    Samuel




    Post Edited (SamMishal) : 7/9/2009 8:36:28 PM GMT
  • SamMishalSamMishal Posts: 468
    edited 2009-07-09 20:45
    Hi Guys,



    I looked more closely at the SerialMirror object and it works great as far as allowing multiple

    instances from multiple objects to all work together on the same Tx and Rx pins.....BUT.....I think it still

    uses multiple cogs if instantiated multiple times.....am I wrong.....if not then is there one that

    does not utilize multiple cogs???



    Sam
  • SamMishalSamMishal Posts: 468
    edited 2009-07-09 21:13
    MagIO2 said...

    It should be possible to modify this object so that it matches with your needs. I don't know the object in detail, but I have the following ideas:
    1. If the TX/RX buffer is in the var section, then shift it to the DAT section
    2. Have a variable in the DAT section, which shows whether the PASM has already been started
    3. Modify the start function to use the right buffers and only start a new COG if not yet started
    4. RX and TX functions should be synchronized with locks if you plan to use the object in parallel from different COGs

    I agree....I was thinking the same thing.....the only point I did not think about was number 1......

    WHY is this step necessary....it is also what MirrorSpin does but I do not understand why it is
    a necessary thing to do???


    Samuel
    ·
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-07-09 21:29
    If you only run one COG it will only use one set of buffers unless you modify the PASM adding a command that switches the buffer to write to/read from. Having the buffer in the VAR section means that each instance of the object has it's own buffers, but the COG will only use the buffers of the first instance.

    So, the read/write functions would simply use the wrong buffers except the ones of the first object.
  • KyeKye Posts: 2,200
    edited 2009-07-09 21:33
    Um,

    Each object gets its won seperate variables. So, the two versions of the fullDuplex serial have completely different buffers.

    Its a problem with spin in general, you have to use the serial mirror hack to get arround it with sperate DAT sections.

    Maybe support for parent and child objects sharing the sample driver will be added one day. Maybe not.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • edited 2009-07-09 21:39
    Only make one Start method call regardless of how many copies of the object (SerialMirror) you use.

    Multiple objects can declare SerialMirror, but their method calls to SerialMirror's other methods (DEC,·STR, etc)·will result in data to/from the same tx and rx buffers because there is only one copy of the code and DAT·block for multiple copies of the object.·

    After the one start method call, calls to DEC, STR, etc will work from any object/cog so long as they are not executed close enough together that a data collision occurs. This is why I started experimenting with the lock and multiple buffer scheme.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Andy Lindsay

    Education Department
    Parallax, Inc.

    Post Edited (Andy Lindsay (Parallax)) : 7/9/2009 9:48:56 PM GMT
  • SamMishalSamMishal Posts: 468
    edited 2009-07-09 22:45
    Andy Lindsay (Parallax) said...
    Only make one Start method call regardless of how many copies of the object (SerialMirror) you use.

    Multiple objects can declare SerialMirror, but their method calls to SerialMirror's other methods (DEC,·STR, etc)·will result in data to/from the same tx and rx buffers because there is only one copy of the code and DAT·block for multiple copies of the object.·

    After the one start method call, calls to DEC, STR, etc will work from any object/cog so long as they are not executed close enough together that a data collision occurs. This is why I started experimenting with the lock and multiple buffer scheme.
    So then if I declare multiple instances in various objects then only the top level needs to call the start method??
    This will definitely use only one cog.....and since the DAT section is in hub RAM then the same buffer will be used....
    ·
    Ahaaa.....now I get it.....I will try this soon......
    ·
    The lock issue would be needed if multiple objects are likely to send/receive simultaneously.....but in my application
    I am not doing that .....so I will look into the locking stuff later.....Unless Andy Lindsay comes out with a new version
    that does all that for us.....Please.....
    ·
    But I have learnt a lot from you guys.........THANKS
    ·
    ·
    Samuel
  • SamMishalSamMishal Posts: 468
    edited 2009-07-09 23:06
    Samuel said...
    Ahaaa.....now I get it.....I will try this soon......
    ·
    Hurray......all problems are all solved......no multiple cogs and all WORKS PERFECTLY......
    only locking is required when I may need it ......but not now......SO THANK YOU GUYS....

    Solution as well as understanding and learning new stuff......what a GREAT LOT you guys are
    and of course Parallax and the Propeller (and SPIN)·are just the best.....


    Samuel

    ·
  • edited 2009-07-09 23:09
    Yes, that's the way it should work.· One call to the Start method, and then the calls to any methods in any of the other Serial Mirror object instances should work.· (There is always a chance that data collisions will interleave strings if two cogs make almost simultaneous STR, DEC, etc, method calls without using locks.)·
    ·
    Side notes:
    ·
    The SerialMirror object's start method is actually designed to stop any previously started instances before launching a cog, so you "could" call the start method more than once, and there would still only be one instance running.· This only prevents the same instance of a given object from launching two cogs; you could still launch more than one cog by calling a start in a different instance of the SerialMirror object.· That is why we only want to make one call to a SerialMirror object's Start method.· Then, all the other instances of the object will only communicate through one cog that's running the serial ASM code.

    I have a Parallax Serial Terminal debugging application that works with SerialMirror posted in the Propeller Education Kit Labs, Tools & Apps thread, and the next step is to add locks to prevent data collisions.

    The existing FullDuplexSerial object can be used with multiple programming tools connected to various pairs of I/O pins so that you could have several simultaneous conversations with one or more PCs or other serial devices.

    The Propeller Library also has SimpleSerial, which might be another option for multi-cog debugging. This object uses whatever cog calls its methods to transmit the bytes at up to 19.2 kbps.

    ·

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Andy Lindsay

    Education Department
    Parallax, Inc.

    Post Edited (Andy Lindsay (Parallax)) : 7/9/2009 11:25:52 PM GMT
  • electricsmithelectricsmith Posts: 20
    edited 2009-07-14 19:57
    Andy Lindsay (Parallax) said...

    The existing FullDuplexSerial object can be used with multiple programming tools connected to various pairs of I/O pins so that you could have several simultaneous conversations with one or more PCs or other serial devices.
    ·

    Can anyone point me to some examples of several RS232 devices connected to different tx/rx pins on the propeller and how these are coded?· I have several devices I want to communicate with simulataneously over different serial ports.·
  • SamMishalSamMishal Posts: 468
    edited 2009-07-14 20:22
    An example would be to use the EB500 and a serial·LCD ......both these need Asynchronous serial



    So you would have two objects that use the object FullDuplexSerial and initialize it to the pins.

    So if EB500 is on pins P20 and P21 and the LCD is on P10 and P11 (for Tx and Rx) then you would have
    two objects say one is called EB500.Spin and the other called LCD.Spin each of these objects would have its
    own OBJ section like this

    ·· Obj
    ······· Com : "FullDuplexSerial"



    And also it would have methods that will enable the Toplevel object to initialize them say

    ·· Pub Init(TxPin, RxPin,BaudRate)
    ······· Com.Start(RxPin, TxPin,0,BaudRate)
    ······· 'do other initialization stuff

    · Pub DoSomething(someParam)
    ····· Com.Tx(somecalue)
    ····· 'etc.



    So then the top level object would instantiate the LCD.Spin and EB500.Spin objects in its Obj section
    and then would call the Init method and then can use the other methods of the object

    Con
    ···· _CLKMODE = XTAL1+PLL16X
    ···· _XINFREQ· = 5_000_000

    Obj
    ··· LCD··· : "LCD"
    ··· Eb500: "Eb500"

    Pub Main
    ···· LCD.Init(10,11,9600)
    ···· EB500.Init(20,21,9600)
    ···· 'do some more stuff
    ···· LCD.DoSomething(somevalue)
    ···· EB500.DoSomething(someothervalue)



    etc. etc.



    ·······

    Post Edited (SamMishal) : 7/14/2009 8:38:07 PM GMT
  • jazzedjazzed Posts: 11,803
    edited 2009-07-14 20:28
    Andy, Why don't you guys just release a SingletonFullDuplexSerial.spin that works the way most of us use it?
    As Tom said, this usage is widely known and common. I've never had a good reason want to use SerialMirror (ya, I've seen it).
    A similar approach can be used with TV, etc... but it's a little harder to describe the "fix."

    For those who don't know, all you have to do is make the change below in FullDuplexSerial.spin to be able to use it from any object (but not with multiple instances on different pins as Andy pointed out). Of course every time you update PropTool, you have to readjust :< vomit.

    VAR
    
      long  cog                     'cog flag/id
    {
      long  rx_head                 '9 contiguous longs
      long  rx_tail
      long  tx_head
      long  tx_tail
      long  rx_pin
      long  tx_pin
      long  rxtx_mode
      long  bit_ticks
      long  buffer_ptr
                         
      byte  rx_buffer[noparse][[/noparse]16]           'transmit and receive buffers
      byte  tx_buffer[noparse][[/noparse]16]  
    }
    
    ' add this DAT
    
    DAT
    
      rx_head      long 0            '9 contiguous longs
      rx_tail      long 0
      tx_head      long 0
      tx_tail      long 0
      rx_pin       long 0
      tx_pin       long 0
      rxtx_mode    long 0
      bit_ticks    long 0
      buffer_ptr   long 0
                         
      rx_buffer    byte 0 [noparse][[/noparse]16]           'transmit and receive buffers
      tx_buffer    byte 0 [noparse][[/noparse]16]  
    
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • TimmooreTimmoore Posts: 1,031
    edited 2009-07-15 00:21
    you could try the 4 port serial port object. It is a singleton that supprots up to 4 ports. So you get the singleton behavour and multiple ports. You can include the object in multiple files in your project and they all share the same ports. I have a convention that port 0 is the debug port so any object can report debug info while the other ports are free for other devices to use. It doesn't attempt to solve the secondary probellm of the outputs from different cogs getting mixed up on the debug port, i.e. if 2 cogs ask to output a string to the debug port the strings will be mixed up when sent on the port.
  • SamMishalSamMishal Posts: 468
    edited 2009-07-15 00:37
    Timmoore said...
    ·the 4 port serial port object.
    What is it called? do you have a link? Also can you not assign the other ports if you do not need them?

    Sam
    ·
  • TimmooreTimmoore Posts: 1,031
    edited 2009-07-15 00:55
    pcfullportserial4fc, its by me, so look for the objects I posted in obex. You can specify between 1 and 4 ports, if you dont assign the pins the port doesn't do anything.
  • SamMishalSamMishal Posts: 468
    edited 2009-07-15 02:01
    Timmoore said...
    pcfullportserial4fc, its by me, so look for the objects I posted in obex. You can specify between 1 and 4 ports, if you dont assign the pins the port doesn't do anything.
    Hi Tim,

    I found pcfullDuplexserial4fc.Spin ....... is it the same?

    Regards

    Sam
    ·
  • TimmooreTimmoore Posts: 1,031
    edited 2009-07-15 03:42
    yes, sorry got the name wrong.
  • SamMishalSamMishal Posts: 468
    edited 2009-07-15 09:01
    Hi Tim,



    I used it and it is VERY Good.............it is definitely another tool I can

    and WILL use.....thanks for making it...............



    Regards



    Samuel
Sign In or Register to comment.