Shop OBEX P1 Docs P2 Docs Learn Events
Parallel cogs and controlling the same output. — Parallax Forums

Parallel cogs and controlling the same output.

WolfbrotherWolfbrother Posts: 129
edited 2011-01-19 14:34 in Propeller 1
I created a simple program to read a switch and either turn on or off the output to a relay (LED) on prop demo board. When you turn the LED on,hold it on for two seconds, to simulate that the relay will be on for about 30 seconds after you press the go button. But I want to always scan for the stop switch, so based on the lab example I started my first cog and that's called switchcaller, it launches LEDonoff just fine, but I can't seem to interrupt the 2 seconds of waitcnt in the cog running LEDonoff. The method lab relaunches the second cog and that stops the program as near as I can tell, but why can't you just make a new call from the main cog and force a stop? Is there a better method?

Thanks,

Dave

LEDonoff.spinSwitchcontroller.spin

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-01-15 20:31
    Your methods Hardoff and LEDOff can never get called. Also, where's the source for LEDonoff? Finally, be aware that every cog has its own dira and outa registers. Writes to an output pin in various cogs are ORed together. So if a pin is set in one cog, it's impossible to reset it from another.

    -Phil
  • WolfbrotherWolfbrother Posts: 129
    edited 2011-01-16 09:17
    Hi,

    I see my mistake on not getting to HardOff and LEDoff in my first program. Thanks. I still get caught in those simple mistakes, originally, I didn't have it written as a method and then I was trying to make it more proper. The functional answer here is that the outputs are ORed. I understand that I can't turn off the output from the first cog, but maybe I am fundamentally not understanding something about cogs here. Once I launch this LEDonoff in it's own cog, aren't any calls to it also acting within the launched cog? That's why I put in a call to LEDoff in LEDonoff from switchcaller, but I do think it waits for the waitcnt to complete before it processes anything.

    I can put in the main calling program to start the LEDonoff cog again and it turns the LED off immediately, but I guess I am wonder if that isn't the best way to cause the output to go low. As a hardware guy, it works, but I wonder if there's a better way. Switchcontroller1.spinLEDonoff.spin

    Is there a better method to have a pin go high and then stay high for a time period unless another switch is pressed? I can do this in hardware just fine, but really hoping to learn the software.



    Thanks,

    Dave
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-01-16 09:50
    For your consideration...
    pri oneshot(pin, ms, kill) | t                          ' launch with cognew
    
    '' One-shots pin (output) for ms milliseconds
    '' -- if kill (input) goes high, output aborted
    '' -- runs in own cog, unloads itself
    
      dira[pin] := 1
      outa[pin] := 1
    
      t := cnt
      repeat ms
        if (kill => 0) and (ina[kill] == 1)
          quit
        waitcnt(t += (clkfreq / 1_000))
    
      outa[pin] := 0
      cogstop(cogid)
    

    The idea is that you can call this will an pin # for the output, the # of milliseconds to run, and a pin # for the kill input (-1 for no kill pin). The output will stay hight for the target milliseconds unless the kill input goes high, then it gets terminated immediately. Once the loop is done the output goes low and the cog is unloaded. You'll need to create a small stack array (32 longs will be plenty) and call it like this
    cognew(oneshot(RELAY, 2_000, KILL_BTN), @stack)
    

    This is, in effect, a software 555 in one-shot mode with the kill input attached to the 555 reset pin.
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-01-16 09:55
    Hi Dave,

    if you launch another cog with a SPIN-method then the SPIN-interpreter is loaded into this cog and starts executing the code specified in the cognew-statement.
    This means the interpreter fetches the SIN-bytecode at the adress of speciefied code and goes on from there following the "execution-path" coded from there.

    You still can call the same method from all other cogs and then each cog will fetch the SIN-bytecodes end execute it independently from all other cogs.

    If you just wnat an output pin to be high until another switch is pressed this could simply be a repeat loop with an if-condition.

    But I think you want to do more. So you have to provide a description what you want to do IN THE END.
    Believe me - in most cases - as soon as the forum knows what should be done "in the end" good and sometimes completly different solutions will be found.

    best regards

    Stefan
  • WolfbrotherWolfbrother Posts: 129
    edited 2011-01-16 18:23
    @ JonnyMac
    Thanks, that's pretty clever. So what I would do for my implementation is launch this when my start button is depressed, which will turn it on for whatever delay I have passed in milliseconds. If I wanted a dynamic reset while the program is running I think I could call the cognew again and then kill this cog by it's cogid, in effect taking advantage of the wired or logic that made my first attempt not too successful.

    @StefanL38, What I want to do, I have a start button and a stop button on one of my sculptures. The start button drives a relay which runs a 90VDC motor on a conveyor. It takes about 30 seconds for the conveyor to move little people from one side to the other. So after 30 seconds, I need a timeout condition to stop the belt. The one condition which has to override this activity is if the stop button is pressed. But I would like it if that was a soft stop, meaning you could start it right back up, if the button was pressed by mistake for example, you could press the start button and be running right again.

    My little programs above do that, but I didn't think they were correct programming wise.
  • WolfbrotherWolfbrother Posts: 129
    edited 2011-01-17 21:44
    Well, I have managed to make what seems perfect not work. I copied JonnyMac's code into the prop tool and edited it to call the PRI method with a cognew call based on one input going high. The LED on pin 18 goes on just fine, but glows long after it should have gone out. (2 seconds I think). Also no response from the Kill input, pin 3. The LED is on and will not go out. I have tried setting DIRA and OUTA, played with different waitcnts and generally think the code is correct, but I am not getting the output to cooperate. Any ideas where I have strayed?
    CON
     
    _xinfreq = 5_000_000
    _clkmode = xtal1 + pll16x
    
    input_pin = 4 
    
    VAR
    
    long  stack[40]
    
    
    PUB main
    
     
    dira[input_pin] := 0         ' set to an input line
    
     repeat
        if ina[input_pin] == 1                              ' check for high or low
            cognew(oneshot(18, 2000, 3), @stack)            ' call this subroutine in a new cog.
         
      
    
    pri oneshot(pin, ms, kill) | t                          ' launch with cognew
    
    '' One-shots pin (output) for ms milliseconds
    '' -- if kill (input) goes high, output aborted
    '' -- runs in own cog, unloads itself
    
      dira[pin] := 1                                        ' sets as an output
      outa[pin] := 1                                        ' sets output high
    '  dira[kill] := 0                                      ' sets as an input no difference
      t := cnt
      repeat ms
        if (kill => 0) and (ina[kill] == 1)                 ' If kill is non-zero and the pin is high
            'outa[pin] := 0                                 ' then quit loop immediately
            quit                                            ' wait a millisecond
        waitcnt(t + (clkfreq / 1_000))
    
      outa[pin] := 0                                        'once you have repeat the number of ms, turn off LED
      cogstop(cogid)                                        ' stop cog
    
    
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-01-17 23:00
    But why do you stop that COG? Your program would be much more responsive, if you'd let it run in the background.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-01-17 23:08
    For using the kill you have to define the PIN as an output in the COG that's going to set the kill-bit. So, in your case you have to initialize kill-PIN as output in the main.

    And 2 seconds is fine, as you call the function with 2000ms = 2s. If it glows somewhat about 54 seconds this means that the counter already had a value bigger than the value you want to wait for in the waitcnt. So, maybe you should not do the division in waitcnt. Simply calculate the delta in front of your loop and then you can simply add in the waitcnt.

    delta := clkfreq / 1000
    t := cnt + delta
    repeat
    ....

    oh ... wait ... now I have it

    waitcnt( t += clkfreq/1000 ) is the fix you need ;o)

    Sorry for this confusing post, but I'm doing brain-debugging, as I don't have a prop near to test. .... and it's early in the morning ;o)
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-01-18 07:52
    waitcnt( t += clkfreq/1000 ) is the fix you need ;o)

    Which is already in the code! :)

    I am with MagIO, though, you might as well start a cog and leave it running. What I think may be happening is that you program is in fact starting multiple cogs. You could prevent this by checking the relay output pin for activity before using cognew with the oneshot method.

    Or you could just let a relay control method run and be activated by giving it some time (this would be a global variable). Here's the idea:
    pri relayctrl(rlypin, mspntr, killpin) | t
    
      outa[rlypin] := 0                                             ' output and off
      dira[rlypin] := 1
    
      dira[killpin] := 0                                            ' input
      
      t := cnt                                                      ' sync timing
      repeat
        if (ina[killpin] == 1)                                      ' check kill pin
          long[mspntr] := 0
        outa[rlypin] := (long[mspntr] > 0)                          ' on if still running
        waitcnt(t += (clkfreq / 1_000))                             ' wait 1ms
        if (long[mspntr] > 0)                                       ' running?
          long[mspntr] -= 1                                         '  yes, decrement
    

    You could call it at the top of your program like this:
    cognew(relayctrl(RELAY_PIN, @relayms, KILL_PIN), @stack)
    

    ... where RELAY_PIN and KILL_PIN are constants for those pins (they don't change, right?) and relayms is a global variable (long) that holds the output timing in milliseconds. A positive, non-zero value in relayms will activate the relay. The kill input actually clears this variable which is used to disable the output. Your code might look something like this:
    repeat
       if (ina[TRIGGER] == 1)                                       ' trigger active?
         relayms := 2_000                                           ' yes (re)start timer
    

    This will start the relay. Once the trigger input goes away the relay will run for another 2000 milliseconds (2s).
  • WolfbrotherWolfbrother Posts: 129
    edited 2011-01-18 18:04
    Hi,

    I can see that multiple cogs would cause the LED to stay lit. I'll work on this code tonight and let you all know what I find out. Thanks so much, I'm still swimming in using SPIN.
  • WolfbrotherWolfbrother Posts: 129
    edited 2011-01-19 14:34
    @JonnyMac, thanks so much for taking the time to offer your code and to explain it to me. Everything works just fine and I understand it all as well. Thanks.

    @MagIO2, thank you also. Your idea made me understand the code JonnyMac posted.
Sign In or Register to comment.