@ Simple Concept
SteveWoodrough
Posts: 190
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 Ive 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
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 Ive 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)
Comments
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.
One problem I noticed is this line.
Since your array "Cog" has two elements, you only want to access elements 0 and 1.
Element "2" is not part of the array so it will overwrite some other memory position.
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 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: 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: 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: 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)
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.
Thank You
Steve
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.
If your main needs 3 of these running it can simply use:
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): 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:
LowerObject: 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?
Steve
How do I change this to SOLVED?
Yours first post in Advanced mode