We now have an object in our
project called “uart” that — once
started — gives us buffered serial
communications using another cog
(which means it can do things
without affecting the program
running in the main program cog).
What we’ve done, in essence, is
added a serial coprocessor to our
system. Pretty cool, huh? It gets
The Parallax philosophy is that support objects, i.e.,
those that are not intended to stand alone, will have a
method called “start” that is used for instantiation. The
start method will usually return True (-1) or False (0) based
on the success of the code at start. Note that there is no
hard-and-fast rule on this, it’s just the current convention.
Since PC_Debug is also designed as a support object,
it will also have a start method. Here it is:
Now we just need to assign the
terminals to different Propeller I/O
terminal.startx(1, 0, 57600)
■ FIGURE 1. Object Hierarchy.
PUB start(baud) : okay
okay := uart.start(31, 30, baud)
In this case terminal. is using
the default programming pins (A31
and A30) at 9600 baud, and termi-
nal. is using A1 (for RX) and A0 (for TX) at 57,600 baud.
Keep in mind that underneath the terminal object is the
FullDuplex UART object that requires its own cog, so the
definition above would require two free cogs to operate.
Let’s get back to our PC_Debug object. Again, this is a
wrapper for FullDuplex that adds features convenient for
sending data to a terminal. Since the FullDuplex object starts
a new cog, it also has a method for stopping that cog and
making it available for other processes. By convention, this
method is called stop and we simply provide access to it.
This is a simple method, and yet a lot is happening. We
start with the PUB declaration — we need this method to
be public so that it can be accessed by higher-level objects.
This method is expecting a parameter called baud. Note
that no matter what size we need, a parameter is always
passed as a Long. This method will return a value as well;
the variable after the colon (okay) is what will be returned.
Return values are also Longs but can be caste to smaller
sizes (Word or Byte) if needed.
The code now is just one line: we’re assigning the
return value of the uart.start method to okay. As we can
see, Spin uses the dot notation found in other object-oriented languages. We can also tell that the uart.start
method expects three parameters: the receive pin, the
transmit pin, and the baud rate. What we’ve done here
is started the uart object using the Propeller’s standard
But what if we’ve got an extra port on our PC and would
rather send information to it using a couple free I/O pins?
No problem, we’ll just create another method.
This may seem redundant but, in fact, it’s not. You see,
any program (top object) that uses PC_Debug will not
direct access to methods in FullDuplex — we must explicitly provide wrappers for them. The good thing about this is
that we can provide wrappers only as needed and leave the
other methods (even public ones) protected to a degree.
Figure 1 shows the object hierarchy of our completed
project. Note that PC_Debug_Test does not have a direct
connection to Full_Duplex.
As you look through the PC_Debug object, you’ll see
that that are several other wrappers for objects in
FullDuplex. They’re self-evident and we don’t need to
describe them all in detail.
Let’s jump into the custom methods that are at the
purpose of our project: converting values to strings so that
we can send them to a terminal program. Since we’ll most
frequently use decimal values, let’s start there. The following method will print a signed decimal number:
PUB startx(rx_pin, tx_pin, baud) : okay
okay := uart.start(rx_pin, tx_pin, baud)
As you can see the startx (x for extra) method
simply passes along the desired pins with the baud rate.
Using this method we could actually open more than one
terminal at the same time (using different ports on our PC,
of course). Spin even lets us define an array of objects, so
we could do this:
terminal : “pc_debug”
PUB dec(value) | div, zpad
if (value < 0)
div := 1_000_000_000
if (value => div)
out(value / div + “0”)
value //= div
elseif zpad or (div == 1)
div /= 10
May 2006 75