Shop OBEX P1 Docs P2 Docs Learn Events
Need some help understanding interaction between 2 objects — Parallax Forums

Need some help understanding interaction between 2 objects

Don MDon M Posts: 1,653
edited 2012-07-29 06:53 in Propeller 1
I have 2 obejects- Main_Test and Object2.

In the Main_Test object it runs a loop waiting for a key press from PST.
CON

  _clkmode        = xtal1 + pll16x                      ' Feedback and PLL multiplier
  _xinfreq        = 5_000_000                           ' External oscillator = 5 MHz

  MS_001   = 80_000_000 / 1_000

obj

  term              : "fullduplexserialdp_1"
  other_object      : "object2"
  
var                                                     

pub main | c

  term.start(31, 30, %0000, 115_200)                    ' start terminal using PST
  pause(500)                                            ' pause for PST
  term.str(@message1)                                   ' display device name on reset  

  other_object.start  
  pause(500)                                            
  
  repeat

     c := term.rxcheck
     if (c => 0)                                         ' anything in m->s buffer?
        case c

           "r" , "R":
               reboot
           "c":
              remote_led   
               
pub remote_led

   other_object.remote

pub pause(ms) | t

  t := cnt
  repeat ms
    waitcnt(t += MS_001)
    
dat

  message1    byte          "Testing for transfer data",0

In Object2 it initializes 4 outputs for led's (Quickstart board) and runs a simple loop flashing 1 led on / off.
  MS_001   = 80_000_000 / 1_000   

  LED4  = 19                                          
  LED3  = 18                                          
  LED2  = 17                                          
  LED1  = 16                                          

obj

var
  byte  p
  long  Stack[256], cog
   
PUB Start

  cog := cognew(main,@Stack)+1
  
pub main

  dira[16..19]~~ 
  pause(1000)                                           ' 1 second delay
  outa[16..19]~~
  pause(1000)                                           ' 1 second delay
  outa[16..19]~

  repeat

    test_loop
    pause(1000)
    outa[LED1]~
    pause(1000)

pub Test_Loop

  outa[LED1]~~

pub Remote

  outa[LED3]~~
  pause(1000)
  outa[LED3]~

pub pause(ms) | t

  t := cnt
  repeat ms
    waitcnt(t += MS_001)
    
dat

What I am trying to do is turn on one of the remaining led's by using a call method from the Main_Test object called Remote_Led. But it doesn't work like I thought it should. I was expecting that when that method was called it would then call the method in Object2 and turn on the led.

Why doesn't this work?

Thanks.
Don

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2012-07-27 15:09
    The problem is the you have objects and you have cogs and they're not the same thing. Each cog has its own set of I/O registers and they're or'd together to provide the direction and output state of the I/O pins. In your case, the main method is being executed by one cog (#1) and everything else (except the PASM portion of FullDuplexSerial) is executed by the other cog (#0). When your main program calls other_object.Remote, it's using cog #0 and cog #0's I/O registers have bits 16..19 set to zeroes (input mode) so .Remote won't affect the LEDs. When main calls test_loop, it's using cog #1 whose DIRA register is set up properly.

    You have two solutions. 1) In other_object, have a global variable that's set by Remote that main will use to change the LED's state. 2) Have other_object's Start method set DIRA so bits 16..19 are outputs. The actual I/O pins will be the logical or of OUTA in cog #0 with OUTA in cog #1.
  • cavelambcavelamb Posts: 720
    edited 2012-07-27 16:28
    I wrote this to learn about coordinating between cogs.
    It's long, too involved and lame, but it works.

    Three objects...
    FlagDemo2.spin - the main program (top object?)
    QS_Buttons.spin - the button driver
    FlagWatch.spin - watches to see what's happening.

    QS_Buttons doesn't play with any LEDs. It scans the touchpads and returns a byte with bits set according to the touch pads.
    I == pressed, 0 == not.

    FlagDemo2 is the main guy. It starts the other two objects in different cogs.
    Notice the start calls... it passes the ADDRESS of a place where stuff will be passed back.

    Then it watches the Buttons byte to see if button 4 is set (Touch pad 4)
    When that happens it sets FLAG to 1
    and changes the LEDs that it uses (22 and 17)
    FLAG == 0 LED 22 := 1
    FLAG == 1 LED 17 := 1


    FlagWatch sets LED 3 just to show it's running.
    Then it watchs for FLAG ==1 to happen.
    When it sees that, it swaps LEDs (15 and 23).
    LED 15 ON for flag == 0
    LED 23 ON for Flag == 1

    So the action is at the extreme ends of the LED string.

    There should be two LEDS on at a time (not counting the middle one),
    and both on the same end. If not, somebody is messing up.

    Like I said, long, involved and way lame, but I learned how it works here.
    Maybe it will help?
    CON { Flag_Demo.spin }
      _CLKMODE=XTAL2 
      _xinfreq = 5_000_000
      
    VAR
      LONG MS001, Buttons, Flag
      
    OBJ button: "QS_Buttons"    ' touchpad driver
    
    OBJ Fwatch: "Flag_Watch"             ' other cog method
    
    PUB ButtonDemo | B          ' local variables
      MS001 := CLKFREQ / 1_000  ' define 1 millisec 
      button.start( @Buttons )  ' send address of Buttons
      Fwatch.start(@flag)
    
    Repeat
         if Buttons & |< 4       ' button 4 pressed?
             Flag := 1           ' set Flag
             TurnON(4+16)        ' show the button pressed
             WaitMS(10)                
             TurnOFF(4+16)
         else
             Flag := 0            ' else clear Flag
         If Flag == 1            ' this cog can see Flag directly
             TurnON(1+16)        ' LED 1 ON
             TurnOFF(6+16)       ' LED 6 Off
         else
             TurnOFF(1+16)       ' LED 1 OFF
             TurnON (6+16)       ' LED 6 ON     
    
    PUB WaitMS(W)                ' wait for W milliseconds
      W := W*MS001                
      WaitCNT (W+cnt)
    
    PUB TurnON(pin)
        dira[pin] := 1
        outa[pin] := 1
    
    PUB TurnOFF(pin)
        dira[pin] := 1
        outa[pin] := 0 
    
    CON { Flag_Watch.spin }
    VAR
      LONG Stack[ 16 ]                 ' define my stack
      LONG FlagA, AcogID
      
    PUB start( F )                      ' start this in a new cog
      FlagA := F                        ' save location of flag variable
      if ACogID
        cogstop(ACogID-1)               ' no cog available
      ACogID := cognew(Aproc, @Stack) + 1
      
    PUB Aproc 
      'main loop - scan the buttons   
      Repeat                            ' loop forever
        TurnON(19)                      ' LED 3 show's I'm alive 
        if  byte[FlagA] ==   1          'if I see a 1
           TurnON(16)                   '  show this LED 15
           TurnOFF(23)
        else                            'if I see a 0 
           TurnON(23)                   '  show that LED 23
           TurnOFF(16)
    
    PUB TurnON(pin)
        dira[pin] := 1
        outa[pin] := 1
    
    PUB TurnOFF(pin)
        dira[pin] := 1
        outa[pin] := 0  
    

    'CON { QS_ButtonScan.spin }
    '    { returns buttons packed bitwide is a byte}
    VAR                  
      LONG ButtonAdr, ButtonCog, MS001
      LONG Stack[ 16 ]                 ' define my stack
    
    PUB start( BAdr )                  ' BAdr = Button Address
      ButtonAdr := BAdr                ' save address of return byte
      if ButtonCog                     ' did the new cog start?
        cogstop(ButtonCog-1)           ' OOPS! no cog available
      ButtonCog := cognew(ButtonScan, @Stack) + 1
      MS001 := clkfreq/1000
    
    PUB ButtonScan | B, B1              ' local variables
      dira [0..7] := 111111          ' all pad pins outputs    
      outa [0..7] := 111111          ' all pad pins high   
      'main loop - scan the buttons   
      Repeat                            ' loop forever
         Repeat B from 0 to 7           ' QS LEDS are pins 0-7
           dira [B] := 1                ' make pin an output 
           dira [B] := 0                ' make pin an input
           WaitMS(4)                    ' short delay for some decay
           B1 := ina[B]                 ' read the pad
           if B1 == 0                   ' 0 here means pressed
              BYTE[ButtonAdr] |= |< B   ' set bit if pressed   
           else                    
              BYTE[ButtonAdr] &= !|< B  ' clear bit if not
    
    PUB WaitMS(W)                       'wait for W milliseconds
      W := W * 1000 'MS001                
      WaitCNT (W+cnt)
    
  • cavelambcavelamb Posts: 720
    edited 2012-07-27 19:28
    Ok, I'm done messing with the explanation. I hope that it makes sense.
    The code works (just checked it again) so if something is unclear, read
    the code!

    Now, I have a question...

    I call fwatch.start to start the flag watch method.
    But I didn't call the mainpart of the code (Aproc in Flag_Watch.spin).
    And yet it works correctly.

    Same thing with Button.Start.
    Never called the ButtonScan method.
    But it runs.

    Why is that?

    Is there something special aboutthe .start?
  • kuronekokuroneko Posts: 3,623
    edited 2012-07-27 20:26
    cavelamb wrote: »
    Why is that?

    Is there something special aboutthe .start?
    Nope. All your start methods do is start a new cog with the methods you apparenly don't call, e.g.
    PUB start( BAdr )                  ' BAdr = Button Address
      ButtonAdr := BAdr                ' save address of return byte
      if ButtonCog                     ' did the new cog start?
        cogstop(ButtonCog-1)           ' OOPS! no cog available
      ButtonCog := cognew([COLOR="red"]ButtonScan[/COLOR], @Stack) + 1
      MS001 := clkfreq/1000
    
    So there is nothing to worry about.
  • cavelambcavelamb Posts: 720
    edited 2012-07-27 20:47
    Kuroneko,

    Thank you for kindly pointing out the painfully obvious which I completely missed when I was looking a the code tonight...
    I remember now. I knew it couldn't fall though the end of the PUB or PRI block.
    But I didn't catch the call inside the .start methods.

    (The COGNEW did it - in the library - with a soldering iron... (anybody here old enough to get that?))

    And the other one is invoked in its' .start function...
    ACogID := cognew(Aproc, @Stack) + 1

    A lot of my learning so far has been pretty much cook-book style.
    But eventually the LED comes on...
  • RS_JimRS_Jim Posts: 1,768
    edited 2012-07-29 06:53
    cavelamb wrote: »
    Kuroneko,

    Thank you for kindly pointing out the painfully obvious which I completely missed when I was looking a the code tonight...
    I remember now. I knew it couldn't fall though the end of the PUB or PRI block.
    But I didn't catch the call inside the .start methods.

    (The COGNEW did it - in the library - with a soldering iron... (anybody here old enough to get that?))

    And the other one is invoked in its' .start function...
    ACogID := cognew(Aproc, @Stack) + 1

    A lot of my learning so far has been pretty much cook-book style.
    But eventually the LED comes on...
    Are you sure the butler didn't do it?
Sign In or Register to comment.