Shop OBEX P1 Docs P2 Docs Learn Events
global variable, multiple cogs — Parallax Forums

global variable, multiple cogs

mikeamikea Posts: 283
edited 2014-03-15 05:48 in Propeller 1
If a parent object calls a secondary object that contains global variables that is intended for both objects to share. Do I have to specifically address them in the parent object? Also the secondary object will be running in a separate cog. I've read or kit book and manual but I'm not clear how to do this.

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-03-12 12:19
    Don't worry about having variable in different cogs. All variables in Spin are in the hub. Having different objects sharing variables is where you can run into trouble. You need to pass the address of the variable either to the child (if the variable in in the parent object) of the child object needs to get the address to the parent object if the variable is declared in the child object. You can't declare the variable in both objects and expect the value to be shared.

    As far as different cogs is concerned, you just need to worry about one cog changing a variable when it's not expected. Because of the round robin nature of the hub, only one cog can access a variable at a time.

    Remember, the Spin code stays in the hub. It's the Spin interpreter that's launched in a newcog when instructed. All the Spin variables stay in the hub so all the cogs can access them.

    The piezo program I posted earlier today returns the address of the note array in the child object. The parent object doesn't use this information but I wanted the parent to have it in case I wanted the parent to directly access the array.

    A lot of the TV object pass the address of a bunch of parameters from the parent to the child.

    It can be a pain to deal with variable by address since one has to write "long[addressOfVariable]" whenever one whats to access the variable. I frequently just make one big program if there's a lot of variables to be shared.
  • Heater.Heater. Posts: 21,230
    edited 2014-03-12 12:32
    Also do not confuse "Spin objects" with "cogs".

    It is quite possible for your program to use sub objects that never start another COG. They can just provide methods for you to call. Everything runs in the same COG.

    Conversely it is quite possible that a single object can start many COGs each running some Spin method or PASM code.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-03-12 12:32
    Here's an example of the child object returning the location of a variable.
    PUB Init(piezoPin_)
    
      piezoPin := piezoPin_
      millisecond := clkfreq / 1_000
      clkfreqTimesTen := clkfreq * 10
      counterSetting := COUNTER_SETTING_FOR_FREQENCY + piezoPin
      SetQuarterNoteTime(DEFAULT_QUARTER_NOTE_TIME)
     [COLOR=#ff0000][B] result := @note ' return the address of the note array[/B][/COLOR]
    
    
    

    You can see on the bottom line the location of "note" is returned.

    The parent looks like this.
    Pst.Str(string(13, 13, "Initializing piezo object.")) 
      [COLOR=#ff0000][B]noteArrayAddress := Piezo.Init(PIEZO_PIN)[/B][/COLOR]
    

    To assign the variable c1 the value of the 13th element (#12 since we start counting with zero) of the note array, the parent object would use:
    c1 := long[noteArrayAddress][12]
    
  • mikeamikea Posts: 283
    edited 2014-03-12 15:14
    Thank you. The reason for 2 cogs is that I need 3 counters. The parent object uses 2 counters for inputs and determines the output of the child object that uses the 3rd counter. So I was wanting to relay the variable info to the 2nd cog. I think I understand. Gonna try it and see.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-03-12 15:29
    Make sure and only set the direction and output states from within the cog using the I/O pin. It's not a problem for multiple cogs to use a pin as an input but if one cog makes a pin an output another cog can't change it back to an input. I one cog has set a pin as an output it will remain an output until all cogs have their dira registers set back to the input state. (This was my favorite way of creating bugs for a long time.)
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-03-12 15:43
    Duane Degn wrote: »
    Make sure and only set the direction and output states from within the cog using the I/O pin. It's not a problem for multiple cogs to use a pin as an input but if one cog makes a pin an output another cog can't change it back to an input. I one cog has set a pin as an output it will remain an output until all cogs have their dira registers set back to the input state. (This was my favorite way of creating bugs for a long time.)

    More correctly since the outputs are or'ed together that means that any cog can set the output high but another cog won't be able to take it low. So if all cogs made a pin an output and only pulsed it high when it needed to while holding it low the rest of the time then it will still work. If the output was an active high alarm for instance then any cog could just set it but there's not too many instances where we could take advantage of the or'ing.

    If debugging is the art of removing bugs then programming must be the art of...... :)
  • mikeamikea Posts: 283
    edited 2014-03-12 16:09
    Sounds like its ok in that respect, each counter and its I/0 pin are dedicated to one job either low or high.
  • mikeamikea Posts: 283
    edited 2014-03-12 18:31
    I think I have something wrong, the compiler wants the variable "pushbutton" to be declared in the child object, its declared in the parent and supposed to be passed to the child. I thought variables should only appear in the var section of only on of the objects. Also I have a line in the parent object ....v_test.start....is this a correct way to put this into a new cog?
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
     'parent object'''''''''''''''
    CON
            _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    obj v_test : "variable test"
    VAR
      long pushbutton
      long stack[100]
    pub main
    dira[18]~ 'pushbutton input pin
     v_test.start(@stack)
    repeat
      pushbutton:=ina[18]         'pushbutton variable should be passed to child object "variable test"
      waitcnt(clkfreq/1000+cnt)
    

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    '''child object''''''''''
    CON
            _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    var
    long measurement
    pub subb
    measurement:=@ pushbutton
    
    dira[20..21]~~
      repeat
        outa[20]~~          'pilot led
        while measurement==1
          outa[20]~
          outa[21]~~        'test led to check if variable is passed ok
    
  • kuronekokuroneko Posts: 3,623
    edited 2014-03-12 19:24
    So where do you pass (a reference of) pushbutton to the child object? This doesn't happen automatically.
  • mikeamikea Posts: 283
    edited 2014-03-13 05:28
    I guess I'm not clear on it yet. Sounds like variables are kept in the hub. So maybe point the variable @ some stack, but then do you equate (:=) the variable to that stack in the other cog with a new variable name? The same variable name shouldn't show up in 2 separate cogs right? Or maybe the point of the same variable in 2 cogs is that it just won't share info.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-03-13 08:07
    mikea wrote: »
    I guess I'm not clear on it yet. Sounds like variables are kept in the hub. So maybe point the variable @ some stack, but then do you equate (:=) the variable to that stack in the other cog with a new variable name? The same variable name shouldn't show up in 2 separate cogs right? Or maybe the point of the same variable in 2 cogs is that it just won't share info.

    I'll try to find (or write) a simple example.

    Cogs have got nothing to do with whether or not a variable gets shared or not. It's objects you need to worry about.

    The only time a separate cog won't have access to a variable is if it's running PASM code. If it's running PASM, all reads (and writes) to the hub require a PASM command to access a variable location. You should need to worry about how PASM behaves for now.

    I just remembered a program which passes an address. It's in the same piezo music program. I'll post the example in a minute.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-03-13 08:31
    The piezo example passed the address of a list of variables to use. I thought it might be easier for you to understand how this works if I just modified your original code to pass the addresses correctly. I left the stack array in the parent object. The stack array could also have been placed in the child object and "@stack" would have been used when launching the cog instead of "stackAddress".

    Since "stackAddress" contains the address of the array "stack" the address symbol shouldn't be used since I'm not interested in the address of "stackAddress" but the value of "stackAddress". This is a very important concept and you want to make sure you understand the difference between the contents of a variable and the location of a variable.

    In this example "stackAddress" contains the address of "stack" in the parent object.

    Here's the parent:
    'parent object'''''''''''''''
    CON
            _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    obj v_test : "variable test"
    VAR
      long pushbutton
      long stack[100]  
    pub main
    dira[18]~ 'pushbutton input pin
     v_test.start(@pushbutton, @stack)
    repeat
      pushbutton:=ina[18]         'pushbutton variable should be passed to child object "variable test"
      waitcnt(clkfreq/1000+cnt) 
    
    
    

    and the child:
    '''child object'''''''''''
    CON
    '        _clkmode = xtal1 + pll16x  'Standard clock mode * crystal frequency = 80 MHz
    '        _xinfreq = 5_000_000
    ' Clock setting of parent is used.
    var
    
    
      long pushbuttonAddress
    
    
    pub start(pushbuttonAddressTemp, stackAddress)
    
    
      pushbuttonAddress := pushbuttonAddressTemp
      cognew(monitorPushbutton, stackAddress)
      
    pub monitorPushbutton
    
    
      dira[20..21]~~   
    
      repeat
        outa[20]~~          'pilot led
        outa[21]~           ' turn off LED when button isn't being pressed
        repeat while long[pushbuttonAddress] == 1
          outa[20]~
          outa[21]~~        'test led to check if variable is passed ok
    

    I've attached the achieve with these two files to this post.

    Edit: I had an incorrect comment added. Comment deleted.
  • mikeamikea Posts: 283
    edited 2014-03-14 13:07
    @Duane, thank you for the example. If this were all one object and a new cog was launched within it would the global variables be seen by all? I mean so they wouldn't have to be forwarded.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-03-14 13:57
    mikea wrote: »
    @Duane, thank you for the example. If this were all one object and a new cog was launched within it would the global variables be seen by all? I mean so they wouldn't have to be forwarded.

    Correct. It's just different objects that don't share global variables. Multiple cogs can share variables just fine.

    An exception to different objects not sharing variables is when you're using multiple instances of the same object. To save space, only one copy of the object's code is loaded into the Propeller. The Propeller can use this same code multiple times without the multiple instances clashing. To keep global variables from clashing, each instance has its own "VAR" section in RAM. However, variables stored in the "DAT" section are shared among the multiple instances. This is one time when variables are shared among multiple objects. This has limited application since the objects sharing the variables have the exact some code. There are occasions when these shared "DAT" variables can be very handy.
  • mikeamikea Posts: 283
    edited 2014-03-14 20:00
    The code below works except that in the method pub testpwm , (which is launched into a new cog), the global variable "dist" always equals zero down in that method I found out. But in the serial terminal it is constantly updated to a believable value. I've tested pub testpwm by manually putting in values for "dist" and it responds ok, but its just not getting any other value than zero the way its supposed to run.
    '' TestIrDutyDistanceDetector.spin
    '' Test distance detection with IrDetector object.
    CON
    _xinfreq = 5_000_000
    _clkmode = xtal1 + pll16x
    OBJ
    ir : "IrDetector"
    pst : "Parallax Serial Terminal"
    
    
    var 
        long dist
        long stack[200]
    PUB TestIr
    cognew(TestPwm,@stack)
    ' Starts Parallax Serial Terminal; waits 1 s for you to click Enable button.
    pst.Start(115_200)
    pst.Clear
    pst.Str(string("Distance = "))
    'Configure IR detectors.
    ir.init(1, 2, 12)     '''''''''''''''pin 12 was pin 0, had to separate bc of induction screwing up signal  (anode,cathode,ir receiver)
     repeat 
    '   Get and display distance.
        pst.Str(string(pst#PX, 11))
        dist := ir.Distance
        pst.Dec(dist)
        pst.Str(string("/256", pst#CE))       'distance is between 0-256
        waitcnt(clkfreq/3 + cnt)
    PUB TestPwm | tc, tHa, t ,measurement                             ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''section below is in new cog ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ctra[30..26] := %00100 ' Configure Counter A to NCO
    ctra[5..0] := 16
    frqa := 1
    phsa:=0
    dira[16]~~
      
    
      tC := 256_000 ' Set up cycle and high times
      measurement:= (dist*990)
      tHa := 256_000-measurement
      t := cnt ' Mark counter time
      repeat ' Repeat PWM signal 
         phsa := -tHa ' Set up the pulse
         t += tC ' Calculate next cycle repeat
         waitcnt(t) ' Wait for next cycle
    
  • Clock LoopClock Loop Posts: 2,069
    edited 2014-03-14 20:09
    Duane Degn wrote: »
    There are occasions when these shared "DAT" variables can be very handy.

    Its how many of my spin magic projects were accomplished with ease.

    The DAT section is a very powerful memory/variable space if you use it right. But it can get you into big trouble if you use it wrong.
  • kuronekokuroneko Posts: 3,623
    edited 2014-03-14 20:29
    mikea wrote: »
    The code below works except that in the method pub testpwm , (which is launched into a new cog), the global variable "dist" always equals zero down in that method I found out.
    dist is only looked at once before you enter the (endless) loop. At this early time it is likely that dist hasn't been updated yet by the call to ir.Distance. IOW you'll see its default value 0. So either move the tHa calculation into the loop or make tHa global and let the primary cog do the math.
  • mikeamikea Posts: 283
    edited 2014-03-14 21:33
    Thank you, that makes sense. Going to get it going tomorrow!
  • mikeamikea Posts: 283
    edited 2014-03-15 05:48
    The variable dist, and line of math is now in the repeat loop.Everything works well. Thanks for all the help.
Sign In or Register to comment.