Shop OBEX P1 Docs P2 Docs Learn Events
Starting, Stopping, updating PASM in COGs other than the original caller? — Parallax Forums

Starting, Stopping, updating PASM in COGs other than the original caller?

T ChapT Chap Posts: 4,223
edited 2013-12-21 19:16 in Propeller 1
PUB Start(StartPin, NumEnc, NumDelta, PosAddr, direction): Pass    ' rotary encoder obj
  Pin := StartPin                                                                                     
  TotEnc := NumEnc                                                                                    
  TotDelta := NumDelta
  Pos := PosAddr
  Stop
  longfill(Pos, 0, TotEnc+TotDelta)
  SetDir(direction)
  Pass := (Cog := cognew(@Update, Pos) + 1) > 0
  'SetDir(direction)   ' or here?  can instruction be changed after cog is started


PUB SetDir(i)   'alter an instruction in DAT  from add to sub  'adding this to the Rotary obj
  if i == 1      'Subtract
    AMask[-8] |=  |< 26       ' sub    set bit 26 high for subtract =  reverse
  elseif i == 0  'Add
    'bitwise NOT bit 26 of the instruction on line :IPos add 0, Diff    
    AMask[-8] &= !|< 26       ' add      

'AMask is in the DAT section of the Rotary obj


A few questions if someone can make this more clear.

1. Does SetDir belong above the Cognew or below?

2. Main(cog0) starts a COG(1) that starts another COG(2) shown above. I can't test this till tomorrow but am trying to get an understanding. If the object above in COG(2) was launched from COG(1), can the SPIN code in COG(1) call SetDir on the fly anytime to alter the PASM instruction from add to sub? Or would COG(2) require a stop, then a relaunch to select the instruction?

3. Can Main contain the object name for COG(2) also under OBJ, and then allow Main to call COG(2) SetDir. Or must Main call a method in COG(1) that calls a SetDir in COG(2). In other words, can any COG call a method in any other cog.

Comments

  • Mark_TMark_T Posts: 1,981
    edited 2013-12-20 18:08
    When a cog is initialized (cognew, coginit) the hardware inside the cog is triggered and it copies 2k bytes (496 longs) from
    hub memory into the cog RAM, zeroes the special registers (except PAR which is loaded from the parameter to cognew or
    coginit) and then starts executing PASM from cog address 0. If the cog is running spin code then the memory copied is
    the Spin interpreter.

    This loading of the cog is asynchronous, in other words the cog calling cognew or coginit will get control back immediately
    and run alongside the (re)started cog's loading.

    Cog RAM cannot be accessed from outside the cog, so any changes into the hub memory the cog was loaded from
    will have no effect on the cog after its copied it. Calling coginit will overwrite the whole of cog memory so all cog-local
    variable state is lost - you will need code in the cog to update itself, rather than trying to change it from outside.

    Also in Spin you can only call methods in the same cog, the only way to initiate code in another cog is
    via cognew or coginit. There is no meaning to calling on another (already running) cog anyway, it doesn't
    make any kind of sense. You can communicate with other cogs, but they have to cooperate with you.

    One last thing, cogs are pretty lightweight to startup, it takes about 100us with a system clock of
    80MHz (for the new cog, the one starting it doesn't lose time), so its quite feasible to spawn and kill them
    on demand (just be sure you never try to have more than 8 at one time).
  • T ChapT Chap Posts: 4,223
    edited 2013-12-20 18:31
    Thanks Mark. The question still remains if the code altering the PASM instruction bit 26 from add to sub should be ran before cognew or after. I am trying to understand if the address for the instruction to change is modified before loading the 2k into ram from hub, or after it is loaded.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-12-20 20:45
    T Chap wrote: »
    3. Can Main contain the object name for COG(2) also under OBJ, and then allow Main to call COG(2) SetDir. Or must Main call a method in COG(1) that calls a SetDir in COG(2). In other words, can any COG call a method in any other cog.

    SetDir is run in whichever cog calls it. Only code launched with cognew is assigned to a cog. The Spin code just sits in hub RAM to be used by any cog wanting to call it. Objects don't correspond to cogs.

    To answer your other questions we need to know where "AMask" is located and how it is accessed. Does the PASM code use a rdxxxx to access it or is it access from within cog RAM? If the latter, then you need to call "SetDir" before launching the cog.
  • T ChapT Chap Posts: 4,223
    edited 2013-12-20 20:52
    AMask is in the DAT section, where the PASM code is running in the Rotary Encoder object. SetDir is a new idea for the Object to alter the instruction so that add becomes sub so the encoder counts in reverse. The goal is to change the instruction on the fly with a call from Main to SetDir with a parameter of 0 or 1 to select forward or reverse.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-12-20 21:32
    T Chap wrote: »
    AMask is in the DAT section, where the PASM code is running in the Rotary Encoder object. SetDir is a new idea for the Object to alter the instruction so that add becomes sub so the encoder counts in reverse. The goal is to change the instruction on the fly with a call from Main to SetDir with a parameter of 0 or 1 to select forward or reverse.

    Okay, I just found what you're talking about.

    You'll need to call SetDirection before starting the cog. You'll have to stop and restart the cog if you want to change the direction after the initial start. It would be possible to add a couple of rdlongs to the loop in order to change them on the fly without needing to stop the cog.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-12-20 22:18
    I think I'm starting to better understand what you're trying to do.

    I hadn't noticed the "[-8]" after "AMask". I see now you want to modify the PASM code on the fly. You can only do this from within cog running the PASM.

    You could add a "direction" variable to be read from hub. You could then set the direction to "1" or "-1" and then the PASM cog would read the value and add whatever the value is to the encoder total.

    If you're not sure how to do this let me know. It would only take a few minutes to add.


    Edit: I was just looking at the code some more. It's not as simple as I had thought. I think you're idea of changing the plus to a minus is a good one, it's just going to be a bit tricky doing it on the fly.
  • kuronekokuroneko Posts: 3,623
    edited 2013-12-21 02:25
    SetDir needs to be called before cognew. You can get away with it after the call provided that the modified location is not located close to the start of the cog image (you have about 97% load time left after cognew returns). But why introduce another uncertainty? The patch itself will only affect new instances of the object. Already running instances are not affected.

    Ideally you also make sure that the cog is loaded completely before returning but that is less critical in your case I believe.
  • T ChapT Chap Posts: 4,223
    edited 2013-12-21 09:46
    Thanks kuroneko and Duane. I have gotten this to work as desired with reboot required to relaunch both a PID loop in a COG and the Encoder object loop in a COG so that they both can be flipped to move the motor in opposite directions as well as count the encoder pulses in reverse. This will save me many hours of time and energy down the drain over the years when installers put in the systems backwards from my drawings. Most people hardly even bother to read install warnings.
      Pin := StartPin                                                                                     
      TotEnc := NumEnc                                                                                    
      TotDelta := NumDelta
      Pos := PosAddr
      Stop
      'SetDir(direction)
      longfill(Pos, 0, TotEnc+TotDelta)
      Pass := (Cog := cognew(@Update, Pos) + 1) > 0
      waitcnt(4600 + cnt)
      SetDir(direction)
    

    I tested out your note about how the cog is loaded into memory after the cognew and found that up to a delay of 4600+cnt the code SetDir will work consistently. However, why bother with trying that, I just wanted to see how things worked. I still don't understand how part of the code is moving on towards the loading of the COG with the 2k from hub, while at the same time some part of the code is running the SetDir simultaneously with the COG memory being loaded, so that the SPIN is altering the DAT section at the same time. So, what COG is actually running the code to call up SetDir post cognew if the COG for the Rotary Object is loading itself? I am thinking this is as Duane stated, the cog that holds the SPIN that is doing the call for the new object(cognew) is actually what is running the SetDir. This is why I was asking about the cogs starting and stopping and altering methods within a cog. Even after years of years of this, some of this still is not clear. The beauty of it is I suppose, that I don't really need to know since it just always does what I want reliably even without a deep understanding of the process.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-12-21 10:11
    T Chap wrote: »
    So, what COG is actually running the code to call up SetDir post cognew if the COG for the Rotary Object is loading itself?

    I would also like to know this.

    At first I wondered if the new cog got loaded with some code to transfer the data into itself but I don't see how it would fit with the code being load. Maybe the Spin interpreter running in the cog which called cognew does some multitasking and both load the new cog while continuing running the rest of the code but then this also doesn't make sense since one cog can't access another. There must be some sort of hub "processor" which takes care of the round robin access to the cogs and maybe this same "processor" loads cogs?
  • T ChapT Chap Posts: 4,223
    edited 2013-12-21 10:17
    I guess it will always be a mystery. Magic sauce stuff.
  • T ChapT Chap Posts: 4,223
    edited 2013-12-21 14:07
    This is first. I had added some extra code to several objects that were getting launched to reflect the changes discussed above, and things started getting weird. I thought it was the typical stack space but it wasn't. It took about 3 hours today to figure out that the extra code was just long enough to cause the cogs a slight bit longer to load( I am guessing at this), since the solution was to put a waitcnt 20_000_000 + cnt right after the coginit that was launching the cogs giving trouble. The delay solved it. kuroneko mentioned this earlier
    Ideally you also make sure that the cog is loaded completely before returning but that is less critical in your case I believe

    I have never given any thought to waiting on a cog to load.
  • kuronekokuroneko Posts: 3,623
    edited 2013-12-21 15:12
    FWIW, loading a cog is a h/w thing. Once the coginit (hub) insn is executed some logic does a background transfer to deal with it. IOW, it just takes the usual 8..23 cycles to initiate the transfer then you can keep doing your thing(s).
  • Mark_TMark_T Posts: 1,981
    edited 2013-12-21 19:16
    T Chap wrote: »
    I have never given any thought to waiting on a cog to load.

    I always have a synchronisation mechanism to talk to a cog, so that outside code automatically waits for it to set its ready flag
    (or whatever scheme I'm using). You can synchronise with a lock, or a hub variable (the latter involves busy-waiting), or if you
    have more than one PASM cog you can synchronize them to the precise clock cycle by passing a value for both to WAITCNT on.

    You can also synchronise with a I/O pin.

    One thing that is often useful is have to cog load some of its configuration variables from hub ram each time
    round its main loop, so that it can be controlled from other cogs - basically the cog is polling for its configuration
    rather than just setting it up at start up. This would be a good way to control a PWM cog for instance since
    the cog decides when its ready to poll.
Sign In or Register to comment.