The Propeller microprocessor is a computer developed
and produced by Parallax Inc. It is a 32 bit computer
running at 80 MHz. Its most important feature is that
it has eight individual processors, called cogs,
which operate in parallell. When all these processors
are working, the total capacity of the machine is thus
More importantly, however, the eight parallell processors allow you to work easily and nicely with real time systems, controlling and interacting with "real things". You can avoid the interrupt concept, with all its pedagogical difficulties and pitfalls. Instead, you assign a dedicated processor to monitor events from, say, a sensor. When it detects the event it can grab some external signals and then invoke computations in the other processors in a very versatile and transparent way. For the monitoring there are instructions that monitor an event in a single instrucion, so that the computer stays within the instruction until the event happens.
The processors communicate with each other over a global memory. This memory is connected to the processors in a round robin fashion, thus avoiding the risk that two processors try to access the memory simultaneously. To allow constistent transfers of data chunks with more than one word, there is a semaphore concept.
The processors communicate with the external world over 32 I/O pins which are programmable to be either input or output pins. There is a simple scheme for resolving conflicts between several processors accessing the same output pins. All input pins are simultaneousy available to all processors.
The processor also has a real time counter, running through all the values of a 32 bit word in a few minutes (after which it overflows and restarts), and wait instructions that halt the processor (cog) until the time counter has reached a specified value. In this way it is possible to contruct very accurate real time functions.
The Assembler language of the processer is available to the user through the Propeller Programming Environment (even though in some sense it has to be encapsulated in a Spin program). Here is a sequnce of four instructions which can illuminate some special features of this assembler language:
The Propeller computer is supplied with another
language at a higher level, the Spin language.
It is an interpretive language. This means that the
programmer is not running his own code. He runs an
interpreter, resident in the propeller, which interprets
the Spin code (somehow encoded into 1:s and 0:s).
This interpretive principle facilitates the design of a nice high level language. But the whole method is slow.
Given a high level Spin language and a fast Assembler language, the natural approach would be to write time critical functions in assembler, and connect them through a Spin program. To my understanding, this is not the way Spin and assembler code work together. The Spin "call" to Assembler code amounts to that a cog is started to run from the machine adress of the indicated assembler code. But there is no return instruction to return to the Spin code.
An interest I had in stack programming several years ago,
led me to try to design a stack based higher level
language, that could be compiled into assembler. I was
also inspired to this by someone, who had made a FORTH
programming language system for the Propeller. FORTH
is a stack based programming language, and so is my
language, called MYRA. A documentation of this
language is found here.
But here are some introductory comments.
Stack based programming means that one has a stack to which one piles up data,and from which one fetches data. These data are all 32 bit words, and there is no typing of data. There are producers which pile (or push, as the term is) data on the top of the stack, and there are consumers who take (or pop, as the term is) data from the stack. But they may only take data from the top of the stack. Thus, when a consumer has consumed one item from the stack, the item under it is reachable for the next consumer. Most things in a computer program are functions, and functions are both consumers and procucers. They consume the argument for the function, compute the result and produce the result on the stack. This interface works for both standard operations like + and for functions written by yourself. The latter can be functions written in MYRA, and functions written in assembler. The functions written in MYRA can be written inside the main program code, or they can be localized to external, so called, object files. Assembler routines are written into an assembler resource file, and at compilation these functions are put into the compiled code as needed. This "universal interface" to functions seems to me to be most important advantage of stack based programming.
The intended meaning of object files, is that they should contain functions useful to interface with some object, like a display, a sensor etc.. If you have an object file for a display with functions for handling the display, you can effectively hide the details of display handling in the main program. To make this transparent, you should also name functions in object files with object "dot" notation, disp.write.
A function that most objects would contain would be an initialization function obj.init. When you call it, the call can look as follow:
Here is the software you have to download in order to use the Myra language:
I developed the MPS language for the Propeller recently,
in order to get faster code. Historically, however, MPS
is several years older than Myra. In the early 1970:s
I wanted to build my own computer. At that time, one could
buy a chip from Intel called 4004. It was a 4 bit machine.
To add two 16 bit numbers required a full page of programming
code. So I decided to build the computer myself from
loose integrated circuits (counters, adders, shift registers
etc.) The computer got the name Computer 108, as the
computer in the Swedish fighter aircraft Viggen (JA37) was called
computer 107. For it I developed the MPS language, which
was short for My Programming Language in Swedish.
Now, some 40 years later, I have adapted almost the same language for the Propeller computer. Myra worked on a computer model with a stack, but the Propeller doesn't have a stack, so the stack has to be simulated, which is costly for execution speed and program size. Computer 108 just has a single register, accu, in which the result is accumulated. Then most instructions refer to
The general structure of MPS is the same as for Myra.
There is a system line, declarations of global variables,
an exec lines, which describes how processes are
executed (in parallell and in series), and then a
number of processes, starting with the "process" keyword,
and ending with a "\". In the process, functions can
be called. Functions can be allocated in object files,
now with the filename ending with ".mpo".
A difference is that the MPS system doesn't have any assembler resource file. As MPS code comes very close to assembler code in effectivitiy, there is virtually no assembler code in MPS, but everything is written in MPS. The functionality of the assembler resource file, is put in the object file std.mpo.This object file is used as any other object file.
There is a possibility to write "in line assembler code" in MPS, but this is used very sparesly, and is incapsulated in functions in object files.
With this mentioned, the differences between MPS and Myra code, appear in executable parts of processes and functions (what comes after the 'begin' keyword).
In the executable parts of the program, instructions are separated with blank spaces and with line feeds if one wishes to structure the code on several lines.
Unary instructions act solely on accu. Hence they don't mention any other operand. The unary operands are:
The propeller computer allows every instruction to
be executed conditionally. In Myra I used this fully.
Whether the execution is done or not is based on
two status registers in the computer. This could be
dangerous, if some instruction in a conditioned chain
of instructions happens to change the status registers.
Subroutine jumps are particularly suspect here, because
they look innocent, but you never know what a subroutine
does to the status register, unless you look at it in
To avoid this, MPS was made in the opposite spirit. No instructions are executed conditionally, except jumps. If we separate the condition from the instruction, we are talking about only one type of jump here. Subroutine jumps are not conditioned. The format of this conditional jump is:condition:target. Execution goes to target if the condtion is satisfied. The target is expressed as a label, which we shall return to in a minute. The conditions are the following:
The Propeller has a DJNZ instruction, that combines decrementing an index with a conditional jump. As it does pretty much in a single instruction cycle, it is worthwhile to encapsulate it in an MPS instruction. It is in a sense a binary instruction, as it has two arguments, but none of them is accu. This is how you write it:
Incrementing a number x by one can be done withe the code:
The nicest use of the stack in a stack based language like Myra, is to transfer parameters to functions (and back). In MPS we have to manage anyway. If we transfer only one argument, we can use accu. For transferring more arguments, we have reserved some more variables, called arg0 to arg5. We load these variables, and jump to the function. Then the function can find its arguments there. The syntax for this is as follows:
Arrays are handled with a so called index register.
The index register is a variable. like accu,
called index. This register is set by an
MPS instruction with a pair of brackets. If there
is a variable name between the brackets, the value
of that variable is loaded into the index register.
An expression, i.e. a sequence of MPS instructions
is not allowed between the brackets. However the
content between the brackets may be empty. In that
case, the value of accu is loaded into
index. In this way the value of index
can be computed as an expression. There is, however,
a weakness with this, that we will return to.
The instruction, that imediately follows the bracketed instruction, now modifies its adress by adding the value of index. Hence, one can point oneself into an array. For getting the i:th entry in the array arr, we could write
'L0' ("Local zero") is an aliasname for the first memory cell in the cog memory of the current cog. Hence L0 is also the name of an array that fills out the entire cog memory. With this, here are two ways of getting the i:th entry of the array arr:
The propeller computer doesn't have any analog inputs.
Its cousin, the Basic Stamp, handles analog inputs by
means of RC circuits, which convert analog voltages to
times. Times can be measured accurately with both
Basic Stamps an Propellers. So I guess, one can use
a similar design for the Propeller. However, one needs
one pin for each analog input, and probably one more
input to discharge, or precharge the RC-circuits.
So my alternative has been to use separate A/D converters. My favorite is Microchip's 3208. It converts 8 channels to 12 bit digital data. It has a serial interface. You need to handle a chip select pin, a clock pin, one data-in-pin and one data-out-pin. So for 8 analog channels, you need 4 pins. If 8 channels aren't enough, you can get 16 channels for 5 pins etc..
You send a conversion order to the converter's data-in-pin. This order announces which channel should be converted. Then you can clock your digital result from the converter's data-out-pin. This is best written in assembler. The interface is like this:
D/A converters are available, but they waste a number
of output pins for a single analog output channel. The
normal way of creating analog outputs is therefore by
pulse width modulation (PWM). There is a pulse repetition
frequency (prf) for the pulses. Then the pulse is on
for some percentage of the total period, and off for the
the rest. Afterwards, you can remove the pulses with
a RC-circuit, and just keep the average, which will
be an analog signal. But if the output goes to, for instance,
a motor, the motor can filter out the pulses with its
mechanical inertia. In that case, you may need to
raise the prf to well over 10 kHz. Otherwise you will
hear the prf from the motor. The time constant of the
RC circuit or the motor will limit the bandwidth of
the output. You need a margin between the desired bandwidth
and the prf, but for mechanical systems, this is usually
not a problem.
Here's an example. We want to control two motors, and we want to drive them in both directions. Assume that we connect motor 1 between pins 0 and 1, and motor 2 between pins 2 and 3. We can drive the motors with codes like this:
We now want to connect power drivers to the Propeller output pins, and connect the motors between the outputs of the power drivers. This structure is sometimes called an H-bridge.
Here's a solution based on an integrated circuit
TDA2050 is marketed as an audio amplifier, but it is actually a universal operational amplifier, with capability to deliver high power. It amplifies the difference between the + and --inputs with a gain of one million or so. Then we can reduce the gain with a feedback through the resistors R2 and R1. We would like to create a gain of about four, to increase the 3.3v span of the Propeller to an output span of 12v. But with the TDA2050 you can't reduce the gain that much without getting oscillations. A gain of about 40 is minimum. So we live with that, and reduce the input signal first with RI and RT.
RC and CC make up a capacitive load, also to enhance stability. The capacitor CV shall eliminate spurious feedback between the different steps of the amplifier over the 12v supply rail. It should be placed physically close to the circuit.
The capacitor CT together with (essentially) RT helps remove the pulses from the PWM-system, and just keep an average. We have time contant of appoximately 500μs, which should filter out the pulses with a period of 100μs pretty well. At the same time, such a time constant shouldn't cause any stability problems for the mechanical system.
The question is still, if the capacitor CT should be there. With the capacitor in place we avoid hearing a tone from the motor. At least cats may appreciate that. Perhaps we save the motor from some wear. And we avoid disturbing the electrical environment around our device. The penalty for all this is heat dissipation.
Without the capacitor, we drive the TDA2050 in full saturation all the time. The output transistors are either fully on or fully off, and hence consume no power. However, such operational amplifiers are not so fast, so they spend some time in the transition phase, so some power is still dissipated.
With reasonably small motors, both solutions should work, but you need a heatsink for your amplifier, and free air flow round the heatsink. TDA2050 and many other modern circuits have the advantage that the cooling tab is connected to ground, so you can without risk screw all the circuits firmly to the same heatsink.
An alternative for even higher power is to use
a IR2103 circuit, which is a FET-transistor driver from
International Rectifier. Here's a quick sketch of how
it is connected.
To drive the upper FET to open, you need a gate voltage a few volts over the drain. So to bring the output all the way up to the E volt rail, you need more voltage than E somewhere. In fact, the upper FET is driven by a little circuit, that sits between the terminals O and X. X should be 12 volts higher than O. The question is, how we get that voltage there.
A hint is to think about a so called charge pump, as in this figure:
C1 and D1 will clamp the voltage at P never to be under the rail voltage. (12 volts). Consequently the voltage at P will vary between 12 volts and 17 volts (as 5 volts is the amplitude of the oscillator). D2 and and C2 will rectify and smoothen this signal to give a voltage 5 volts over the 12 volt rail. This works fine, but it probably doesn't work unmodified, if we are going to pump a voltage over a rail, that moves all the time. That is the situation we have with our IR2103 circuit.
The conventional way to provide the X voltage is to use the systems output signal as charge pump oscillator. Here's the way it is done.
When the output O is all the way down to zero, the capacitor C will be charged through the diode D. Then, when O flies up, C will fly up with it. It will gradually discharge, though, so O will have to go down to zero every now and then. This is a constraint for the programming of the device. With the PWM, the pulse width must never be 100% of the full period. This is OK, but it may be easy to forget, when you make your programs.
Hence it would be nice if we could design a system with an independent oscillator for the charge pumping. It's open for invention. With a little luck, we could maybe use one oscillator for all IR2103-circuits around.
IR2103 is a purely digital system. The input is truly digital, so there is no way, that you could smooth away the pulses with capacitors. The circuit is fast, so the time in transition between the two saturated states is short, and the switching is also synchronized, so that both FET:s are on simultaneously only for very short periods.
The most dramatic property of this circuit is, however, the bound on the voltage E. E can be as high as 600 volts! With 600 volts supply, these 600 volts penetrate right into the IR2103. It's a tiny 8 pin dip-circuit, or an even smaller surface-mount version, but it is said, it can take it. Beware however! Your circuit board design might not tolerate 600 volts. Maybe you dare to work with 200 volts. You easily find FETs that can handle 7 A (with some cooling). Then you can control 1.4 kW power from a 3.3v output from a Propeller pin. That's pretty awesome.
RS232 is a very old protocol for communication. It has
changed name now to EIA232, but very few people seem to
have noticed that. It is a standard for serial communication
over only one line (per direction), where the bits
are sent after one another in time. It was fairly specific
about voltage levels, and it had several options for flow
control, so that a receiver could inhibit data sending,
when it was too busy. Surprisingly for a one line concept,
the protocol was standardized for a 25 pin D-sub connector.
The standard was also pretty open, when it came to
different parameters like number of bits sent, parity,
sign on start bit, communications speed etc..
Luckily a certain set of parameter values have become de facto standard, so now we communicate with a large number of devices and modules, with almost the same communication parameters. At the same time, the voltage level issue has become less important. Most devices use 0 volts as 0, and 5 or 3.3 volts as 1. But if you buy a true standard RS232 device, and connect it to a Propeller computer, the Propeller will be destroyed, as the voltages are too high.
If I can, I always avoid flow control, as it complicates things (more wires, more Propeller pins used etc.) Most devices can be configured so that flow control is not used.
The standard allows parity control, but the most common choice is "no parity", which simplifies your software. You don't need to set parity bits, and you don't have to check them (you never have to check them, even if they are there).
The most common communications speed nowadays is perhaps 115200 bits per second, which is about what today's processors can manage. But the default setting is often 9600. Conventionally these bit rates are called baud rate, and the unit is baud, and not bits per second. So we have 115200 baud etc. (The reason for this is that the term bits/second is reserved for the effective speed of a line with disturbances. If there are disturbances, you have to check and resend, and you loose speed on that.) Some devices can tell you which baud rate they are set to, but if you don't know the baud rate, you can neither put the question, nor interpret the answer. Most devices have some sort of reset button, which restore default parameters, like 9600 baud. For the eventuality that you have abandoned the default parameters, and happen to press that button, you have to have a little reconfiguration program up your sleeve. This is a maintenance problem for your system.
Then, the normal standard is that the line is 1 when it is idle. A new transmission is announced by the line falling to 0. This is the start pulse. Then you wait one and a half of TS, where TS is 1/(baud rate). Then you can clock in yor data every TS, least significant bit first. The standard is that one such package of bits is 8 bits long. Then follows an optional parity bit and one or more stop bits. When it's all over the line goes up to 1 again. It is not terribly complicated to build and read such a pulse train, if you have computer. To do it with conventional hardware was probably quite complicated.
On the Assembler Resource File there are two programs called send and receive. They are called lik this:
I2C is a bus standard invented by Philips. I2C means
Inter Integrated Circuits, and is thus a bus for communication
between individual circuits in an electronic system. It is
a master/slave concept, where a master controls the
trafic on the bus. In the general case, there can be more
than one master on the bus, which calls for an arbitration
policy to divide the bus between the masters. However, in
most cases, there is only one master.
The bus has two wires, one data line and one clock line. The slaves and the masters are connected with open collectors. Consequently, when a device tries to send a '1', the collector is open, and thus, the impedance is infinite. The voltages are pulled up with a set of pull up resistors, which belong to the bus.
The role of master in our application, will most likely be played by a Propeller computer. The Propeller doesn't have open collector outputs, but we can mimic this by using the direction register. We permanently set the output to the pin to zero. When we direct the pin to be an output pin, zero with low impedance will be visible on the pin. When we direct the pin to be an input pin, a high impedance is visible, and the pull up resistor of the bus will pull the line high. When we expect inputs from the line, we should set the pin to 1, i.e. high impedance. When we send data to the device, we should expect an acknowledge signal from the receiver. At that moment the master should have high impedance, but there is no harm if we forget that (except that we mislead ourselves to beleive that the acknowledge signal has come).
To send data to a slave, the master will send a start pattern, followed by an address to the receiving device, and a write bit. After this the master will send the data on the bus. Data (and address) are clocked, in the sense, that the slave should trust what's on the data line, when the clock line is high. The slave will finally respond with an acknowledge signal, and to receive this, the slave has to turn its datapin into an input pin.
The protocol for receiving data to the slave is slightly more complicated.
We will return to more details about the I2C bus in the radio application. There you will use assembler routines on the assembler resource file to handle the I2C bus. Formally, when you use the I2C bus for comercial use, you should pay a license fee to Philips.
USB, Universal Serial Bus, is an almost indispensible
protocol, as it is almost the only way to talk
to a PC nowadays (specially a laptop). It is a complicated
protocol though. It is a master slave concept, where the
master is called host, and the slave is called device.
Writing a host software for USB is certainly not easy,
but we get it for free, when we by a PC. But writing
device software is not easy either.
Fortunately, there is a Scottish company, called FTDI, that has made the jobs for us, in the form of integrated circuits, and hybrid modules. Most of them wrap an RS232 interface into a USB interface.
In the other end, in the PC, the RS232 reappears again as something called Virtual Com Ports. They behave as good old RS232 ports, but there is an arbitration of port numbers, that can cause the programmer some troubles, specially when the port number exceeds 10. As a Java programmer, I regret that there is no USB object available (it has been anounced), so I have to use Java Native Interface and C code.
An alternative to Virtual Com Ports, which is said to be faster, is called D2XX, which is a series of DLL:s to access the data.
FTDI also produces a module, where 8 bits a time are loaded in parallell. This allows a rate of at least 1 MByte/s, where the limit seems to be on the PC side, at least if one uses the Virtual Com Port concept.
The propstick and propclips, which are used for programming the Propeller, also contain FTDI circuits. They are probably RS232 circuits, with an extra ability to handle a Propeller reset signal.
The standard IEEE 802.15.4 describes a wireless
communication protocol for the 2.4 GHz band, with
checks, resending and acknowledgement, so that data
are safely brought from one point to another. It more
or less acts as an RS232 connection, where the cable
is replaced with wireless communication.
On top of this standard, there has been built a higher level standard for communication in networks, called Zigbee. That's why I call IEEE 802.15.4 "proto-Zigbee". Zigbee is an advanced standard for building networks, where units beyond range can talk to one another by relaying over intermediate units. Important is also means for letting units go down to sleep mode, from which they can be wakened up on command. This is intended for battery driven data logging equipment and the like.
All these advanced possibilities are certainly usefull, but I have found much of it difficult to understand in detail, and handle. That's why I have stayed with "proto-Zigbee". Parallax have gone through different communication concepts and have chosen "proto-Zigbee" to be very easy to work with. Units are manufactured by Digi inc. previously Maxstream. But buying from them can be a little confusing, because it's hard to tell if you are buying Zigbee or "proto-Zigbee". Proto Zigbee is mostly called "IEEE 802.15.4 OEM-modules".
Proto Zigbee units are gathered in networks call PAN:s, Personal Area Networks, and each such PAN has its one PAN-ID. In the same place, there can be another PAN with another PAN-ID, and in that case, they are isolated from each other. Furthermore you can set which 2.4GHz channel you work on. You can set the role of the unit in the network. The simplest role is as an end-point. If your units are end-points, then they can communicate point to point with one another. You can also set the baud rate for communication between the unit and a computer. This is about what you need to configure in the first place.
When you buy units, they are configured to the same default PAN-ID, the same default 2.4GHz channel, and they are all set to be end-points. Then you can just connect your units to power and to two Propeller pins, and then you are ready to communicate between computers. What you send from one computer to one unit, arrives to the other computer via its unit. That's what we call cable replacement.
What you might like to reconfigure is the baud rate, and maybe move from default 9600 baud to 115200.
Once I bought three units, and later two more. But in the meanwhile, for some reason, that I have forgotten, I had changed the PAN-ID for my old units. So I had to spend some time reconfiguring. It took some time, but when I finally succeded, I had done it exactly as I had thought it would be done. So now all my units can talk to another. Among the object files there will be a simple program that may be helpful for reconfiguring units.
Say that you want to command a robot wirelessly. At the same time you want to upload sensor data to a PC, (which can also talk to Zigbee, it is RS232, but nowadays, you have to take the way over USB). There may be many ways to solve that. The simplest way, but maybe not the cheapest, is to have two PAN:s for the two tasks, command and data uploading. A unit can not belong to two PAN:s so you must have two units onboard the robot. This is a simple example of how you can use the simpler concepts of "proto-Zigbee".
Beside the simplicity ("point to point communication direct out of the box") proto-Zigbee has another important advantage: The units are cheap. You get them for something like 30 or 40 dollars.
Bluetooth is a complicated standard with a stack of
different profiles, for transmission of images, music
etc. One such profile is SPP, Serial Port Profile, which
is "RS232" in both ends. Like Zigbee, Bluetooth has checks,
acknowledges and resending to guarantee safe arrival of
data. Parallax marketed devices called Embedded Blue,
which you accessed through a RS232 interface. I found
them easy to work with, but they are now out of production,
and their replacers seem more complicated to interface.
The main drawback of bluetooth is however that the modules are expensive, about four times as expensive as the proto Zigbee modules.
Parallax markets some simple transmitters and receivers. They are truly cable replacements. When you set the imput to the transmitter high, the output of the receiver goes high. So you build your own RS232 link with that. The RF modules don't contribute with any security checking. I found that the transmission failed now and then. But I never found out how to pair transmitters and recievers in this system. There are new modules now which combine transmitter and receiver, and this could make it easier.
These are Myra Objects files, named "Name.myo", which contain functions, that are useful to handle things like sensors, displays, special number types and the like. These functions are used by a main program named "Name.myr".
This object file, "Num.myo", contains some numerical functions, They are far fewer than what is available in Spin. I have simply made what I have needed. The file contains the following functions:
This object uses Parallax' Intelligent Alphanumerical Display. It is somewhat expensive, but relative to a standard alphanumerical LCD display with Hitachi's interface HD44780, it does a good job, and it let's you interface the display with only one pin. The object has a field, which contains the number of that one pin. Here are the functions:
The code in the file "Graf.myo" uses a graphical LCD display,
which is controlled in a somewhat standard way. Such a
control consumes pretty many Propeller pins, so i chose
to give the display its own Propeller processor, hereafter
called the display computer. Another
computer, hereafter called the application computer,
interfaces with this with a serial link,
that sends a pixel pattern to the display computer.
The display is monochrome (white on blue) and has a size of 64 by 128 pixels. We put the pixel pattern in 32 bit words (long words), so we need 2 for each columm, or 256 long words in total. These 256 words are sent one word at time (32 bits) with a RS232 like protocol with a bit rate of 1 MHz. There are assembler routines for sending and receiveing according to this protocol.The pixel pattern has to be declared in both computers under the name gr. The declaration is written as
This is a very simple object, that handles a three color RGB-LED. The object file has only one function:
This is a relatively simple object for handling a standard
ps2 keyboard. The object normally only receives data from
the keyboard, but there is a historical circumstance, that
forces us also to send to the keyboard. The creators of
ps2 decided that the PC and the keyboard should synchronize
the following way. The keyboard would repeatedly send a
character, but with the wrong parity. Synchronization would
be established when the PC complained about this. So we
have to send such a complain message.
The user has to call the function key.init. He also has to declare two global variables key and keyp. Keys are scanned with key.scan. This program has to be alert at all times, as one never knows when the operator hits a key. Thus, it has to have its own process. The keycode for the key pressed the latest, will be deposited in the variable key. Keycodes are seemingly arbitrary numbers assigned at the dawn of computing. The A-key has its number, as well as the shift key. The latter would enable us to distinguish 'a' from 'A', but we don't care about that here. When a key is released, key will assume a value called 'break'.
Now, we can call the function key.ascii. It will translate the key code to the corresponding ascii code and push that on the stack. As long as we keep a key pressed, we will thus find its ascii code on the stack. If the key is released, the keycode will be 'break' and then key.ascii will return 0, which is the ascii code for the null character.
In higher mathematics, a complex number is defined as a pair, (x,y), of real numbers x and y together with the following addition and multiplication rules:
(x1,y1)+(x2,y2) = (x1+x2,y1+y2)Then, there is the style, to write (x,y) as x+i·y. We think of x + i·0 as just the real number x. We call 0 + i·y just i·y, and 0 + i·1 just i. Now, if we take (0,1)*(0.1) alias i·i alias i2 and use the above multiplication rule, we find that i2 = -1.
(x1,y1)*(x2,y2) = (x1*x2 - y1*y2, ,x1*y2 + y1*x2)
This is really an untested group of functions,
so right now, I don't give any closer details.
Floating point representation means that a number is written as m·2exp, where exp is chosen so that m, called the mantissa, is a number between a half and one. IEEE has standardized floating point numbers, so that the mantissa and the exponent are packed into one 32 bit number. That leaves 23 bits for the mantissa, which is somewhat little, so now double precision floating point numbers are popular. To keep precsion and make things simpler, we store exponent and mantissa in separate words. They are put on the stack with the exponent highest. With this double pushing and poping, floating point operations can be made as normal fix point or integer operations.
Download float.myo (untested)
This object handles an accelerometer, which delivers
its results as pulse widths.
Accelerometers never measure acceleration only. They measure the sum of acceleration and gravity, i.e. they measure one component of this vector. Hence, if the accelerometer isn't moved very vividly, it can be used to measure tilt. When the accelerometer is tilted, a no longer horizontal accelerometer will measure a component of the vertical gravity vector.
I used this to make a simple joystick. It has a vertical plastic tube with a horizontal accelerometer mounted between some foam rubber pads. At he bottom of the tube, there is a heavy plane brass foot. If you leave the joystick on the table, it will show nothing (except some bias), but when you grab and tilt it, it will show the tilt angles.
The object contains a censor function which eliminates sudden spikes in the signals. Biases can be eliminated by calling the acc.cal function in a situation, when the accelerometer shouldn't show any acceration (the joystick resting on the table). The signal is scaled as a number between 0 and 4096, with 2048 representing zero signal.
Odometry comes from a Greek word for "way" or "road",
and it is the art of determining travelled distance.
To do it we have a striped strip and two optical sensors.
We can put that strip around a wheel of a robot, to measure
its travelled distance, or we can glue the strip on the
road itself, that we travel along. Here's how it works:
We have two pictures of a strip and two optical sensors (the circles) in both pictures. The strips move as indicated. In both these cases, the right hand detector switches from white to gray, which indicates a motion. But which motion is it, the upper or lower case? We can tell by looking at the left hand sensor. In the upper case it is white, in the lower it is grey. So now we can detect a motion "with sign", and we can accumulate the incremental motions to a distance travelled.
The Odo object odo.myo handles two strips and two sets of optical sensors, to determine movements in the plane.
These objects control IEEE 802.15.4 modules. Read about them here. The basic object is zig.myo, which contains the following functions.
This objects controls a little chip, AR1010, which contains a complete FM radio in a chip, 4 x 4 mm in size. The chip is controlled from a computer, and the object contains functions for that. We will however describe all the details about this in the FM radio application.
The linear camera is a camera that produces an image, 1 pixel high and 512 pixels wide. We will describe the functions of this object, while we describe the Linear Camera Application.
Once I made a box containing a Propeller Computer,
a bluetooth modem, an alphanumeric display, an SD card
reader and three power amplifiers. Unfortunately the
box became full of wires, and it wasn't easy to keep all
these wires intact.
So here's a more modest project. It is a smaller box which contains a Propeller computer together with the normal EEPROM and the normal 5 MHz crystal, an A/D converter, an RGB led for debugging etc., and circuits for voltage supply. Here's what the circuit board looks like:
Here's how the circuit board is connected to external connectors. I have always liked to use 9 pin D-sub connectors.
On this side there is a reset button, and a switch which disconnects the reset input from the PC connection. This is necessary if you want to send data from the PC, without resetting the computer every time. In the middle there is a programming connector. I only use 4 of the connection points there, and they go directly to the pins of a Prop Stick device, that I have built into a D-sub connector with housing. The right hand connector goes to 7 of the 8 analog inputs of the A/D converter. The remaining two pins of the D-sub connector go to ground and 5 volts supply. To the right on the top of the box, you can see the end of a plastic screw, that acts as a ray guide from the RGB-led.
On this side there are connections to 14 of the universal digital I/O pins of the Propeller. The left connector also has a ground connection and a connection to 3.3 volts. The right connector instead provides ground and 5 volts. Further right there is a small handmade connector for connection of the alphanumerical or graphical displays, which are housed in separate boxes. Rightmost is the supply input which receives an unstabilized voltage of 7.2 to 12 volts.
Bluetooth has been replaced with Zigbee, but the Zigbee modem is now placed on a D-sub connector. The power amplifiers are built into a separate box of the same shape as the computer. As mentioned, the two displays, the alphanumeric and the graphic, are placed in separate boxes.
Everybody who has a Propeller, or any other microprocessor,
wants to make his own robot. Here is mine:
It has two relatively strong 12 volt motors with gear boxes (1:21), two strong rubber wheels and a caster wheel in front, and a led battery, that I charge with a CTEK led battery charger.
It has three power amplifiers. They are built with discrete components, but they don't work at very high PWM frequencies, as they get hot. It's OK for this application to work with low frequencies, but I don't recommend these amplifiers. The alternatives mentioned previously are better. Anyway, you can see the coolers for the transistors as three aluminum bars on the circuit board.
The computer is a Spin Stamp, which is a surface mounted Propeller mounted on a hybrid circuit, which also contains a crystal (10MHz unfortunately, perhaps), voltage stabilizers, and an EEPROM. On the card, there is also a 3208 A/D converter, and two voltage stabilizers. One of them reduces the 12 volt battery power, not to exhaust the stabilizers on the Spin Stamp. The other provides 3.3 volts for some sensors. Unfortunately, the Spin Stamp doesn't make its own 3.3v voltage available externally.
In the front, there is a Lego block, on which I can put sensors and other stuff, mounted on small Lego blocks.
In the picture you can see a compass, mounted on a high Lego tower, to keep it away from the magnets of the motors, an infrared distance sensor, and a "proto Zigbee" unit. The whole robot is controlled over proto Zigbee from a remote control. I also have an infrared receiver, adapted to an infrared LED modulated to 38 kHz with a Propeller computer. So, there is an infrared control for the robot, but it requires that you direct the LED pretty accurately towards the receiver.
One thing I don't have is odometry sensors on the wheels. I once had that. You can read more about that in the description of the milling machine.
I am a specialist in autonomous control of unmanned vehicles, but as this is a hobby, I have made a robot completely free from all autonomy. It is a remotely controlled vehicle, basta!. But I did some experiments with a software, that would drive the robot to the nearest object. But that is not ready yet.
Otherwise the robot is pretty robust, fast and strong, though it can't compete with modern radio controlled model cars with brushless motors.
Here's the software RobotZ.myr
The first thing you notice is a "10 MHz" tag. That's because the Spin Stamp has a 10 MHz crystal, while the standard is rather 5 MHz. The Spin code, that is generated from the Myra code has to know that. So the Myra code uses the "10MHz" tag to modify the Spin code.
The process input receives the input from the Zigbee unit. It's a single number comm whose bits signal which buttons on the remote control are pressed.
The process motor's main program decodes comm and sets two motor masks and a velocity. The motor masks are each of two bits, and determine whether the motor will run forward (01), backward (10) or be stopped (00). The velocity is set lower if we turn the robot left or right, and higher when we drive forward and backward. This facilitates the driving. In the main program, there is also a call to a heading control function, heading, which drives the robot to a given heading, as measured by the compass.
The motor is finally controlled by the function drive. It sets the PWM duty cycle according to v (16 is full speed, 100% duty cycle). The motor masks merged together with shifts and an or instruction are sent to the amplifiers during the on period, and 0 is sent during the off period. The total cycle time of the PWM signal is 80000000/100 ticks, which gives a repetition frequency of 100 Hz.Fortunately we don't hear any 100 Hz tone from the motors, probably because of the inertia of the wheels.
The compass process catches the signal from the compass, which amounts to measuring the length of a pulse, that the compass electronics sends regularly. The scaling i 100μs/degree.
Finally a word about the heading control function heading. The control error is basically psi - psiC where psiC lies on the stack, and the measured heading is a global variable. But just subtracting angles is a little dangerous. 1 degree and 359 degrees are only 2 degrees away from each other, but the subtraction would give 358 degrees. So we have to "normalize" the result to within ±180 degrees, by adding or subracting an appropriate multiple of 360 degrees. Then we control the motor mask with the sign of the control error, and we control the velocity with a ramp function of the absolute error. (We use the || assembler function). The ramp function is difficult to trim, due to the friction of the motors. The motors don't run at all if the signal to them is too low. That is also why I haven't succeded yet with my "drive to the nearest object function".
The remote control is a box with buttons, a Propeller
computer with its crystal and EEPROM and a proto Zigbee
unit. It is driven with a 9 volt battery. At the back
side there is an on/off switch and a programming connector.
There are 7 buttons, which is less than 8, so the whole button pattern can be sent in one byte. For that, each button is connected to its own Propeller input pin.
This picture shows the wheel steamer
I built it together with my son, when we were in the country with limited technical resources. You can see, perhaps, that we are not exactly any expert naval architects. The ship is built in fur wood, and not plastic foam, so it is rather heavy. To keep it afloat, it is not a katamaran, but a pentamaran.
We found a small DC-motor as a main motor. To keep it away from the water, you can have a propeller with a long shaft, or a belt drive. But a wheel steamer was also a way to bring the motor up. We have only one drive wheel, placed in the middle of the ship, and built around a square hub.
Control is made with a rudder, which is driven with a little gearbox kit (for those who want to learn what a gear box is). It gives a slow enough movement to make the rudder controllable.
We also found a waterproof lunch box, in which we mounted the electronics, which consists of a proto Zigbee module, a Spin Stamp module, and a TDA2050 based power driver.
I don't publish any software here, as it is essentially the same as the software for the robot, although we have one drive wheel and a rudder here, while the robot has two drive wheels and a passive caster wheel.
I am the happy owner of the milling and drilling machine
you can see here:
It has a coordinate table with two cranks to move the workpiece in two orthogonal directions. I have mounted striped tape on the two cranks, and then I have mounted a pair of reflex detectors nearby. The reflexdetectors are from Polulu and intended for odometry. The following pictures show the arrangement more in detail:
Then i have coupled the reflexdetector to a box containing a Propeller computer and an alphanumeric display.
The software consist of odometry computations based on the odometry object as described above. With the stripes I have made, the resolution in table movement becomes 1/14 mm, but I have recalculated this, so that I get resolution of 0.1 mm. On the two first lines of the display, I show the coordinate table positions in tenths of milimeter. All coordinates refer to a reference point, that you set by going there, and then pressing the right hand red button.
The third line shows the distance to the referenc position. This is computed with Pythagoras' theorem and the num.itsqrt function for computing the square root. This function is of course usefull when you want to mill out a big circular hole. If the hole should have the radius R, and your milling tool has the radius r, you should move out to the distance R-r everywhere, but no longer.
Another thing that you maybe would like to mill, is an oblique straight line. You could define such a line by moving to two points on the line, and press the two red buttons. Then the display could show the distance to the line. This is a function I haven't made, but it would be possible.
The equipment is good for milling, but also for drilling where you could place your holes with good precision. In all, this is a very nice little equipment, that raises the value of the machine considerably. Of course, from this point one can go on and add motors, and make a numerically controlled machine. The following picture gives a little instruction for how to make a hole for a D-sub connector.
FTDI manufactures some USB modules, where data to be
transfered are loaded in parallell, one byte at a time,
rather than serially. On the PC side, data appear in
a VCP port, which makes data available one byte at a
time, or over D2XX. With this type of module, data can
be transferred faster than over RS232 emulators.
The module can handle the situation, that the USB bus is busy, by stacking up non sent data on a stack (a FIFO stack, First In First Out).
I have used this module to build a data logging system, with data display on the PC side, a so called USB oscilloscope. It works in two modes, a digital mode where one or more digital signals (being either 1 or 0) are transferred, and an analog mode where one or more analog signals are transferred. The advantage of the digital mode, is that it can sample data faster.
In digital mode, I can transfer 300000 bytes/second. The byte can contain up to 8 digital signals, which are read directly from the computer input pins. I have preferred, though, to use the 8:th bit for time marking. The last bit flips every 1ms with high precision. This allows me to create a very exact time scale on the PC side. Furthermore, I have chosen to pull out only two digital signal wires from the computer, but that is easy to change.
In analog mode, I have two operational amplifiers, to scale the inputs, and give them a symmetric range around zero volts, and then I use two channels of an 8 channel 12 bit A/D-converter (Microchip 3208). I make the A/D conversion, and the packing of data into bytes in one processor. A second processor handles the USB device. An analog data takes up 12 bits, and I pack that into two bytes. That leaves 4 bits free. I use the last bit for time marking, as in the digital mode. The remaining 3 bits contain the fix code of 101. The PC uses this, to recognize the least significant byte, so that it doesn't loose phase, and mixes the two bytes up. This describes how I handle 1 analog signal and two bytes, and that is what I do right now. With two analog signals, I have to reduce the sampling rate to one half. In analog mode, I transfer data at a rate of 66.666 kHz, but not all these data are new analog samples.
For both modes, there is a red trig button. Its signal is also pulled out, to admit electronic triggering. When the trig signal comes, 50000 data are transferred to the PC. Then the signals can be analyzed with an interactive plot program. There are different programs in digital and analog mode. In the digital mode, one sample covers 0.168 seconds of real time, in analog 0.75 seconds.
The fundamental principle here is one time triggering. You get one set of 50000 samples, to analyze afterwards, unlike a conventional oscilloscope, where you retrigger all the time, which gives you problems, when you have non periodic signals. Here, the problem is to trigger at the right moment.
The signals enter the oscilloscope through a 9 pin D-sub connector. At these frequencies there is no nead for high quality coaxial connectors. There are two probes, one for digital mode and one for analog mode. The software distinguishes the modes through a jumper wire in the digital probe. Then you have to select the corresponding software on the PC side. On the Propeller side, there is only one program, but if you change probe, you have to restart the device.
Here is a drawing of the electronics:
You can see the standard set up of a Propeller with crystal, EEPROM and prop plug. In the upper left corner you see the connection of the 3208 A/D converter. As it is connected to other pins than the normal you have to use the parametrized initialization init_analogp. The lower left part of the drawing, is the analog part of the system. We come back to that in a while.
In the upper right corner, there is the connection of the USB module, with the USB connector depicted as a gray square. The module is such, that you have to connect ground and power to a number of places externally. With the way it is done here, the whole apparatus will be fed from the USB output of the PC. There is also a 3.3 volt input, to make sure that the module outputs are constrained to 3.3 volts, so that the Propeller inputs are not destroyed. The 8 data pins are connected directly to the Propeller outputs 0 to 7. Then there are four control pins, which go to the Propeller, The Propeller software will handle these pins apropriately.
This is a simple program, that, depending on mode, uses the two assembler functions fifolog or fifoalog. These refer over the stack to the variable tstamp, which is the time marking signal, or x which is the word to transfer. It would seem natural that the references here would be through adresses #tstamp and #x, but these variables are variables in the common variables, and such variables are always transferred via adresses, that are used in rdlong instruction. It would be neater, if we could write #tstamp and #x, but it would be difficult to use that in the assembler functions. Otherwise, fifolog and fifoalog are simple 50000 times loops.
Here are some hints about the analog circuitry at the lower left of the diagram. To create a symmetric range of the analog input, we need a negative reference voltage. We use a chargepump, MAXIM 660 for that. The operational amplifiers are of type OP90. They can be driven with a single 5 volts supply, and they produce output "rail to rail" i.e. from 0 to 5 volts. The trim potentiometer should be trimmed, with the input disconnected or grounded, so that the output i exactly 2.5 volts. This is the middle of the A/D converter's range. Hence the ouput will be 2048. This number is then subtracted on the PC side, so we get zero output for zero voltage. Now, nominally, the trim pot value should be 390/2 = 195 kΩ. The all over impedance at the input is then 390/3 = 130kΩ. So if you let R be 130 kΩ, you get a gain of 1, and a range of ±2.5 volts. You probably prefer a range of ±5 volts, so you chose 260 kΩ. This is also the input impedance of the device. It is not so impressive, but probably good enough for most purposes. If you trust the precision of the 390kΩ resistor and R, you trim the bias and the gain at the same time with the trim potentionmeter.
Information and download of the PC java programs is found here.
The data logger makes the same job as the USB oscilloscope,
but without a PC. Instead data are shown on a graphical
display. The device is controlled from a standard
Data are stored in a, 4096 words wide, data area in the common memory, by means of an assembler routine logg.
Data are displayed with a program in the graf object (graf.myo) called gr.loggshow. It makes a pixelmap in the standard way for the graphical display in an area in common memory called gr, 256 words wide. This is then transferred to the graphical display for final drawing. gr.loggshow is controlled by 4 variables. The scaling in the horizontal and vertical direction is made as shifting an integer number of steps according to the variables tshift and fshift. The curves are also moved in both directions, so that the left hand edge corresponds to a time tstart, and that the low edge corresponds to a value flow. These parameters are controlled from the keyboard.
The keys used, have the following meanings:
When you look at a star with a telescope, the telescope
will rotate with the rotation of the earth. So to get a
stable picture, you have to rotate the telescope backwards,
relative to the earth. Amateur telescopes usually have
something called an equatorial gimbal system, which is
a mechanical arrangement, such that one of the degrees
of freedom falls along the rotation axis of the earth.
There is a knob there, and by rotating that slowly, you
can counteract the rotation of the earth. Equatorial
gimbal systems are a bit clumsy, though. They require a
big counterweight, which makes the whole telescope heavy,
and the telescope tube sometimes makes a pretty awkward
journey, when you direct it against different parts of
So the whole project here is about making a virtual equatorial gimbal system. The starting point then, is what I would call a "fork gimbal system". The telescope tube is hung up between the arms of a fork, and can be moved up and down there. This is called the elevation movement. Then the fork can be rotated around a vertical axis. This is called the azimuth movement. The problem now is to distribute the counterrotation against the rotation of the earth to the two axes, azimuth and elevation.
Here is a picture of the fork gimbal arrangement:
First of all, the rotation of the earth is directed towards north, and it is tilted up from the horisontal plane with the latitude of the place. So on the equator, the rotation axis is lying down, and at the North Pole it stands right up, so the direction towards north doesn't matter, which is lucky, because there is no notion of north at the North Pole. Then, there is a more tricky mathematical problem. The azimuth angle and the elevation angle are so called Euler angles. There is a third Euler angle around the axis of the tube. So what we want to control is time derivatives of the Euler angles, and what we have is the earth rotation vector. But the relation between rotation vectors and Euler angle derivatives is a little bit involved, and it is easy to make mistakes there.
But I provide you with a Java program that solves the problem. The result shall be a function with three inputs:
1/24·1/2/100 radians = 2.08333·10-4This value appears in the Java program.
This radio is based on a chip from Airoha called AR1010.
In a volume of 4x4x1 mm it contains a complete FM radio
with stereo decoder, sound outputs and two different
computer interfaces. I don't know if this is a so called
Software Defined Radio, i.e. a completely computerized
radio, or if there are any special circuits. Nevertheless,
you don't see any traditional things like coils or capacitors.
My work is based on a small breakout board, which includes
a crystal. It is sold by Spark Fun Electronics. Apparently
Telefunken has made circuits of this type, and there is
another chip called SI4375, which also has a short wave
band, but it seems to be sold by nobody. This will
The problem with Airoha AR1010 is that the documentation to it is confidential!. All that is availble is a datasheet that describes the electrical connections, but it says nothing about the protocols, with which you speak to your radio chip. A software specification is avaiable on the internet, however, though it is pretty hard to find. The name of the document is ar1000F_progguide-0.81.pdf, which you can try on Google. One adress you find is www.docin.com/p-34190202.html which is a chinese site where you can see and read the document, but it is unclear to me how to download it. I have downloaded the document, of course, but I don't dare to make it available here. Some people have complained about the quality of this document, but I think it is quite good. As you can see from the name, it is actually about the circuit ar1000, which is a more advanced sister to ar1010, which has RDS, but it works for ar1010 also.
The breakout board is maybe intended for surface mounting on a circuit board, but it is easy to connect to a normal hole mount board with some small wires. The breakout board hides some details of the original cicuit, so all you have to think about is this:
The linear camera is a little device from Hamamatsu
labeled S9227. It procuduces an image 512 x 1 pixel, so
it produces a one line picture. Another name is line sensor
or line scanner. I didn't know what I would use it for
when I bought it, and I still don't know. A use as a
robot sensor would be natural, but the vertical field of
view is quite small, so to use it for recognizing beacons,
you need either beacons of some height or a spread lens
in front of the sensor. In fact, the vertical pixel size
is 20 times bigger than the horizontal pixel size, but
the vertical pixel size is still quite small.
On the Parallax forum, there is someone who has taken a sensor like this and mounted on a tilt table. Then he can scan in a complete 2 dimensional image. He has even put movable color filters in front of the camera, and thus made a color picture. The exposure time is long, and the colors are perhaps not perfect, but it's nice. You can do it with this sensor and this software, if you just make a tilt table. You have to accumulate the image in a PC, because there is hardly enough memory onboard the Propeller.
Nevertheless, I think this was a nice project. It's a nice mixture of digital and analog technique, because you clock in a video signal, that is analog in nature. And with a single line, you can store the whole picture in the Propeller, so you can build a stand alone solution in a Propeller. With normal cameras you can hardly hope to do that.
The sensor is just a sensor, so I made it a camera by mounting it behind a magnifier. The focus of the magnifier is such that I should mount the camera slightly behind the backplane of the magnifier, so I used a sheet of macrolone for that (plexiglass would do too). Then I have an experiment circuit board and a connector and cable, and that is all. Here it is, mounted on a gorilla pod:
Here's a close up of the sensor:
The software is a main program Lcam.myr, which captures the image (process capt), displays it as a plot on the graphical display (process show), and also sends image data to a PC (process topc). The PC has to request the data by sending an arbitrary byte, and then receives 512 bytes of image data.
For capturing, you could consult the spec. I don't include it here, for I assume, that if you can get hold of the sensor, you can get hold of the spec. You communicate with the device with two pins, a startpin, and a clockpin. When the startpin is high, you do the exposure. I preferred to do that immediately after the previous picture was sent. I use now an exposure time of 64μs. During transfer of a picture, I keep the start pin low. You can transfer and expose simultaneousy, but I chose not to use that.
For transferring, you should first send 15 clock pulses to initialize the device. Then you run the clock signal up and down, and then the next pixel is available, so you start A/D conversion and fill your image array im. You do this 512 times to get 512 pixels. Then you turn the startpin on and continue to send clockpulses to expose the next picture. (It is not clear to me, why you have to send clockpulses to expose, but I tried without, and it didn't work).
Here's the "picture" of a small lamp hanging in my window. It is a little dark outside, so you only see the lamp. The ambient light outdoors is undersaturated.
The Mandelbrot set is a set of complex numbers. Now,
as we have learnt here, a complex
number has two coordinates (the real and the imaginary), and
a point in the plane also has two coordinates, and thus
we can depict a set of complex numbers as a set of points
in the plane. So the set becomes a "figure" in the plane.
The Mandelbrot set was discovered by Bénoit Mandelbrot, while he worked for IBM, but the Mandelbrot set has a kind of dual relative, called the Julia set, discovered by Gaston Julia and Pierre Fatou much earlier. But Mandelbrot had the opportunity to make his set into computer graphics, which quickly made it gain world reputation.
The Mandelbrot set is generated from a very simple equation (or rather function), but once it is there, and you can show it with your computer graphics, and you can zoom into its details, it reveals itself as an extremely complicated structure.
Here is the function:
f(z) = z2 + cz and c are complex numbers. What you do now, is that you take what comes out of the function (f(z)) and plug that back into z. And then you keep doing that. What happens then? Well one of two things can happen, z can stay limited, and maybe converge to something, or oscillate in a limited world. Or, z can go to infinity. It depends on what we start with, but we always start with z = (0,0) = 0 + i·0 = 0. And it depends on the constant c.
An EEPROM is an Electrically Erasable Programmable
Read Only Memory. A PROM is a memory with a content, that
you can give to it once and for all. An erasable Prom is
usually erased with UV lamp. After that, you can program it
again. An EEPROM is erased with an electrical signal, which
is handier than using a UV lamp. For the EEPROM:s I use
here, you don't really see a specific erase phase. They
behave as normal writeable memory (RAM or RWM), but they
keep the content after power down. However, the EEPROM:s
have a limited number of write cycles. After that, the
component is worn out. Depending on quality class, the
limit for the number of write cycles varies between
10 000 and 1 000 000. This is pretty much, but it makes
these components less suited for data logging, but well
suited for storing of programs.
Different types of memory cards, SD-cards, Memory sticks etc. are popular components of this type, but it's hard to find good documentation for them, and they have a somewhat complicated structure (page structure). Ideally you would like to implement a standard file system, so that you can read and write data from a PC. I have a device that does all this, based on a serial command interface from a computer like a Propeller. But I didn't always manage to erase files properly, it was somewhat slow, and it is not sold anymore. (In Parallax' object repository, there are Spin objects for handling SD-cards, including building a file system for them).
EEPROM:s that look like ordinary electrical components are also available. The upper limit in size is 1 MB, but more will come, I suppose. The component type I have chosen, is the type, that is used together with the Propeller computer. The type is called 24LC256, which has a size of 32 kB which is 256 kbits, hence the name. With the same interface, a type called 24LC512 is available. The size, consequently, is 64 kB. They can be stacked together up to eight at a time, so then the limit is 512 kB. If we store Propeller code, we are interested in the number of long (32 bit) words, so then the biggest chip contains 16 kLongwords. That's enough to fill 32 Propeller cogs with code.
These devices are controlled through an I2C interface. This is described here. Since the eeprom application of I2C is somewhat demanding, I have updated the assembler iic-routines, so they are now in the state as described in the I2C description.
24LCXXX memories have a memory page structure, but it doesn't disturb too much. There is a page write mode, but I haven't used it. My data to write are coming from a PC over RS232, and if I were to write that data one page at a time, I would have to store all that data first in the Propeller RAM. It is possible, and faster than writing individual bytes, but it is unnecessarily complicated. You have the same situation if you want to log real time data into the EEPROM.
For reading, you can read a single cell, but once you have adressed that single cell, you can keep reading from consecutive cells, and the limits between pages is immaterial in this case.
For talking to the memory, your Propeller, as a master, first has to wake up the device (the memory chip). It does so by first sending a start pattern, and then a byte with an I2C adress. The I2C adress for these devices is always a hexadecimal A. After that there are three bits, that allow you to adress up to 8 individual chips. The chips have three adress pins, and you connect them to 1s and 0s in an individual pattern. The chip that wakes up, is the one, whose wire pattern matches the three bits sent. Finally, there is a receive/send bit (0 for sending). To begin with, it is always 0, because now you have to send a memory adress.This adress takes up two bytes.
If you write data, you just keep sending the data after the adress. When you are satisfied, you send a stop pattern. In all this trafic, you have to leave the bus open between the bytes, to allow the device to send an acknowledge bit.
When you want to read data, after the adress has been sent, you send a start pattern and a new device adress, this time with a 1 as receive/send bit. After an acknowledge bit, you can clock in your data as long as you want, but you have to acknowledge each byte received. Acknowledgment amounts to sending a 0 on the bus.
I have a routine that reads a given number of bytes from a specific EEPROM adress, to a given adress in an array in Propeller RAM. I also have a routine that reads 4 bytes, and then packs them into a longword. There is a consideration there, about how the bytes in a word are supposed to be packed into consecutive cells in a byte oriented memory. The two principles here are called Big Endian and Little Endian. It can be said that each of these principles is more logical than the other (in some sense). Consequently Unix and Windows have made different choices. I am not quite sure what the alternative chosen in the Propeller should be called, but I found the way the EEPROM content is displayed in the Propeller Environment a little bit confusing. Anyway, the code that you can download here works fine.
This is now my project for using the EEPROM.
When you use your Propeller computer "in the field", but want to run different applications on it, you find, that you have to bring a PC with you, to switch application. It would be nice to have a small memory box, that could contain a bundle of programs, that you could choose between, load into the Propeller and run.
Technically, we build a card with one or more EEPROM chips, and connect its two control signals (called clk and sda) to two Propeller pins. We also need some means to control which program to run. As I have analog input channel free, I have chosen to use a potentiometer for choice of program. The current choice is displayed as a color on my RGB-led. So you need a little table to pair the applications with a color. I also need a button to confirm a choice, and it is connected to a Propeller I/O pin.
The rest is software. I'll come back to the software for writing the EEPROM in a while.
For running the program, the key mechanism is a Propeller instruction called coginit. It appears both as a Spin instruction and an assembler instruction, but I use the assembler instruction. It has one argument, which is a reference to a variable, called cogreg by me, which contains three different arguments packed into different bits. The first of them is the number of the cog to be started. The second is an adress to a cell in the Propeller RAM, where the cog program is stored. The third argument is an in principle arbitrary reference, that the cog is provided with, so that it can find its way to global variables.
Before we can use this, we have to load the program code from the EEPROM into an appropriate place in Propeller RAM. In fact, we load all the cog programs first into RAM before we call coginit for all the cogs, in order to make all the cogs start with reasonalbe simultaneity. We call the whole program a Bootloader. The Propeller already has a bootloader, but its implemented in ROM, so we can't modify it for our purposes. Hence we have to let the built in bootloader load our bootloader. It has to do so in a new cog (number 1), so we waste one cog on this. From this, our bootloader loads the remaining cogs from EEPROM via RAM.
A cog has an adressable space of 512 longwords, but the the sixteen last of these are special registers. Some of these may be proper memory cells, but some are certainly more general registers, which are mapped to the memory adress space. The outa, dira and ina registers are here. The first of them, which has some importance here, is the paramater register par. This register is loaded with content by the coginit instruction, and the content is usually used as a way to reach global variables in RAM. But the par register is interesting for another reason. The bootloader loads the program code into an array called ee. We should give the adress of this array to coginit. But what we need, is the absolute adress of ee. How do we find it? Well, when we start our bootloader, from the standard bootloader, we can write (in Spin now) coginit(1,@boot,@ee). This should load the absolute RAM adress of ee into the par register. So when we call coginit to load our programs, we can compute where the code is by adding the content of par and some relative adress of the code within ee.
When we run our programs, once we have loaded them, we would like to use the space taken up by ee for global variables. So the third part of the cogreg variable is also based on par.
There are two more details in this to consider. Firstly, in the bootloader, we need a few global variables except ee, and it is easiest to put them first. Hence, the par register doesn't contain exactly the adress of ee, but it can be computed. Secondly, the par register is 16 bits long, so that it can adress every byte in RAM. But in cogreg, there is a lack of space, so the 2 LSB's or the adress are shifted out. In this way, we can still adress every longword in RAM. But we have to do this shifting, when we load cogreg from par.
Programs for the individual cogs are loaded both in the EEPROM and RAM with a spacing of 512 longwords. These programs are maximum 496 longwords, and minimally much smaller, so there is some waste, but it is not too bad. You will find the program Boot.myr and the objectfile Eeprom.myo below.
The code you load into the program bundle in the EEPROM
is machine code, so I first had to make a machine code
generator. With the structure of Propeller Assembler, it
isn't awfully difficult. It produces the machine code
disguised as assembler code, so that all instructions are
presented as variable declarations, with data initalized
in binary form (following a %-sign). Hexadecimal code is
also presented as a comment on each line. Then there are
four initial lines, which makes the code runnable from
the Propeller environment.
The machine code generation is an integrated part of the Myra system. In Myra.java there is boolean machineCode that you can set to false if you want normal assembler language code. In either case you can procede through the Propeller Environment as usual, if you want to run the program directly.
If you get mystified by the machine code, there is a disassembler, that converts the code back to assembler.
The next step, if you want to make an eeprom bundle, is to make a packlist, called packlist.txt. It has a little code for writing a header in the eeprom. On the packlist there is:
These are files to download. For the files from PromWriteH.java and down, you can find more information here.
Probably, the EEPROM memories we have just mentioned,
are flash memories. But they are really pretty small.
On the other end of the scale, we have the memory cards,
like SD cards and so on. They have a huge capacity, but
I find them difficult to program. In between there are
flash memories, which look like ordinary integrated circuits.
SST25VF032B is such a memory with a capacity of 4 MByte. It is delivered in a 8 pin SOIC surfacemount package. The interface is serial, according to a standard called SPI (Serial Peripheral Interface).
You can adress individual bytes, and read or write them. But you have to erase the byte before you can write it. But you can't erase single bytes. You can only erase whole blocks of memory (the blocks are called sectors by the manufacturer). This needs to be considered, when you write the memory. Erasing amounts to that all the bits in the byte become 1 (so the bit pattern is 11111111 or FF in hexadecimal notation). Writing amounts to lowering some bits to 0. So if you write more than once to a byte, the result will effectively be a logical and-ing of the words you try to write.
These memories have a very elaborated write protection, system, so if you don't work hard, you have actually bought yourself a read only memory, that you can't even program. It is not easy to override this write protection, and you wouldn't believe that you had been successfull, unless you had actually tested it. Here are the protection mechanisms:
On top of the flash.myo system, I've built an
object called file.myo, which represents a file
in a file system. You can create up to 5 instances of
the file object at the same time. They are distinguished
by a unit number, so any call to any of the
file functions should be preceded by the right unit number,
so that you work on the desired file. This allows you
to have 5 files open at a time, and move data between
These files are the standard type files (not so called random access files), where you stand at a pointer, and can read or write data there, and then move the pointer one step ahead.
Here's the main consideration for anyone who tries to make a file system: You must imagine that you may want to delete files.. If you have done that, there is space left for new files. But if your new file is bigger than the deleted one, you can't squeeze it in. And if it is smaller, you get an even smaller piece of space left. After a short time, the memory medium will be like a Swiss cheese.
The remedy to this is fragmentation. You divide your file into fragments of equal size. Now, when a file i removed, you get a set of standard fragment holes left over. Your new file's fragment fit precicely into these holes. If the file is two big, there won't be enough holes, so the new file will have to allocate its last fragments elsewhere. It the new file is too small, some holes will be left over for fragments of future files.
To make it possible to read through the file, each fragments ends with a link to the next fragment of the file. One says, that the whole file is represented as a linked list.
In the PC world there is something called defragmentation. It is not the opposite of fragmentation, but a procedure to move the fragments of each file as close as possible to one another, physically. This is only meaningful for media like magnetic discs, where one can avoid delays, when the magnetic head has to move from fragment to fragment over the disc.
The best choice for my memory, is to let a fragment be as big as a memory block, i.e. 1024 longwords. It is pretty much for a fragment, but it makes it easy to erase files. As we delete a file fragment, we have to erase the memory there, to make the area usable for new files.
To find the start block of each file, we need a file catalog to point out where each file begins. Each entry in the filecatalog contains a file name, and a starting block. I have chosen to represent the block information with a single byte. Thus I can only adress the first 255 blocks, but the remaining blocks can contain fragments further down the files. I have chosen to let the catalog entry for each file be a single longword. That leaves only three bytes for the file name. But it is good enough for my purposes. I have also chosen to let my system contain up to 64 files. That gives me a file catalog, which is an array cat of 64 longwords.
I also need an account for which blocks are free in the memory, and which are occupied. There are 1024 blocks. which i 32x32 so we can store that information in an array occ of 32 longwords.
cat and occ are placed in the first memory block. However, they are not easy to work with there, as you can't write to them without erasing the whole block first. Hence, these two arrays have to be mirrored into the Propeller RAM. At power up, you read data to the mirrors from the flash memory. Then, basically, you work with the mirror variables. But you should see to that they get back to the flash memory every now and then, so that no information is destroyed at power down. You have a similar problem with a PC, where you risk to loose information, if you just shut power down. The system here writes the mirrored variables back to the flash memory, after creation of any new file, and after any delete operation.
Here's now a little of what you have to do:
The upside of an interpretive version of Myra is that
one avoids the limit of 496 longwords in Cog RAM. The
program resides in the global RAM of the propeller, where
there is much more space. From there, instructions are
loaded down to a cog and executed there.
The downside is that the execution is slower, firstly because all the instructions have to be moved from the global RAM to the cog, which takes a little longer time. Secondly, the interpreter has to work a little with the instructions, before they are executed. In practice, I have observed a reduction in speed of 2 to 3 times, which for many applications doesn't matter too much. (This is the relation between compiled Myra, and interpreted Myra; what you can do with hand written assembler code is another matter).
Here's then how it works. You load each cog with an interpreter, which is called Tolk.asm, from 'tolk', which is Swedish for 'interpreter'. This interpreter, together with the Propeller Cog, behaves in a new way relative to the Propeller itself, so we can call it a virtual machine Hence we can program this virtual machine in a new language, which comes both as a somewhat readable Assembler language, and as machine code. We call this language iMyr.
The iMyr code is generated from the Myra code, with a special compiler. Hence, both compiled execution and interpretive execution are compatible with the original Myra language. However, interpretive execution has some advantages, and if we use them, we may create a Myra program, that can't be executed in compile mode. There are four major such differences:
An iMyr instruction is parsed into three parts:
|0||pushim||push the adresspart to the stack top|
|1||push||push the value of the adressed local variable|
|2||pushg||push the value of the adressed global variable|
|3||pop||pop the stack top value to the adressed local variable|
|4||popg||pop the stack top value to the adressed global variable|
|5||pushel||For the following 4 instructions, the stack top value is an index pointing to an array element. The array base adress is the adress part of the instruction. For this instruction, the array resides in local memory. The value of the array element is pushed to the top of the stack.|
|6||pushelg||Like the previous, but the array resides in global memory.|
|7||popel||The next highest element on the stack (i.e. under the index) is pushed to the adressed array element in local memory.|
|8||popelg||Like the above, but the array resides in global memory.|
|9||pushat||The two top elements on the stack are summed, and the value at that adress in local memory is pushed.|
|10||popat||The two top elements on the stack are summed, and the third element on th stack is popped to that adress|
|11||raise||raises the stack pointer, so that a value popped off at a recent pop operation, becomes visible again.|
|12||popoff||removes the top value of the stack, whithout sending it anywhere|
|13||flip||exchanges the two top elements on the stack with one another|
|14||dup||duplicates the top value on the stack over the current stack top|
|15||jmp||A jump. The adress part is the target of the jump|
|16||call||A subroutine jump. The adress part is the target of the jump. This target adress is pushed on the subroutine call stack.|
|17||return||This is a pop of the subroutine stack. The value that is popped up to the top of the stack is incremented with one.|
|18||asm||calls an assembler routine. The adress part selects which of the assembler routines is called.|
|19||status||pushes the values of the Propeller status registers (z and c-register) on the status stack|
|20||rstatus||pops the status stack, so that the previously sampled value of the Propeller status is recovered.|
|21||l21op||Operation stack to stack|
|4||or (logical or)|
|6||& (logical and)|
|8||xor (exclusive or)|
|10||>>n (non algebraic right shift)|
|12||>> (algebraic right shift)|
|14||<< (left shift)|
|2||compl (bitwise complement)|
|7||G (1 if stack top greater than zero)|
|11||Z (1 if stack top is exactly zero)|
Here's a simple sketch of the virtual machine.
In the middle of the figure, there is a register called Instr Adress. Through the global RAM (gRAM), the instruction is brought to the instruction register, where it is parsed into type, condition and adress. The type goes a little everywhere. The adress may go to the memories (the global and the local) In case of a jump, it goes to the Instr Adress register. This register is connected to th subroutine call stack. In case of a normal jump (jmp), nothing happens with this stack. In case of a subroutine call, the previous value in the Instr Adress register i pushed down into the call stack. When the stack is popped, the value, that goes up to the Instr Adress register is incremented with one. This means that execution continues at the instruction after the subroutine call.
To the left is the normal stack, which communicates via its top element with local or global memory. Some of the memory cells in local memory (cog RAM) are mapped to input and output registers, so this is how the computer communicates with the outer world. Operations take data from the highest layers of the stack, and push the results to the top of the stack.
The status stack is depicted as a horizontal bar, as it is actually a single memory cell, where status data are shifted in. The least significan bits are updated from the Propeller status registers, upon execution of a "?" instruction (STATUS instruction). Subroutines that use the "?" instruction, should restore the status by popping the status stack with a "!" instruction.
Based on the condition and the value of the status stack the condition checker decides whether the instruction shall be executed or skipped.
As with Spin, there are two ways to run iMyr code;
directly from the PC or via the EEPROM.
For direct running, we first have to bring a bootloader into the Propeller, using the standard Propeller system. That bootloader is called BootI, where "I" stands for this mode of running iMyr. BootI will load the program into RAM, and then load it further into the Cog memories with coginit as described above. The file iMyrLoad.bat is a suggested batch file, to make this as easy as normal execution of Spin code. As easy - but a little slower, as the speed is limited by the RS232-link with a speed of 115200 baud. Also, the operator has to operate a "reset off" button, to disconnect the reset of the Propeller chip from the Prop stick device. Otherwise, the Propeller may reset, as data come from the PC.
For running via EEPROM, we first need more EEPROM space, than in the normal system. Replacing a 24LC256 chip with a 24LC512 chip will do, and this causes no further work. Alternately we can add an extra 24LC256, and connect its adress pins to something other than (0,0,0). Then we will load the loader EEPROG into the Propeller. To control where the program goes into the EEPROM, we should have an eeprom directive somewhere in the source code file. It typically reads:eeprom:0,17. 0 is the EEPROM chip number. If we replace the 24LC256 chip with a 24LC512 chip, nr 0 is appropriate. If we have more chips, and we want to use them, we direct the code to them with some other number than 0. The figure 17 points out a 512 longwords big block in memory. For 24LC512, there are 32 such blocks. For chip 0, 16 blocks are reserved for the ordinary Propeller system.
Compiling the Myra source code with the MyrI compiler gives an .eep-file, which is loaded into the EEPROM.
Running the code requires another program, BootJ, where J stands for this EEPROM-mode. BootJ can be loaded in the Propellers standard EEPROM, so that everything starts at power up. BootJ has to be programmed so that it loads the program from the correct block in EEPROM. In the example above, a variable iblock should be set to 17. You can use hardware jumpers, switches, or potentiometers and A/D-converters, to allow different applications to be ran at start up.