idx := ||lottery // 32 + 1
if (count > 0) and (count =< 32)
Starting from the top, we can see that this object —
our top object — has a child object called term that is of a
FullDuplexSerial type. Let’s skip past this for a moment
and come back to it.
In the VAR declaration section, we have a long called
stars. Variables declared in the VAR section are global to
the object; that is to say that any of the methods in the
object have access to them. While we’re not doing it now,
we could access stars from the main() method, as well as
from the printstars() method.
In the main() method, we have two local variables:
lottery and idx. The only code that has direct access to
these variables is in main(). If I wrote a line of code in
printstars() that attempted to use lottery or idx, the
compiler would complain. This is what we mean by scope:
it refers to the access of a variable. Some variables have
global scope, some are local. On the storage side, all
variables for Spin code are stored within the 32K hub
RAM; it is the compiler that prevents local variables in one
method from being [directly] accessed by another
In Spin, local variables can have the same name as
local variables in other methods; the local scope prevents
conflicts. What we cannot do is give a local variable the
same name as a global variable in the object as this would
create a conflict for the compiler. I try to give most
variables unique names but as in this case, there are
generic names I use for local variables that have meaning
to me. For example, lottery for random numbers and idx
for an array index or generic counter.
At the top of the our listing, we declared an object
called term that will handle serial communications to a
terminal program. If we open that object, we’ll see that it
also has a global VAR section. With these variables
defined in a VAR section, do we have access to them from
our top object in the main() and printstars() methods?
No. As I stated earlier, global variables are only global to
the object in which they are defined. A child object
usually provides access to its variables through custom
methods. The benefit of this strategy is that a child object
controls what it reveals to its parent.
It may seem a bit of a hassle to have to write a
method to expose the value of a variable in the child
object, but this is really for the best. Imagine if variables in
a child object VAR section became global to a project in
which the object is used. It’s likely that we’d have all sorts
of naming conflicts in the project, rendering the use of
separate object files, well, useless.
WHAT’S YOUR ADDRESS, MAN?
I have deliberately used the term “direct access” a
couple of times — let me explain why. As I indicated
earlier, all Spin variables are stored in the hub RAM. It
stands to reason, then, that we should be able to get to
any variable from any piece of code. We can ... if we
know that variable’s address.
You may see code that looks like this:
pntr := @myVariable
The symbol tells the compiler to move the address
of myVariable into pntr; without the symbol, we would
copy the value in myVariable to pntr. This is tricky at first
but really useful. If we know the address of a hub variable,
we can get to it from anywhere — even from anther cog.
To write a value to a known address, we could do this:
long[pntr] := someValue
This bit of code tells the compiler to write a long (four
bytes) to the address stored in pntr. We can also write
words and bytes. This technique allows objects to update
variables in other objects, even when normal scope rules
would prevent it.
Of course, we can also read a value this way:
someValue := long[pntr]
Knowing the base address, we can treat the hub RAM
as an array, as shown above. In this particular example,
the second word after the location indicated by pntr will
be moved into someValue.
It should be clear that the key to allowing one method
or object to access variables in another — even from
another hub — is to share the address of the variable(s)
you want to allow access to.
Let me give you a real-world example: I’m working on
a pan/tilt controller for my buddy, Lou. The circuit includes
an MCP3208 ADC chip. In Lou’s project, I want the
joysticks to be read every millisecond and automatically
update an array that is part of the main program. The
ADC object I’m working on (in PASM, hence runs in
another cog) uses the following call to initialize:
analog.init(CS, CLK, DIO, @joysticks)
The first three parameters are the pins used by the
January 2011 15