PDA

View Full Version : Solved @ Simple Concept



SteveWoodrough
03-26-2012, 03:16 AM
Attached is a pair of fairly simple objects that I'm using to get the concept of address passing through my thick gear head brain. These objects will run on an unmodified DEMO board.

So far I'm fairly confident retrieving data from cogs that are started from the main method, but I'm having trouble with retrieving data from cogs launched from "lower" methods.

Ultimately what I want to be able to do is bring in the data from the lower object method running in a separate cog, into the main object and display through the PST. I can do that just fine if the method, cog, and PST are launched from the main object. Currently when I try to display the data from the cog launched by the lower object I get 9.

Coupled with all this is an attempt to better understand the use of the @ symbol. In a few cases Iíve used the @ but mostly in the trivial cases where it is equivalent to the variable value it self.

Anyway, first things first, what am I doing wrong where I get a result of 9 when the value should be incrementing by 1 each half second?

Thank You
Steve




{************************************************* *
* Main01 *
* *
************************************************** *
The intent of this program is to demonstrate the passing of parameter data using both local and global variables
Addtionally is an attempt at using the @ symbol to pass data between objects.
Runs very easily on a Prop Demo board
}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000

OBJ

LO : "LowerObject"
PST : "Parallax Serial Terminal"

VAR
long a,b,c
long countstack[15]
byte cog

Pub Main
' pst.start(115200)

{
LO.StartBlink(22,5) 'Starts a new cog in a lower object using pin 22 at a rate of 5 hz
waitcnt(clkfreq+cnt)
LO.StartBlinker(18,3) 'Starts a new cog in same lower object using pin 18 at a rate of 3 hz
waitcnt(clkfreq+cnt)
}

' StartCountUp 'CountUp run in seprate cog from this method

LO.StartCountUp

{
repeat
'a:= Long[@b] 'both a:= expressions seem to have the same effect
' a:= b
pst.dec(a)
pst.char(13)
waitcnt(clkfreq/2+cnt)
}

Pub StartCountUp :success
StopCountup
success:= (cog := cognew(CountUp, @countstack) + 1)

Pub StopCountup
if Cog
cogstop(Cog~ - 1)

Pub CountUp
repeat
b++
waitcnt(clkfreq/2+cnt)







{
This is a simple object that can run in a another cog(s)

}

OBJ


PST : "Parallax Serial Terminal"


VAR
long stack1[10], stack2[10] 'Cog stack space
long countstack[15]

long Z
byte cog[2] 'Cog ID's


Pub StartBlink(mom,dad) :success 'The parameter names can be pretty much anything as long as they match
StopBlink
success:= (cog[0] := cognew(Blink(mom,dad), @stack1) + 1) 'The cog name, however, must be unique
Pub StopBlink
if Cog[0]
cogstop(Cog[0]~ - 1)

Pub Blink(pin,rate)
dira[pin]~~
repeat
!outa[pin]
waitcnt(clkfreq/(rate*2) + cnt)

Pub StartBlinker(apple,pie) :success 'The parameter names can be pretty much anything as long as they match
StopBlinker
success:= (cog[1] := cognew(Blink(apple,pie), @stack2) + 1)

Pub StopBlinker
if Cog[1]
cogstop(Cog[1]~ - 1)

Pub Blinker(pinadd, rateadd) |pin, rate

pin := long[@pinAdd] 'Each of these expression pairs seems to be the same
rate := long[@rateAdd] ' what is the difference?

' pin := long[pinAdd] 'Each of these expression pairs seems to be the same
' rate := long[rateAdd] ' what is the difference?

' pin := pinadd 'Each of these expression pairs seems to be the same
' rate := rateadd ' what is the difference?

dira[pin]~~
repeat
!outa[pin]
waitcnt(clkfreq/(rate*2) + cnt)

Pub StartCountUp :success
StopCountup
success:= (Cog[2] := cognew(CountUp, @countstack) + 1)

Pub StopCountup
if Cog[2]
cogstop(Cog[2]~ - 1)

Pub CountUp

pst.start(115200)

dira[16]~~ 'indicates method and cog are in fact operating
repeat
z++
!outa[16] 'indicates method and cog are in fact operating
pst.dec(z)
pst.char(13)
waitcnt(clkfreq/2+cnt)

turbosupra
03-26-2012, 04:06 AM
Hello fellow gear head ... your stack is too small. Replace your vars in your child object with the following and she'll count up like you want her to. I didn't try increasing them individually, but the culprit is going to probably be just one of them, you can figure it out through process of elimination if you'd like.

As a general rule of thumb, as I've had obnoxious things like this happen to me before, I make all of my stacks 100 longs, and if I ever get to a point in one of my programs where I'm almost out of space, I'll start rationing the stack space out, but that pretty much never happens to me and I've never had an issue with "long space" when I've set them to 100.



VAR
long stack1[100], stack2[100] 'Cog stack space
long countstack[100]

long Z
byte cog[2] 'Cog ID's







Attached is a pair of fairly simple objects that I'm using to get the concept of address passing through my thick gear head brain. These objects will run on an unmodified DEMO board.

So far I'm fairly confident retrieving data from cogs that are started from the main method, but I'm having trouble with retrieving data from cogs launched from "lower" methods.

Ultimately what I want to be able to do is bring in the data from the lower object method running in a separate cog, into the main object and display through the PST. I can do that just fine if the method, cog, and PST are launched from the main object. Currently when I try to display the data from the cog launched by the lower object I get 9.

Coupled with all this is an attempt to better understand the use of the @ symbol. In a few cases Iíve used the @ but mostly in the trivial cases where it is equivalent to the variable value it self.

Anyway, first things first, what am I doing wrong where I get a result of 9 when the value should be incrementing by 1 each half second?

Thank You
Steve




{************************************************* *
* Main01 *
* *
************************************************** *
The intent of this program is to demonstrate the passing of parameter data using both local and global variables
Addtionally is an attempt at using the @ symbol to pass data between objects.
Runs very easily on a Prop Demo board
}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000

OBJ

LO : "LowerObject"
PST : "Parallax Serial Terminal"

VAR
long a,b,c
long countstack[15]
byte cog

Pub Main
' pst.start(115200)

{
LO.StartBlink(22,5) 'Starts a new cog in a lower object using pin 22 at a rate of 5 hz
waitcnt(clkfreq+cnt)
LO.StartBlinker(18,3) 'Starts a new cog in same lower object using pin 18 at a rate of 3 hz
waitcnt(clkfreq+cnt)
}

' StartCountUp 'CountUp run in seprate cog from this method

LO.StartCountUp

{
repeat
'a:= Long[@b] 'both a:= expressions seem to have the same effect
' a:= b
pst.dec(a)
pst.char(13)
waitcnt(clkfreq/2+cnt)
}

Pub StartCountUp :success
StopCountup
success:= (cog := cognew(CountUp, @countstack) + 1)

Pub StopCountup
if Cog
cogstop(Cog~ - 1)

Pub CountUp
repeat
b++
waitcnt(clkfreq/2+cnt)







{
This is a simple object that can run in a another cog(s)

}

OBJ


PST : "Parallax Serial Terminal"


VAR
long stack1[10], stack2[10] 'Cog stack space
long countstack[15]

long Z
byte cog[2] 'Cog ID's


Pub StartBlink(mom,dad) :success 'The parameter names can be pretty much anything as long as they match
StopBlink
success:= (cog[0] := cognew(Blink(mom,dad), @stack1) + 1) 'The cog name, however, must be unique
Pub StopBlink
if Cog[0]
cogstop(Cog[0]~ - 1)

Pub Blink(pin,rate)
dira[pin]~~
repeat
!outa[pin]
waitcnt(clkfreq/(rate*2) + cnt)

Pub StartBlinker(apple,pie) :success 'The parameter names can be pretty much anything as long as they match
StopBlinker
success:= (cog[1] := cognew(Blink(apple,pie), @stack2) + 1)

Pub StopBlinker
if Cog[1]
cogstop(Cog[1]~ - 1)

Pub Blinker(pinadd, rateadd) |pin, rate

pin := long[@pinAdd] 'Each of these expression pairs seems to be the same
rate := long[@rateAdd] ' what is the difference?

' pin := long[pinAdd] 'Each of these expression pairs seems to be the same
' rate := long[rateAdd] ' what is the difference?

' pin := pinadd 'Each of these expression pairs seems to be the same
' rate := rateadd ' what is the difference?

dira[pin]~~
repeat
!outa[pin]
waitcnt(clkfreq/(rate*2) + cnt)

Pub StartCountUp :success
StopCountup
success:= (Cog[2] := cognew(CountUp, @countstack) + 1)

Pub StopCountup
if Cog[2]
cogstop(Cog[2]~ - 1)

Pub CountUp

pst.start(115200)

dira[16]~~ 'indicates method and cog are in fact operating
repeat
z++
!outa[16] 'indicates method and cog are in fact operating
pst.dec(z)
pst.char(13)
waitcnt(clkfreq/2+cnt)

Duane Degn
03-26-2012, 04:45 AM
Steve,

One problem I noticed is this line.


success:= (Cog[2] := cognew(CountUp, @countstack) + 1)

Since your array "Cog" has two elements, you only want to access elements 0 and 1.


byte cog[2] 'Cog ID's

Element "2" is not part of the array so it will overwrite some other memory position.

MagIO2
03-26-2012, 06:35 AM
@Steve:
You have some open questions in your code comments, so here is my answer:

Let's assume we do know nothin! What is a variable?
A variable is a concept that has been introduced with the first interpreters and compilers. Before that we only had memory addresses, then came labels. And it's only purpose is to make programs readable!
$1f30 := $500
is for sure worse to read and later on to remember the purpose than this


CON
DEFAULT_RPM = $500
VAR
long current_RPM
PUB main
current_RPM := DEFAULT_RPM

Please note that with the "new" programming style using variables there is no need to know the address at all - well ... in most cases. The compiler takes care of placing the variable somewhere in memory and you can easily use it in your code.

Nevertheless, with long[], word[] and byte[] we still have the chance to work with addresses and with @ we can ask the compiler where it placed a variable in RAM.
One of the most important points you have to understand here is:
long[ @aVariable ] := 10 is the same as
aVariable := 10
(in case aVariable is a long)

So, if both do the same, why do we need both ways?
Well .. there are many answers for that:
1. Object-orientation
2. Function calls where the parameters are called 'by value'
3. cognew
but below the line the reason is the same for all cases: you want direct access to memory locations!

Why:
1. In objects you don't know anything about the programs that will use this object. So, there is no chance to use variables defined outside of the object. If the object shall work directly on variables defined outside, the only way is to tell the object where to find the variable in memory - so, passing the address.
2. If you call a function which has parameters, the parameters are copied into local variables on the stack:


var1 := 10
var2 := 20
func_test( var1, var2 )
var2 := 44
print( var1, var2 )
...
PUB func_test( par1, par2 )
print( par1, par2 )
par1 := 22
print( par1, par2 )

Output would be in func_test [10, 20] then again in func_test [22, 20] and then in the main [10,44]. The local variables par1 and par2 are initialized with the values of var1 and var2, but are completely independend variables. If you want to have a link, you'd use addresses instead:


var1 := 10
var2 := 20
func_test( @var1, @var2 )
var2 := 44
print( var1, var2 )
...
PUB func_test( par1_adr, par2_adr )
print( long[ par1_adr ], long[ par2_adr ] )
long[ par1_adr ] := 22 ' remember ... it's the same as var1 := 22
print( long[ par1_adr ], long[ par2_adr ] )

Output would be in func_test [10, 20] then again in func_test [22, 20] and then in the main [22,44].

3. For cognew of a SPIN function you need to tell the COG which memory can be used as stack - variables defined in the same SPIN-file are accessible by all COGs started here.
Cognew for PASM-code most times needs to agree on some memory locations which can be used to communicate with the PASM - like when it's waiting for instructions. Variables are unknown by a COG especially as most instructions of a COG operate in COG-RAM whereas the variables are placed in HUB-RAM. Here we have the concept of labels again.

Now ... coming back to your code:


Pub Blinker(pinadd, rateadd) |pin, rate

pin := long[@pinAdd] 'Each of these expression pairs seems to be the same
rate := long[@rateAdd] ' what is the difference?

' pin := long[pinAdd] 'Each of these expression pairs seems to be the same
' rate := long[rateAdd] ' what is the difference?

' pin := pinadd 'Each of these expression pairs seems to be the same
' rate := rateadd ' what is the difference?

under some circumstances all 3 versions will run, but differently:
For 1.) You have to call Blinker( apple,pie ) -> value of apple and pie are copied into local variables pinAdd and rateAdd and then you say pin:=long[@pinAdd] which is the same as pin:=pinAdd where pinAdd contains the value of apple
For 2.) You have to call Blinker( @apple, @pie ) -> the addresses of apple and pie are copied into pinAdd and rateAdd and pin:=long[pinAdd] is the same as pin:=long[@apple] which is pin:=apple
For 3.) You have to call Blinker( apple, pie ) -> easy pin := pinAdr := apple

1. and 3. are totally equal, but 2. gives you an addidional possibility. If you change apple or pin while Blinker is running, you can change the ... well ... at least the blink-rate. Changing the pin is not that easy and would need some additional code which also updates DIRA.

Hope that helped!
;o)

SteveWoodrough
03-29-2012, 01:06 AM
Thank you all for the thoughtful replies. It turns out the stack was too small. My aplogies for not responding sooneer, I was away on business and would you believe, no internet in the hotel! Now that we have that little matter solved it's on to a better understanding of the concepts explained by MagIO2. I'm sure I will get stumped again soon!
Best Regards
Steve
PS, I can't figure how to change this post from Unsolved to Solved. I thought there was a drop dowm menu some where, but I'm not seeing it.

SteveWoodrough
03-29-2012, 02:28 AM
Ok, now that we got the stack size issue taken care of we can get to the root of my quest. Attached are simplified versions of the corrected code mentioned above. The called method, LO.StartCountUp is running in a separate object, separate cog, so therefore the local and global variables associated with the method, and object are unknown to the Main method making the call. The challenge is how to bring that data from the called method and object into the Main object.

Thank You
Steve




{************************************************* *
* Main01 *
* *
************************************************** *
The intent of this program is to demonstrate the passing of parameter data using both local and global variables
Addtionally is an attempt at using the @ symbol to pass data between objects.
Runs very easily on a Prop Demo board
}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000

OBJ

LO : "LowerObject"
PST : "Parallax Serial Terminal"

VAR
long a,b,c 'A few global variables

Pub Main
pst.start(115200) 'Starting and running the PST

a:= lo.StartCountUp 'Start CountUp Method in another Object, in another Cog
'Count Up represents some other process running in a separate object, separate cog
'whose information is needed in Main method. Could be a Compass, speed sensor,
'whatever. In this case it just simulates data changing in another cog

'HOW DO I BEST GET THAT DATA BACK INTO THE MAIN OBJECT?
repeat
pst.dec(a)
pst.char(13)
waitcnt(clkfreq/2+cnt)





{
This is a simple object that can run in a another cog(s)

}

VAR
long stack1[100], stack2[100] 'Cog stack space
long countstack[100]

byte cog[3] ' 3 Cog ID's

Pub StartCountUp :success
StopCountup
success:= (Cog[2] := cognew(CountUp, @countstack) + 1)

Pub StopCountup
if Cog[2]
cogstop(Cog[2]~ - 1)

Pub CountUp : Z

Z:=0
dira[16]~~ 'indicates method and cog are in fact operating
repeat
Z++
!outa[16] 'indicates method and cog are in fact operating
waitcnt(clkfreq/2+cnt)

MagIO2
03-29-2012, 06:08 AM
First of all a question for the object:
Why do you have 3 stacks and 3 bytes for storing the COG ID?
Your start and stop functions don't support starting 3 COGs!

Does it make sense to have 3 COGs started by the object?

Well ... it depends! If all 3 COGs would do different things that work hand in hand it makes sense! For example ... hmmm ... let's say you have a device which has a very complex interface protocol which does not fit into one COG. You could start a COG for IN and another for OUT and the object provides functions for IN and OUT making use of both COGs.
If on the other hand all 3 COGs do the same thing, only with different Pins, it's better to let the main create as many objects as needed and not code something which is only true for your current project. For example: Full Duplex Serial.

In your case I guess that starting 3 COGs is only needed in this special project and for the object it would be better not to have this project specific setting hardcoded.



{
This is a simple object that can run in a another cog(s)

}

VAR
long stack[100]
byte cogID

Pub StartCountUp :success
StopCountup
success:= (CogID := cognew(CountUp, @stack) + 1)

Pub StopCountup
if CogID
cogstop(CogID~ - 1)

Pub CountUp : Z

Z:=0
dira[16]~~ 'indicates method and cog are in fact operating
repeat
Z++
!outa[16] 'indicates method and cog are in fact operating
waitcnt(clkfreq/2+cnt)


If your main needs 3 of these running it can simply use:


OBJ
Lo[3]: "LowerObject"

PUB main
lo[0].StartCountUp
lo[1].StartCountUp
lo[2].StartCountUp



If you need data from the COG to be showing up in the main you have several options. First of all you can use getter and setter functions (assuming that Z is what you are interested in):


{
This is a simple object that can run in a another cog(s)

}

VAR
long stack[100]
long Z
byte cogID

Pub StartCountUp :success
StopCountup
success:= (CogID := cognew(CountUp, @stack) + 1)

Pub StopCountup
if CogID
cogstop(CogID~ - 1)


Pub getZ
return Z

Pub CountUp

Z:=0
dira[16]~~ 'indicates method and cog are in fact operating
repeat
Z++
!outa[16] 'indicates method and cog are in fact operating
waitcnt(clkfreq/2+cnt)

You have to move Z from the local variable space to object-global space which is the VAR-section. If it's local only CountUp knows where to find Z! Moving it to VAR, the variable is also accessible by the getter-function.

In your main you can call lo.getZ whenever you need to know tha actual value of Z.

Or you create the object in a way that it directly changes the value of a variable defined by the main:


OBJ
lo : "LowerObject"
VAR
myOwnZ
PUB Main
lo.StartCountUp( @myOwnZ )
...


LowerObject:


{
This is a simple object that can run in a another cog(s)

}

VAR
long stack[100]
word zPointer
byte cogID

Pub StartCountUp( whereIsZ ) :success
StopCountup
zPointer := whereIsZ
success:= (CogID := cognew(CountUp, @stack) + 1)

Pub StopCountup
if CogID
cogstop(CogID~ - 1)

Pub CountUp

long[ zPointer ]:=0
dira[16]~~ 'indicates method and cog are in fact operating
repeat
long[ zPointer ]++
!outa[16] 'indicates method and cog are in fact operating
waitcnt(clkfreq/2+cnt)

This way myOwnZ, from main's point of view, is updated by magic ;o) Remember, each instance of an object has it's own VAR-section, so each one has it's own stack, it's own cogID and it's own zPointer.

One thing is left: If you have 3 instances of this object all 3 would still operate in the same indicator-pin (PIN 16). Maybe you want to fix that by yourself?

SteveWoodrough
03-30-2012, 01:51 AM
Oh my gosh, this is starting to make sense! THANK YOU!! for taking the time to explain it so well and with two different approaches. Sorry about the Cog [3], that was a bit of code that did not get trimmed down.
Steve

How do I change this to SOLVED?

Sapieha
03-30-2012, 03:41 AM
Hi Steve.Reedit

Yours first post in Advanced mode



Oh my gosh, this is starting to make sense! THANK YOU!! for taking the time to explain it so well and with two different approaches. Sorry about the Cog [3], that was a bit of code that did not get trimmed down.
Steve

How do I change this to SOLVED?