Shop OBEX P1 Docs P2 Docs Learn Events
Using repeat loops with coginit/cognew and cogstop — Parallax Forums

Using repeat loops with coginit/cognew and cogstop

GUFFGUFF Posts: 8
edited 2015-01-12 12:41 in Propeller 1
I recently used a prop for a custom piece of test equipment. I am generating a custom dropout pulse used to control another piece of test equipment. Layout is fairly simple: pulse start/stop switch and pulse selector switch (switch between two choices). I can get the pulse generator to work and control things but would like to improve the code. Currently when one pulse runs and I switch to the next i have to wait until the former pulse finishes before the new one begins. So as you can see I am only using one cog to control and call methods. This is not a deal killer but something I would like to tweak. I want to set it up so I get instant change from one pulse to the next.

My first idea was to start and stop different cogs for each pulse. I was doing this inside repeat loops that look at both switches current state. When I do it this way I cannot get any pulse output. Maybe I am getting stack space problems? I did a sanity check and decoupled the start cog commands from the repeat loop(s) and it works fine with code similar to what can be found in PE kit. Attached is a test version of the code where i changed pulse output to blink LEDs instead.

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2015-01-10 15:43
    Your program is hard to understand. You have several variables declared as 128 byte arrays, yet you're using only the first byte of them (accessing them without a subscript). I don't see why you need so many cogs. Maybe start with a very simple description of exactly what you're trying to do, maybe with a picture or clear description of the timing and timing dependencies (what triggers what and when).

    When starting up a separate cog, remember that the COGINIT or COGNEW takes time to start up the cog. COGINIT and COGNEW return (and the initiating cog continues execution) almost immediately (as soon as an idle cog is found). The Spin interpreter is copied into the new cog and initialized in parallel with the execution of the initiating cog. This takes a bit over 100us to do.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-01-10 16:08
    I'm with Mike: Your code is hard to understand because it's far more complicated than it needs to be.

    Consider this -- it does the same thing, is easy to call, and only uses one cog. (Update) The pulse loop is broken into units of 1/64s so that early exit is possible
    con
    
      { P U L S E   G E N E R A T O R }
    
    
    var
    
      long  pulsecog
      long  pulsestack[32]
      
    
    pri start_pulses(status, mode, pin)
    
      if (pulsecog)
        cogstop(pulsecog-1)
    
      pulsecog := cognew(pulse_gen(status, mode, pin), @pulsestack) + 1
    
      return pulsecog
      
    
    pri pulse_gen(status, mode, pin) | t
    
      dira[pin] := 1                                                 ' make pin output 
    
      t := cnt
      repeat
        repeat while (ina[status] == 0)                              ' if status pin low
          outa[pin] := 0                                             ' output off
          t := cnt                                                   ' re-sync delay timer
    
        !outa[pin]                                                   ' toggle pin
    
        if (ina[mode] == 0)                                          ' if mode low
          repeat 64 { 1s }
            if ((ina[status] == 0) or (ina[mode == 1]))              ' status or mode change?
              quit                                                   '  yes, abort loop
            else
              waitcnt(t += (clkfreq >> 6))
              
        else 
          repeat 16 { 1/4s }
            if ((ina[status] == 0) or (ina[mode == 0]))  
              quit                                       
            else
              waitcnt(t += (clkfreq >> 6))
    
  • David BetzDavid Betz Posts: 14,516
    edited 2015-01-10 16:37
    One reason that your code isn't work is that your main program running in COG 0 sets P1 to an output but the programs running on COG 3 do not do that. You have to set the DIRA register in the same COG that is manipulating the pin.

    Also, you still won't get "instant" response to a change in the pulse generator because it takes a significant amount of time to load code into a COG.
  • Mark_TMark_T Posts: 1,981
    edited 2015-01-11 11:27
    GUFF wrote: »
    My first idea was to start and stop different cogs for each pulse.

    You normally use some hub variables to control a cog - set a start-flag to set it going, cancel it to stop, use a separate variable to
    report status back from the cog in question. Locks can be used as a semaphore directly for each cog too.

    Killing and restarting a cog costs about 8200 cycles, and killing a cog risks leaving things in a broken state (there is no
    cleanup done, the cog stops and all its special registers reset to zero.)
  • GUFFGUFF Posts: 8
    edited 2015-01-12 12:41
    Thanks for the replies everyone, I appreciate the feedback.

    Agreed, I am making it more complicated than it needs to be. But then again, what you do expect from a hardware guy (EMC Engineer)? Attached is a visual for what I am doing.

    I think you are right, no need for multiple cogs.

    There are two pulses I need to output. Both would be considered "slow" due to the timing parameters:

    Pulse 1

    10% duty cycle @.2Hz (500ms on/4.5soff)

    Pulse 2

    24 segments ranging from 50ms to 350ms as follows:

    Segment/High/Low/Time (s)
    0/Low/0.050
    1/High/0.050
    2/Low/0.350
    3/High/0.250
    4/Low/0.050
    5/High/0.050
    6/Low/0.250
    7/High/0.100
    8/Low/0.050
    9/High/0.350
    10/Low/0.050
    11/High/0.050
    12/Low/0.150
    13/High/0.350
    14/Low/0.050
    15/High/0.050
    16/Low/0.350
    17/High/0.150
    18/Low/0.050
    19/High/0.050
    20/Low/0.250
    21/High/0.050
    22/Low/0.050
    23/High/0.050

    @JonnyMac

    I used the idea you presented of breaking up the delays into smaller chunks and then looking for switch changes. That seemed to do the trick nicely. I updated the code and verified on the scope the pulses still work and the pulses change quickly when switches are toggled. Code Attached.

    I know I can optimize the code more and plan to as I continue gaining more prop experience. Thanks for helping me learn a thing or two.
Sign In or Register to comment.