Shop OBEX P1 Docs P2 Docs Learn Events
COGNEW is not returning — Parallax Forums

COGNEW is not returning

LawsonLawson Posts: 870
edited 2007-07-23 16:13 in Propeller 1
Ok, I'm building servo controller intended to replace solenoids and limit switches. It uses a modified version of the ServoTracker circuit and code as found here http://forums.parallax.com/showthread.php?p=582447

I've got the core aspects of my code working. Now I'm trying to speed it up by taking advantage of the Propeller's eight cores. My current system has an extra serial port for application communications, in addition to the default programming port. It's built on a Proto board. It's currently setup to share the serial port and servos amongst several "controllers" that each grab serial packets, move the commanded servo, and spit back status code packets.

The problem I'm having is that when I try to start multiple instances of my "controller" code, the COGNEW that started the first "controller" never returns! I didn't detect this earlier because otherwise the code works perfectly, and I hadn't been ready for parallel "controllers" yet.

P.S. this particular protoboard did get washed in tap water. (yea, not too smart) It didn't work for a day, but worked just fine once it fully dried out. Also, the full Blinker tutorial code ran fine on it after the dunking.

P.P.S. the .zip archive attached is a simpler version of my code that reproduces the same error.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Lunch cures all problems! have you had lunch?

Post Edited (Lawson) : 7/20/2007 8:33:49 PM GMT

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2007-07-19 18:11
    I think the main problem you're running into is that each instance of Servo requires an initialized instance of FullDuplexSerial and you're only initializing the 0th instance. When you use Servo[noparse][[/noparse] 1 ], the FullDuplexSerial instance associated with that hangs up.
    You either need to redo Servo_Diagnostics to share an instance of FullDuplexSerial or you need to call Servo[noparse][[/noparse] 1 ].Init.
  • LawsonLawson Posts: 870
    edited 2007-07-19 18:36
    If that was the case then i'd get a "one cog started " message. All i'm seeing on PropTerminal is "welcome to my GLORIOUS code" and ".int went all right "

    Also, the "servo_diagnostics_starter.spin" uses a modified FullDuplexSerial.spin that has had all it's variables moved into the beginning of the DAT block. Hence, I only need to initialise it once. (i've also added lock statements to expose a shared lock to prevent contention)

    I've attached my modified serial driver "DatDuplexSerial.spin". Once I clean it up a bit I plan to submit it to the object exchange.

    by the way, is there a "better" way to share a serial driver? One way I've just thought of is to move the "controller" code and serial driver down to the startup object and manually start several versions of just the "controller" code in separate cogs. (still need to use locks for serial port access though)

    Marty
  • LawsonLawson Posts: 870
    edited 2007-07-20 20:00
    I think I've found a bug in the COGNEW statement. I've attached a simple program to demonstrate it. The program uses PropTerminal on pins 31 and 30 for feedback, and toggles an LED on pin 1 to show that the second cog is running. The main object of my example uses COGNEW to start code from a child object in another cog. PropTerminal *should* show all three text messages after this is run and the LED should be blinking. What PropTerminal actually shows, when I run it on my proto board, is only the two text messages prior to the COGNEW statement and the LED blinks.



    also, funny things happen if COGNEW is used to start a method in the current object twice in two different cogs.

    COGNEW(my_parallel_code, @stack1)
    COGNEW(my_parallel_code, @stack2)
    


    this *should* work, but the two cogs appear to be stepping on each other's toes. COGNEW does return as expected in this case though.



    None, of this solves my core problem though. I'd like to have a single cog running a serial port driver, which is then shared among three or more command processing cogs. The execution of commands from the serial port can take several seconds so it is desirable to have several commands executing at once.

    Thank you for your time, this one is really stumping me,
    Marty

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Lunch cures all problems! have you had lunch?
  • Mike GreenMike Green Posts: 23,101
    edited 2007-07-20 20:50
    Ah!
    The first parameter to a COGNEW (or COGINIT), must be a method in the same object as the COGNEW. You can't pass a call to a method in another object. The best way to handle this is to move the COGNEW to the object itself along with the stack (which is replicated for each instance as well). You'd have:
    con
      _clkmode = xtal1 + pll16x     'set to ext low speed crystal
      _xinfreq = 5_000_000          'Frequency on XIN pin is 5 MHz
    
    obj
      D : "pc_interface.spin"       'debug terminal
      my_obj : "my_object.spin"     'pin toggling object
    
    pub main
      D.start(31,30)                'start up my debug interface
      D.str(string("starting a new cog to run my_object.  "))
      my_obj.start(1)
      D.str(string("This statement will only appear if COGNEW returned.  "))
    
    

    and:
    var long cog, stack[noparse][[/noparse]20]
    
    pub start(pin)
      stop
      cog := cognew(togle(pin),@stack) + 1
    
    pub stop
      if cog > 0
        cogstop(cog-1)
    
    pri togle(pin)
      'show signs of life by toggling a pin
      dira[noparse][[/noparse]pin]~~
      repeat
        !outa[noparse][[/noparse]pin]
        waitcnt(clkfreq/10 + cnt)
    
    
  • deSilvadeSilva Posts: 2,967
    edited 2007-07-21 11:02
    Mike Green said...
    Ah!
    The first parameter to a COGNEW (or COGINIT), must be a method in the same object as the COGNEW.

    Mike, why is that so and where is it documented? This is against all my previous understanding of how things work. I see hardly any reason for it, and - also- it is syntactically accepted.
  • Mike GreenMike Green Posts: 23,101
    edited 2007-07-21 14:47
    Why is it so? ... Because a new Spin interpreter has to be launched and a call to a method in another object is more complex than a call to a method in the current object and I don't think there are provisions for the extra information in the parameter block passed to the new interpreter instance.

    Where is it documented? ... I don't know ... some forum message somewhere.

    It is a compiler bug that it's accepted, but not implemented properly. Theoretically, the compiler could produce a short stub that consists of a parameterless unnamed local private method that just does the cross-object call and then do the COGNEW/COGINIT on that, but the compiler doesn't do that and that's a complicated fix that won't likely be done any time soon.

    I did add a comment about this to the Propeller Tricks & Traps sticky thread.

    Post Edited (Mike Green) : 7/21/2007 2:56:26 PM GMT
  • mirrormirror Posts: 322
    edited 2007-07-22 22:49
    Lawson said...

    by the way, is there a "better" way to share a serial driver? One way I've just thought of is to move the "controller" code and serial driver down to the startup object and manually start several versions of just the "controller" code in separate cogs. (still need to use locks for serial port access though)
    Have a look at SerialMirror. It does what this object does (except for the locks which I haven't found necessary) but also allows for variable buffer sizes. The link is here: http://forums.parallax.com/showthread.php?p=649541
  • LawsonLawson Posts: 870
    edited 2007-07-23 16:13
    Mirror: AH! I knew someone had made a serial driver that could be included multiple times but only operate in a single context! Have you submitted this object to the Object Exchange? In my case the Locks are required. Without the locks I'd have two or more cogs pulling bytes off of the serial buffer at the same time. This would be guaranteed to mangle packets and cause all kinds of trouble. And without separate locks on the transmit and receive buffers cogs waiting for a new packet would block finished cogs from sending a response packet.

    Currently i'm using a single instance of FullDuplexSerial with the controller code in the parent object. I'm then loading this controller code into multiple cogs using COGNEW. This works great with two controller cogs, but gets corrupted when I try for three cogs. I'll track down this bug today. If this doesn't work I'll switch back to using SerialMirror, or DatDuplexSerial.

    Edit: my second bug cleared up when I boosted my stack space. I'd previously been allocating 30 longs for stack. Now with 100 longs for stack it works fine. I'll have to try the stack size measuring code to see just how big the stack gets with this code.


    Marty

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Lunch cures all problems! have you had lunch?

    Post Edited (Lawson) : 7/23/2007 5:32:04 PM GMT
Sign In or Register to comment.