This is a new version of this page. Many things are updated
here. Most of all, I am using a new language, called
MPS. Many of the applications are new or updated too.
Many of the files can be downloaded from the
chapter MPS objects
The old version is available
here
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
640 MHz.
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 instruction, 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 sequence 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.
After some time with the Myra language, that you will find
here, I decided to go back to an older
language idea. The purpose was to get smaller and faster
programs, by working against a computer model that was
closer to the real architecture of the Propeller. Speed
may be important, but program size is even more important in
Propeller applications, because of the relatively small
memories in the Propeller cogs. In fact, the size is only
496 longwords. It may seem pretty hopeless to solve any
task with such a small program size. But, after all, you have
8 cogs of this size, and in these types of computers you can
do a lot with small programs.
You find a more or less complete
documentation of the MPS language, and also the standard
object file std.mpo
here
For Myra, I decided to make an interpretative version, to
overcome the progam size limitation. For MPS I haven't done
that. It seems that I can solve my problems with the standard
language. Myra also made use of an assembler resource file
written in assembler, but for MPS I don't need that.
I can write everything I want in MPS, except for a few
lines with so called in line assembler code.
Here is the software you have to download in order to use the MPS language:
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. I had some introductory comments on Myra here, but I have now removed them.
Here is the software you have to download in order to use the Myra language:
As a little apetizer for the rest, I will present the
following figure, which displays a Propeller surrounded
by devices, from which it can get sensory data and operator
commands, and on which it can act. In short - an ecology
around the propeller:
Let's start in the upper left corner, and go around in
counterclockwise direction.
In the upper left there is an analog to digital converter.
To it, we can connect potentiometers, and thus control the
program with one or more knobs. There is also a great
selection of sensors, that give analog outputs. In the
figure we have shown gyros, which measure rotation, and
accelerometers which measure acceleration and tilt (due to
gravity). Under the A/D converter, there is an RGB LED on
which we can create colors. Its main use is perhaps for
debugging. You can display a certain color, when you come
to a certain point in the program.
The next item is a keyboard, which can be used to control
a program. Here I show a numeric keyboard, which is smaller
and handier than a full alphanumeric keyboard. Touch controls,
which play such an important role in smartphones, are
available to amateurs today, but perhaps only in the older
form of resistive touchscreens, which require using
a stylus. With a touchscreen, you can make a universal
mode selector, by drawing "buttons" behind the screen, or
you can input analog data. You can relatively easily make
a program to input simple sketches to your computer.
RFID is a way to recognize simple and cheap "tags", when
they come into the vicinity of the RFID device. Each tag has
a unique serial number, and you get that, when the tag is
detected. One, maybe bad, idea I had about this, was to use
RFID for robot navigation. You placed out tags, and when the
robot encountered a tag, it would know where it was.
"TCP/IP" represents a little device called WiFly, which
lets you connect your Propeller to you WLAN at home. From
there you can go with your Propeller data out on the world
of internet. ZIGBEE represents a wireless device, so that
you can send data (and commands) between your Propellers
wirelessly.
The EEPROM is an integrated part of the Propeller system.
That's where you store your program, if you want it to
be started after power down/power up. All that is programmed
into the Propeller. But you can write you own code, to talk
to the EEPROM, for your own purposes, and you can stack more
EEPROM chips to the same wires, to get more space for data.
I have also tried some other components with the same
functionality, but with more capacity. They are usually
called flash memories, but they are functionally EEPROMS
(Electrically Erasable Programmable Memories).
RAM is a Random Access Memory, i.e. a standard memory, where
you can store data at high speed. But you loose the data
at power down. A RAM has many pins, so I have chosen to
connect the RAM via an interface Propeller.
SD is an SD-card (Secure Digital). Technically it is a
flash memory and a small interface computer, built into
a "card" that you can plug into a slot. They have a huge
capacity, and it is practical that you can plug them
in and out.
ESC is an Electrical Speed Control, which belongs to the
world of Radio Control Aircraft. You connect a powerfull
battery to the left, and a brushless motor to the right,
and then you can control great mechanical power with pulses
from the Propeller.
Over that, there is a more conventional way to control
standard DC motors with a so called H-bridge.
The diodes further up
belong, together with the striped strip, to an
odometry system. With that you can measure displacement along
the strip.
The, maybe, camera like object at the right top, is
- a camera. It is a camera with a serial interface, so that
you can get the pixels of the picture into the computer.
The rectangle with the sailboat is a graphical display, with
color depth good enough to display photographs.
But, with some programming, you can also display
alphanumerical data on it.
Finally, the USB box, is the standard umbillical through
which the Propeller is loaded with programs from a PC.
But you can also use it to up/download data from/to the
PC. You need some software at the PC-side to take care
of the data. Such a program will be presented
here. Concretely the USB box
contains a little device called a Propstick.
With that and the Propeller development environmens,
you can load programs into the Propeller.
Given all this, you can build different combinations. For
example, if you take a picture with the camera, you would
like to store it on the SD-card. But for most cameras,
the camera produces more data than you can handle in time
with the SD-card. So you may need to store the picture
in the RAM. After you have transferred the picture to the
SD-card, you can display it on the display at any time.
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 MC3208. 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. All this is done in a function adc.get
in the file adc.mpo. The call is like this:
A parallell input Digital to Analog Converter (DAC) would require many Propeller pins, but I have a serial interface DAC called MCP4822, and I have made an mpo-file for it:DAC.mpo. It is a small power device, so you may need to add some power amplifier to it.
But another popular way to make analog outputs is with
PWM, pulse width modulation.
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
called TDA2050:
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 constant 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.
Lately I have had some problems with the IR2103 driver,
in that some of the FET:s have been destroyed. I don't know
why, but it always hard to remove and replace components.
Because of this, I have tried another alternative. It is
an integrated driver called L298. It contains two full
bridges (4 half bridges), so you can drive 2 DC motors
(or 1 stepper motor) with it. It comes as a so called
Multiwatt package with 15 pins. The circuit works fine,
and I have been surprised that the component stays so
cool. You can mount it on a bit of aluminum profile, if
you just drive moderately sized motors. The circuit can
drive up to 48 volts and a few Amperes.
Another circuit is called L293. It is an ordinary
DIL20 capsule, which is a little more difficult to cool.
It has four ground pins, and you can make a larger suface
on the circuit board connected to the ground pins for
cooling. I haven't tried these circuits yet, but they are
part of an Arduino motor shield, and also of a Raspberry
PI motor interface.
Electrical motors have an inductance. Then, when you
stop the current through the motor, the inductance will
respond with a very high voltage. This could destroy your
electronics, so you need to have protection diodes to absorb
the voltage peaks. The choice of these diodes is a little
mysterious. International Rectifiers driver FET:s
(called among others IRF510) contain protection diodes,
so the problem is solved there. For L298 you have to add
diodes yourself. I have the impression that they are built
in into L293, but I am not sure. An important factor is
that they are fast. When you reverse the voltage over a
diode, you expect that it would stop conducting. But before
that, the charge carriers have to leave the diode. In a
standard diode, there is no electric field at this occasion,
so the charge carrier leave by diffusion only, and this
takes a loooong time (a few microseconds). (There is the
same mechanism in bipolar transistors). Shottky diodes have
another desigh that overcomes this. The measure of this
is called trr (reverse recovey time). You rarely find this
information for slow diodes, so look out when this is not
mentioned. As there weren't many enough fast diodes in
stock with my supplier, I tried a fast but small diode
called 1N4148 (a classical diode). I put two in parallell, and
it seems to work fine. My recomendation is still to look
for somewhat bigger Shottky diodes. Here's a circuit diagram
for how to connect them:
Here's a picture of a motor driver circuit based on
integrated power drivers:
The integrated circuit is to the left. I have chosen to
connect it in a pretty primitive way with wire to make it
easier to replace when necessary. Then you see a 5v stabilizer
for the logic level of the circuit, and then the protection
diodes.
(Most of this applies to AC-motors as well, but DC-motors
are more popular in control applications.) As just mentioned,
a motor has an inductance (it has a coil in it), and this
means that the motor produces high voltages if you try to
stop the current through it quickly. So use diodes as
presented previously.
Secondly, a motor is also a generator. So it produces a
voltage proportional to its rotation speed: ug
=a·ω.
It is the difference between the applied voltage, and this
generated voltage, that drives the current through the
motor winding. So the current i = (u-ug)/R,
where R is the resistance of the motor winding (usually
a small value).
Then that current determines the torque M of motor:
M = b·i. This torque is then reduced by external torques
Mext,
like friction. This gives an acceleration of the motor
as dω/dt = 1/I·(M-Mext), where I is the so
called moment of inertia of the motor + what is connected
to it (this becomes a bit complicated, if there is a gearbox).
Now, let us think that Mext is small, so that
motor is almost free wheeling. Then the motor will keep
accelerating, and ω will grow, and so will ug.
Finally, the current will be very small, but the torque
M will manage to balance, the small Mext. So
we have the equation u-ug ≃ 0, or u - a·ω ≃ 0, or
ω ≃ u/a. So, the voltage over the motor controls the
motor's speed.
Now, let's grab the motor axis and hold it firmly, so that
the motor stalls. Then ω = 0 and ug = 0. So
the current is u/R, which is a high current. This current
controls the torque of the motor. This is the torque, that
we feel in our hands, when we try to stall the motor.
So now the voltage of the motor, or the current through
the motor controls the torque.
Hence the motor acts somewhere between two extreme modes,
one where voltage controls speed, and another where voltage
controls torque. We can also see that the motor is not
a passive receiver of electric signals. It responds by
requiring high currents if it experiences mechanical
resistance. Finally, if you make some kind of
feedback to your motor, from, say, the position of the
motor, the generator effect in the motor will contribute
with some damping, which you probably very well need.
Brushes in a motor serve two purposes. They bring
the electric current over to moving coils in the motor.
And they serve as so called commutators, which reverse
the current, when the motor has gone a half turn. To
get brushless motors, you have to do two things. First,
you build a motor with stationary coils, and a rotating
permanent magnet. Then you have to solve the commutation
problems.
You can simply drive the motor with alternating
current. With some luck, you can have the motor rotate
in sync with that alternating current. In order to drive
the motor in one, and only one, direction, you should have
a three phase system, but you can create a false third
phase with a capacitor.
Another idea is to measure the
position of the motor with a sensor, and then
reverse the voltage with electronics at the right moment.
This is a kind of "software commutator". But then you can
maybe avoid the separate sensor, by registering the
motor voltage. There will be a small pulse induced, when
the moving magnet passes one of the electromagnetic poles,
This is not quite easy, because you are trying to measure
some small induced voltages, while you are, yourself, imposing
much higher voltages. But it can, obviusly, be done.
After all this, the motor is simply a three phase motor.
And the electronics is a machine for creating three phase
alternating voltage based on
A stepper motor moves in steps. These steps are steps
in position, so they are in themselves position controlled
devices. You can control their speed, but hardly torque.
The idea is that you can send a sequence of positive
and negative voltages to (usually) two windings. Such
a sequence will take the motor 4 steps, but you can stop
anywhere in the sequence. Then the motor will stop where
it is. You basically have full control of the motor.
By running through the sequence at a defined pace, you
can get a specified velocity.
A stepper motor has a hold torque. If external forces exceed
that torque, the motor will slide away. If you thought that
you would have full software control of where the motor
is, this is a disaster. The holding torque is a function
of the current you send into the motor. Higher current
means higher holding torque, but at some current, the motor
will overheat. Now, here's a disadvantage of the motor.
If we want a reasonable holding torque, we have to send
a hight current into the motor all the time.
For some applications, where the motor is connected to a
big inertia, stability may be an issue. The motor might
slip over a lock position and go to the next.
A stepper motor normally has two coils and a rotating
permanent magnet with many poles. First one coil attracts
a north pole, while the other is passive. Then you can
remove current from the coil, and apply current to the
other. Then it will attract the north pole. In the next step
you reverse currents to attract the south poles instead.
After 4 steps you can repeat the pattern, to attract the
next north pole.
Obviously you need 4 power amplifiers here, to drive
a stepper motor. With these amplifiers you could otherwise
run 2 DC motors in both directions.
So the issues with stepper motors are:
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.
As RS232 is such a common protocol, I've put the code for
it in the standard object file std.mpo.
The standard routines are called as:
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).
Data are clocked by the clock wire in the sense that the
slave can trust the data, when the clockline is high. Hence,
the data line should not change, when the clock line is
high. If it does, this is taken to be a start pattern or
a stop pattern. When the start pattern appears, the
slaves should expect data on the bus. The first data
after the start pattern is a device adress (plus a read/write
bit). Those slaves which do not recognize the adress as
their own, can now go to sleep, and they don't need to wake
up again, until a stop pattern appears. Communication is
now open between the master and a single slave, and the
way the communication proceeds is pretty much an agreement
between the two. What normally happens, is that the master
sends data to the slave. If it wants to receive data from
the slave, it normally sends a new start pattern and
the adress, but now with a read bit. When one of the sides
receives a piece of data, it acknowledges this with a single
zero on the data bus.
The I2C protocol has an object file called iic.mpo.
Its functions are called in the following way
SPI means Serial Peripheral Interface. Unlike RS232, it
has a separate line for clock signals. Normally the clock
signals are generated by a master device, so the master
clocks in data from a device. This has the advantage that
a computer can acquire data in a pace that it can handle,
while in RS232 the receiving computer can be flooded with
data. Data can be sent in both directions, normally over
separate wires. You can tie them together, but with the
risk that hardware is destroyed if both devices try to
send simultaneously. Finally there is a chip enable wire,
which enables a device, normally when that signal is low.
All together, then, there are four wires. But for one
wire more, you can communicate with two devices. One
of the devices can then be disabled, so it doesn't listen,
and it doesn't send. With seven wires, you can communicate
with 16 devices, if you buy yourself a one of sixteen
decoder circuit.
SPI is simple to program in both ends. The normal standard
is to send 8 bits serially, but you can easily go to 9. A
typical case of that, is when you send both commands and
data. The data is normally 8 bits, but you can use the
9:th bit to distinguish commands from data.
SPI functions are on the spi.mpo object file.
The functions are called like this:
If RS232 is a very old communication standard, Morse
is even older. The good old Morse alphabet with combinations
of long and short beeps, could that be
something for our time? Perhaps. In the first place, I
simplify the alphabet to this: 0:short pulse, 1:long pulse.
Important in Morse signalling is also the pauses. There
are short pauses between the individual pulses. If the
pauses are longer, it means the end of the character. If
the pauses are even longer, it means the end of a word
(there is no code for "space"). Here, a slightly longer
pause means "end of message". With that we have a
variable length protocol. Away with the standard 8 bits.
If some message requires 32 bits, we can send 32 bits. If
in some case 4 bits is enough, we can send 4 bits. If we
want, we can go to the original Morse alphabet, to send
common characters with fewer bits. "e" was only a single
short beep (a single 0). We have a self synchronizing
system, no separate clock pulses, no hard requirements on
common frequencies. All you require is that you can
distinguish a long pulse from a short, and a long pause
from a short. I have tried the system successfully up to
an average pulse frequency of 500 kHz.
There aren't many Morse type devices around, so the only
thing you can use this for, is for communication between
your own propellers. I used it for communication with my
RAM computer.
The functions are in the objct file morse.mpo.
It has functions called like this:
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 job for us, in the form of integrated
circuits, and hybrid modules. Most of them wrap an
RS232 interface into a USB interface.
One of these FTDI modules is built into a device called
Propstick, which is used for loading and running
Propeller programs under control of a PC:
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.
There is no usb.mpo object file, as usb from the Propeller's
point of view is nothing but RS232 (thanks to FTDI). But
there is PC-communication object called pc.mpo.
It uses the fact that the PC interface goes over standardized
pins, 30 and 31, and with a standardized baud rate,
115200. The functions are called like this:
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.
The zigbee communication is controlled through a zigbee
object called zig.mpo. Its functions are called
in the following way:
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 input 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.
I have tried several displays over the last years. But right
now I have a favorite. It is from Adafruit, and they
call it "lovely". So I agree. It is pretty small, and
the communication to it is not superfast, but it is
easy to use, and it has a colorspace rich enough
to show photographs. It is purely graphical,
so if you want to show text, you have to do some
programming. It is a 2.2 inches TFT-display with 220x176
pixels. More information is at
learn.adafruit.com/2-2-tft-display". It is sold in
Sweden at www.lawicel-shop.se
(This product is now discontinued. I will look for their
replacement, and study how it is driven as soon as possible.)
It is controlled with the SPI protocol. What comes on the
SPI-bus is characterized as commands and data, where data
has the 9th bit = 1. Hence, we use the spi.send9
function.
Data are normally 16 bit data. For color data, all 16 bits
are used. For things like coordinates, only 8 bits
are used, so the first 8 bits are filled with 0.
Now, the principle for drawing is the following: You
send a set window command, where you define a window on
the screen, by the x and y coordinates of the lower left
and upper right corners. Then you send color data. Pixels
with these colors fill the rectangle collum by collum.
That's all.
To draw text, you need a font, that you place in a
global data block like this (so this is done in your
main program after the global variables).
As mentioned, this 2.2" display has been discontinued.
With Lawicel, the replacement is a 1.8" 18 color display,
also from Adafruit. Adafruit may have some display of
bigger size. So this display is slightly smaller, and
it also has fewer pixels, which may be just as important,
when it comes to modifying code. The image resolutions
is 160 x 128 pixels
The color quality is still
so good, that you can use the display to display photographs.
I have the impression that this display is slightly faster
than its predecessor.
Information about how to program this display comes, as
with the previous one, as C++ code at Adafruit's webpage.
The code is written as common code for several different
microprocessors, with a lot of #ifdef:s and
#endif:s which
makes the code a bit complicated. Furthermore, the designer
has chosen to write the initalization codes, as a big
field of constants interpreted by an interpreter. I don't
think that really pays. A programming language is already
like an interpreter for computer code, and it doesn't pay
to wrap another layer of interpretation around it. So my
code is just a straight code, sending commands and data
to the display. Furthermore, some of the code is just sending
values to registers who already have these values by
default. So I have been able to eliminate parts of the
code. There is code for two different versions of the
display driver circuits, a B version and an R version.
But to my understanding, only the R version is sold by
Adafruit.
I also tried to remove the gamma correction code, to do
with default settings. But then I found that the image
become rather dim. So it pays to use the values provided
on the web page. The gamma corrections somehow have to do
with how transparent the pixels appear. I guess, if you
are really interested in this, you could go on doing
experiments to get an even better picture. Right now my
picture has very good contrast, but it is a little dark.
The code provided is not for the raw display, but for a
breakout board, which also contains the driver circuit and
a micro SD card reader. You can run this board with just
3.3 volts, which you also connect to the pin marked "lite"
for the LED background light. The new display, unlike the
old one has a separate d/c pin to distinguish between
command (0) and data (1). (In the old display, the d/c
information was sent as a 9th databit). The rest follows
the SPI protocol. So there is Clock and MOSI
(Master Out, Slave In) and MISO
(which you can skip) and Chip Enable. Finally there is
a Reset pin, but I have the impression that you could
do without that. With these pins connected, the following
code should be equivalent with the code in the previous
section. But remember that the display resolution is
different. The code is packed into the object file
grafb.mpo. I also provide a grafb.mpp with
prefabricated processes.
RAM mean Random Access Memory. It means that, whatever
random adress you want to write to or read from, the
process of doing that, takes equally long time irrespective
of the adress. This is not so for the other memories, where
you have a block structure, that makes reading or writing
take longer time, every now and then. Right now, RAM's
forget everything, when power is removed from them. Nobody
has come up with a design that would make a memory
both RAM and non-volatile.
My RAM has 512 kBytes capacity. I think it is called
LY625128SL from Lyontek, but I'm not sure. It comes in
package called SOP32 which is for surface mounting, and
not quite easy to deal with for an amateur. 512 kBytes
requires 19 bits of adress. Data takes up 8 bits. Then
there is a write enable and an output enable signal. So
this chip uses up almost all the pins of a Propeller. That's
why I have decided to use a dedicated Propeller for the
RAM. Some sort of serial communication is the only choice
for the communication with the Master Propeller, as there
are only few pins left. So, I decided to use Morse
communication, where I can manage with a single pin
to communicate in both directions.
Then the two Propellers communicate with a command
language, with the following commands:
23LCV1024 is a static RAM, in a 8 pin chip, controlled through SPI. Thus the pins for communicating with it are only 4, but even that was too much, so I decided to use a dedicated SRAM computer. The interface is contolled by code in the MEMI.MPO object file. It has functions for different type of memory actions, and they send Morse signals for invoking these memory actions. Such a command consists of some data, and in the last four bits a command. We have:
This idea of controlling an SRAM through a Propeller comes back in "Terminal project" which is presented here
An SD-card is an electronic component, which is built
into a "card", that can be pushed into a slot. It contains
a non-volatile flash memory and an interface computer.
These cards have a huge capacity, and they are handy
to use.
Here's a picture of a small interface box for the SD-card.
You can see the card pushed into its slot:
The SD-standard is a semi-open standard. You can join
an SD-society, but it probably costs a couple of milions.
If you are not a member, there is a rough public spec. It is
actually not bad, but some questions remain unanswered.
There is useful information on this site:
elm-chan.org/docs/mmc/mmc_e.html.
There are two protocols for the SD-card, one called
SD-bus, and the other is SPI. Amateurs probably prefer
SPI; the SD-bus seems unnecessarily complicated. A special
issue is the so called CRC, Cyclic Redundancy Check.
With CRC, you are supposed to add a so called CRC-code
to the message you send. If there is any error in the
transmission of the message or of the code, the receiver
is able to detect this. CRC-codes are generated by a
very interesting algorithm, but with the time I have spent
on it, I haven't been able to penetrate it, so I can't
compute CRC-codes in real time. Fortunately there is a
web-page, that can compute CRC-codes off-line:
ghsi.de/CRC
Fortunately, the CRC-checking is disabled in SPI-mode,
though not quite.
So, we all want to use the SPI protocol. However, SanDisk,
which is probably the major supplier of SD-cards, have
abandoned the SPI protocol for their SD-cards, which means
that they break the specification of their own society.
I've tried Verbatim-cards and Kingston-cards, and they
work.
SD-cards come in a newer standard called SDHC (High Capacity),
and I thought it would be wise to adapt to this new standard,
as it might be difficult to find regular SD-cards in the
future, specially if I have to keep away from SanDisk.
The point is this: You adress an SD-card with a 32 bit
adress. That's good for adressing memories up to 4GB
(232 is approximately 4 bilions). But SDHC cards
are bigger than that. So instead of letting the adress be
the adress of a single byte, you let it be the adress of
a block of 512 bytes. When you read and write, you can
only read and write full blocks. When you read you can find
your interesting
byte somewhere in that heap of data. This is in a way good.
When you write, you always write a whole block, which
you can do without problems. Block writing automatically
opens the memory for writing. And you read almost the
same way as you write.
But there is a job for you in this context. You have to
tell the card, that you have understood, that it is an
SDHC-card. For some odd reason you have to send this message
with a correct CRC-code. But this is a static message,
so the CRC-code is static, and you can find it on that
web page.
The cards are controlled by numbered control commands.
The message starts with binary 01, and then follow
6 + 8 bits of command. Then follow three bytes of
parameters associated with the command, then the CRC code
and a single bit 1. In the sequel I give the command
number as including the 1 in the second bit. That means
that all commands are greater than $40 (in the way that
hexadecimal words are written in the Propeller world.)
Now, let's take it from the beginning. The SD-card needs
clock cycles to get through its own initialization procedure.
It seems that the card computer doesn't have a clock.
A simple way to achieve this is to send 8 bit data with
the SPI protocol. I send 20 such bytes, which is probably
more than enough.
Now, the card wakes up in SD-mode. It is comfortable
but strange, that we can still send an SPI-message to it.
That message is $40 (hexadecimal 40), with
a zero argument. And it has to have a correct CRC-code.
But many amateurs have found out that this CRC code.
is $95. (formally it is $47, but after you've squeezed in
that final 1, the last byte is $95.) This command puts the card in idle mode, but
it also tells the card, that we will talk to it in SPI-mode
Then we must give the message "I know, that you are an
SDHC card". The command is $48, but this is a kind of a
group command, so it needs a parameter $1AA. The CRC-code
is $43.
Then we need to leave the idle mode. It is a command $69
but it belongs to an expanded group of commands (so called
app-commands) so we have to send the command $77 before
it. The command $69 has a parameter which is 1 in the
thirtieth bit.
The card always sends a response to the commands. There
are different categories of responses, but this is the simplest
of them. In it, the last bit represents that the card is still
in idle mode. So we will keep sending these commands until
the response is 0. With that, the card is initialized.
Once you have downloaded the software, take a look to
see if it fits with this description.
To begin with, writing is simple. We just write the
data to our own writebuffer in the Propeller.
We build the writebuffer in longwords,
and there are 128 longwords in the buffer (=512 bytes). We
strip off the last 7 bits of the adress as in-buffer-adress.
In every such write operation we increment the adress by
1. Initially, we have set the adress through a set adress
function.
But when the in-buffer-adress reaches 127, we have to do
more. We have to write the data out to the card itself.
The command for this is $58, and the parameter is the
block adress, which is the adress except the 7 last bits.
We can then put anything as CRC code. This command should
then be followed by a so called token, which in this case
is $FE. Then we send the data byte by byte, so we have
to extract these bytes from the longwords in the writebuffer.
Then we send two arbitrary numbers as CRC for this whole
data packet (this is supposed to be a longer CRC of 16
bits, while the CRC codes mentioned before are 7 bits long),
and then we wait for a response from the card.
The card now has all the data, but it takes a while to
actually write them to the card. In the meanwhile, the
card will send a busy signal.
The read system tries to find the data in the read
buffer first. This supposes that no one has written new
data to the card since the buffer was downloaded from the
card. This fits with the assumption that we don't write
and read the card in anarchy.
For this, the system has a current block number
(called rbl), which
is the number of the block most recently downloaded.
From the read adress, the block number can be extracted
as the bit pattern except the last 7 bits. If this block
number equals the current block number, the data can
immediately be read from the buffer.
If not so, we have to download a new buffer from the card.
This is done with the command $51 with the block adress
as argument. Then we wait for a response from the memory,
and then we clock in the data by using the spi.exch
command. We also use it to clock in two bytes of
CRC-code for the package from the card.
Now the buffer is updated, so we can read the desired
datum from the buffer.
The SD-card is handled from an object called sdh.mpo ("h" for "H" in SDHC). The functions there are called in following way:
The standard program memory that Parallax uses for the
Propeller is called 24LC256, but if you can find it, it
pays to buy a 24LC512 instead. You get twice as much
capacity for almost the same price. 512 means 512 kbits,
organised as 64 kBytes. (we will mention a version
with even more capacity here)
But you can do more than that. The chips have three pins
called adress pins. Parallax advises you to ground all
these pins, to make for the adress 0. In fact you don't
need to. The pins have a pull down circuit, so they "ground
themselves". But if you add another chip, you can give
it another adress, by pulling some adress pins high. Then,
alltogether, you can have 8 different 24LC512:s with unique
adresses. So, the maximum capacity of such a system is
512 kBytes or one half Meg. We call these subadresses,
set by the adress pins, chipadresses.
These memories are pretty straight forward
I2C-components. In the I2C world, each
circuit type has its own device adress, though these
device adresses can hardly be distributed in such an orderly
fashion as IP-adresses or Bluetooth adresses. Anyway,
these memories have the device adress $A0. But then
the above mentioned chipadresses fill the three bits after
the 'A'. The final bit is a read/write bit; 0 for writing.
Then the chip with the chipadress 3 is adressed for writing
with $A6.
The protocol is then as follows:
If you want to write to the chip with chipadress 3
(as an example), you start with the start pattern.
and continue with the code $A6. Now the appropriate chip
will listen, and all others will go to sleep. Next you
send the adress within the memory, which takes up
16 bits for 64kBytes, so you have to send this adress
in two bytes (the most significant first). Then you can
just send your data in bytes. After each byte, you have
to wait for an acknowledge signal from the memory.
(it's no really just waiting. You're the host, so you
have to send the clockpulse to get any response.)
Finally you send a stop pattern.
If you want to read from the memory, you start the same
way, sending device adress, and the adress within the
memory. But then you have to send a new start pattern, and
then again the device adress but with a read bit. So in
the example, the code to send is $A7. Then the component
will send you the data byte by byte, encouraged by the
acknowledge patterns you send. You stop the traffic at
any time by sending a stop pattern instead of an
acknowledge pattern.
These memories behave pretty much as RAM-memories in the
sense that the time it takes to read and write, is
independent of the adress. But they are slower to write
than to read. When you have sent data for writing to the
memory, they have just been buffered so far, so you have
to wait some extra time, before they are acutally written.
The object file eeprom.mpo contains functions for
handling the EEPROM. You can initialize the memory system,
and then you can set the chipadress (called chipcode),
to adress a particular
chip. There is no particular support for writing over
the boundaries of the chips. Then you can set a start adress
for reading and writing, and this adress is then incremented,
when you read and write. You can read and write bytes
and longwords. But you can also move chunks of data between
an array called ee and the EEPROM. If you use that,
you have to declare ee as a global variable. Here's
how the functions are called:
The flash memory I have used is from SST and is called
SST25VF032B. It has a capacity of 4 MBytes.
It comes in an 8 pin surfacemount package,
which is not all that hard to work with. It's a pretty
straightforward application of the SPI protocoll.
Two things are a little more difficult. One of them is
the write protection mechanism. It is nice of SST to be
careful about my data, but after all, I would like to
write something at some time. So we have
to break open the write protection mechanism. First there
is a WP-protection pin, that has to be high. In that
situtation, it is in principle possible to write to the
status register, that controls the write protection. You
can do that with a Write Status Register command WRSR.
But before that, you have to enable the writing of the
statusregister with an Enable Write Status Register
command. But that command is not allowed, unless a
Write Enable command has been sent before it. For all
these instructions you have to handle the chip select bit,
that belongs to the SPI protocol. When you have found
all this out, it is not terribly complicated, but after
you've read the spec, you couldn't feel sure about it.
It is about trying. In the object file Flash.mpo
there is a function called fl.open which does all
this. It involves a call to fl.wren, which is used
in many places.
The other difficult thing, is that this is a flash memory,
and you don't write to flash memories just like that. You
have to erase it first. You can erase the memory in blocks
of 1024 longwords (there are 1024 of these). When the block
is erased, all bits are just 1. While writing, you can
change any bit to 0. If you try to write to the same cell
again, new bits are changed to 0, but nothing ever gets 1
without erasing. There is also a command for erasing the
whole memory. It is the fastest way to erase the memory, but
you erase all your data. All this, of course, calls for some
planning.
The protocol is like this. You send a command number, and
then the adress, split to 3 bytes (which would be good
for 16MBytes, but 2 bytes of adress is insufficient for
1 MByte). And then you send your data, or receive your
data. You terminate this traffic by pulling the chip
enable bit high.
Here are the command codes used:
I have made a file system for the flash memory.
I tried to do it for the SD-card, but I haven't been
successfull yet.
The key issue for a file system is that you should be able
to erase files. After you've done that, you have some space
left. If you try to squeeze in a bigger file there, you
have to give up. If you have a smaller file, you will get
an even smaller space left. As you write and erase, the
memory space will be more and more like a Swiss cheese.
The trick to handle this, is called fragmentation.
You divide all files in equally sized fragments. When you
have erased your file, a number of fragment spaces will
be free to fill with fragments from your new file. If the
new file is smaller, then some fragment spaces will still
be free for future files.
The fragments are kept together by links. So when a
fragment space has been filled, you have to find a new
fragment space elsewhere, and then you write a link to
that fragment space, last in your current fragment. When
reading the file, we have to follow these links through
the file.
In operating systems like Windows, there uses to be
a program for defragmentation. This might seem as
a cure for the fragmentation disease. But fragmentation
is not a disease. It is a necessary part of a file
system. But - for physical memory devices like hard disks,
it's better if the fragments are not physically too far
away from one another. To move from one part of a hard disk
to another, far away, may take maybe a millisecond. It doesn't
sound like much, but if you have to do that thousands of
times, when reading a big file, it gives you a very noticeable
delay. Hence, defragmentation is about moving the fragments
of a single file as close to one another as possible on the
surface of a hard disk.
You may think that a file system is much about creating a
hierarchy of files with so called directories. But all this
is just a name issue. Say that you have a directory
c:\propeller\mps and that you have a file there called
flash.mpo. Then the actual real name of that
file is c:\propeller\mps\flash.mpo. Now, if the
systems thinks you are "in the directory"
c:\propeller\mpo (and informs you about that with
e.g. a prompt), then the system will automatically add
c:\propeller\mps\ to the filename you write. So
if you write the filename flash.mpo, you will
automatically get the right filename. This gives you the
impression that the file flash.mpo is in
the directory c:\propeller\mps\. In fact, all
files are all over the place on the disk, specially as they
are fragmented.
My file system is much simpler, when it comes to names. A
file name is only 3 bytes long, i.e. three characters. It
doesn't allow for any system of directories, but it is
enough for my purposes. The fragments of the files coincide
with the blocks of the flash memory, i.e. they are
1024 long words. That is really a little too much, if you
have many small files.
Then there is a file catalog,
which takes up the 64 first longwords of memory block 0.
Each file here is represented with its name in the first
three bytes of the longword. The last byte contains the
block number, where the file begins. This allows us to
let the files begin in the first 255 blocks. But then
the files can continue in blocks with higher block numbers.
After the file catalog, in block 0, follows an account
for which blocks are busy in the memory. Each block has
a bit for this. So we need 1024 bits, which takes up 32
longwords. Block 0 is always marked as busy, as it should
contain the file catalog - and this busy accounting
structure. The busy accounting structure is called
occu.
In each block, words 0 to 1022 are sequentially filled with
data, but the last word is the link to the next block.
When we try to write data there, we should observe that
this place is reserved for a link. Then we should find
a new block, by inspecting occu. We prefer to look
for free blocks above number 255, as the lower numbers are
good to have as first block in each file. We don't need
to erase the new block, because we assume that this is done
either initially, or when we delete a file. After we
have chosen a new block, we just write its number
in cell 1023, and then we move to the new block,
and write our datum there.
The file catalog and occu belong to a block in
the memory. Such a block can not be handled easily, as
we cannot change data in the block without erasing the
entire block. Due to this, we have to create a mirror
image in the Propeller of this block. We keep the two
mirror images updated by writing mutually, whenever
anything changes.
There is a danger in this for battery driven equipment.
The computer will stop working when the battery falls
under a certain level. This is likely to happen when
a block erase of the memory occurs, as a block erase
consumes pretty much current. If so, the computer is lost
in a precious moment, when it should restore the file
catalog after it has just been erased. I've seen this
happen. The file catalog is gone, but with some detective
work, I can still read the files. But with the file
catalog gone, it is impossible to manage further writing
to the memory.
Of course I can't be
quite sure about the causes of this loss of the catalog.
The state of an individual file is just, except for the
data we have written into the memory, a pointer to where
we stand, and are ready to read or write. (In this system,
a file is either being written or being read, never both.)
The pointer is practically three variables. One is
block, which is the block where we stand, and the
second is pos, which is where we stand in position
within the current block. The third variable is called
bit, and tells us which bit we are currently
reading or writing. It would allow us to write and
read the memory bit by bit, but right now it is
only used to read the memory byte by byte. But
normally, the file system regards the files as
files of longwords. (Slightly unconventional, but
I prefer to view the Propeller as a longword machine,
and then it is practical to regard the memory as the
same.)
The file system is built according to the principle of
a class, and instances of a class. This means that the
variables that belong to the file, i.e. block,
pos and bits are arrays. The index to the arrays is the
last argument to every function. (This is what was called
unit numbers in Fortran). So you can open a file with
index 3, and write data to it with that index. At the same
time, you can have another file with number 2, which is
completely independent.
Files are files of longwords. The file system, as mentioned,
is kept in the flash memory. Thus, the file system serves
as an interface to the flash memory, where the flash
memory is completely invisible to the user.
Here's how the functions at file.mpo are called.
The file index (Fortran unit number) is called k:
Lately, the EEPROMs as described above have come in a
version with 1024 kbits, which could maybe be enough
for some applications. Problems I have had with a
GPS logging system, encouraged me
to make a try to use these memories for GPS-logging.
In that application, I store three longwords per seconds.
That is 12 bytes, and the memory has a capacity of
128 kBytes, so I could store 10000 samples, which is
well over 2 hours. If I would like more, I could change
to sampling every 2 seconds.
First a note about these components. The 1024kbits is
organized as 128 kbytes. To adress that space requires
17 bits. But in the protocol to control these components
over I2C, we only send 16 bits. Rather than
changing this, the manufacturer has chosen to send the
17th bit in the device adress. That device adress consists
of the device code (hexadecimal A) + three free bits + a
read/write bit. The three free bits were supposed to
to match values set to three input pins on the chip.
Now, the first of these bits is instead used for the
17th adress bit. Previously we had 3 bits, so that we
could build a battery of 8 chips. Now, with only 2 bits
left, we can only build a battery of 4 chips. The chip
still has three adressing pins, but now we can only use
two of them. For some reason, it has been decided that
the third bit has to be connected to the voltage supply
line. If you forget that, the memory won't work. This
is described in the data sheet.
The EEPROMS have the advantage over the Flash memories
I've used, that I can write to individual adresses.
That means that I don't need any mirror areas in the
computer. As I had some problems with that (see
here), I decided to build
a file system for the EEPROMs, as an alternative, and that
is now what I use in the GPS logg application.
Writing to individual adresses is fine, but it comes at
a cost. Firstly, writing an individual byte takes as
long time as to write a whole page of bytes, and this
is about 4ms. If you write individual bytes, this is
the average time it takes. If you could buffer your data,
and write a whole page at once, that again would take
4ms, so your average write time would be much shorter.
But the maximum write time would still be 4ms. But
there is more to it than that. EEPROMs, which are in fact
flash memories, wear out after a milion writes or so.
When you write individual bytes, the memory chip still
has to write the whole page. So the number of writes
is much bigger giving the EEPROM a shorter life. But
for the applications I have in mind, I don't think this
matters too much.
Then, another thought has caught me. In my other file
systems I had a global array of pointers to point at current
block and current position. This was fairly costly, so I
decided to have only single pointers, and then I could
make them local, by letting them be field variables in
my file system object. That would mean that I could
only hold one file open at a time. But this is not quite
true. If I manipulate files in separate processes, I
can handle them individually. The pointers are local
variables, and so there are instances of them for each
process (cog).
The end of this, is that there are no global variables
at all. The file catalog and occ are in the EEPROM only,
and the pointers are local field variables.
The EEPROM has pages of 128 bytes (the smaller EEPROMs have
pages of 64 bytes). I like to see the
memory as a memory of longwords, and then the pages
are 32 longwords. The first page, Page 0, is used for the file
catalog. With that I can maintain 32 files. The
next page is used for the correspondent of occ, i.e.
as an account for which pages are occupied by files.
There are altogether 1024 pages, and these can be
represented by the 1024 bits of the 32 longwords in
page 1. Page 2 is reserved for a single filename for
the GPS application, so actual data are stored from
the Page 3 and up.
Then, files are stored in "fragments" filling up one
page each. In the file catalog, each entry consists of
a three byte (character) file name, and then a pointer
to the first page. Then, when a page is full, a new free
page is sought for, and a link to that new page is
written into the last word of the page. The EEPROM, unlike
the other flash memory, is never erased completely, so
to be sure, whenever a new page is reserved for use,
a pointer 0 is written to its last word. This 0 will
be overwritten by a new link, when the page is full.
Specially, in the GPS applicatione, there is never time
to write an end-of-file-symbol, because logging ends
when power goes away, and then it is too late to write
the end-of-file-symbol. Then, the end of the file is noted
when a 0-link to the next fragment appears.
To read the files, one just follows the links
through the fragments, until an end-of-file-symbol is
encountered, or until a 0-link is detected. In the latter
case, we have usually read a little too much, but it is
not always a problem. When deleting a file, we have to
follow the links, and set the corresponding bits in
the words in page one back to zero again. And we erase
the entry in the file catalog. But no actual erasing of
data is necessary.
Here are the functions of the object in fileE.mpo,
where the 'E' of course symbolizes the EEPROM:
Potentiometers can be good as human interface devices. Their outputs can easily be connected to A/D converters, and those are controlled by functions in the standard object file std.mpo. Some other interface devices require a little more.
The object file key.mpo contains a relatively simple
collection of functions for handling a standard
ps2 keyboard developed for the PC many years ago.
The ps2 communication was a serial communication protocol
not quite unlike the SPI protocol.
The communication is handled
by two function kb.rec and kb.send. Unlike
SPI, the communication is clocked by the keyboard, so
as a receiving computer, you have to be alert to catch
when the operator hits a key.
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 complaint 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
is the function that has to be alert at all times.
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, but they do reflect the position the key has
on a standard English keyboard.
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 return that.
As long as we keep a key pressed, a call to key.ascii
will return the ascii code of the key. When the key is
released, the function key.ascii will return 0,
which is the ascii code for the null character.
Right now, I have a numerical keyboard, rather than a full
size keyboard, as it is handier. Then, to produce figures,
I use the keycodes, that the numeric keys have on the
so called numpad part of the keyboard.
So the functions to call are the following:
As an amateur, you can buy a type of touchscreen formerly
used by Nintendo. They are cheap and simple to use, but
of course they don't compare with modern touchscreens used
in smartphones. They are still usefull, but you need a little
stylus to handle them; they don't work well with your
fingers.
They are resistive devices consisting of two conductive
sheets, which can be brought to touch one another, when you
press them. One of the sheets has two horizontal metal bars
up and down. The other has two vertical bars right and left.
Say that you apply high voltage (3.3v) to the upper bar,
and low voltage (0v) to the lower bar. This will create
a potential field that varies linearly over the sheet.
Then you connect say the left bar to an
A/D converter, and let the right bar float.
The high impedance of the A/D input means that there is no
current through the second sheet, so the voltage over
the second sheet will be constant. When the two sheets
touch one another, that voltage will be the voltage at the
contact point. In this way, we get a measure of the
y coordinate of the point of touch. To get the x coordinate,
we just have to shift the roles of the upper an lower sheet.
To put this under program control, we connect all four
bars each to its own Propeller pin. For the active sheet,
we make them output pins, and give 1 and 0 to them. For
the passive sheet, we set the pins as input pins. Then we
connect two of these pins to input channels of the
A/D-converter.
We also have to detect the situation that the touchscreen
isn't touched at all. For this we connect one of the
A/D channels to 5 volts through a reasonably big resistor
(10 kohms should be good). This resistor will pull out
the voltage to values, where it couldn't be if there were
contact.
Here are the functions of the object file touch.mpo,
and how they are called:
An accelerometer is not in itself a human interface
device. It's a sensor. But you can use it to build a
joystick.
Those who sell accelerometers use to say that they can
be used to measure two things: acceleration and tilt.
In fact, they can measure none of them, but just a
confusing mixture of them. The deeper reason for this
is that acceleration and gravity are indistinguishable,
which was the basis for Einstein's foundation of the
General Theory of Relativity.
But this means, that if we don't move the accelerometer
with too much vigour, we can sense its tilt angle.
Then I've built the accelerometer into a plasic
tube with a heavy brassfoot, that makes it stand up:
The accelerometer is padded in there between two
pieces of plastic foam.
If I grab it and tilt it, I can read off the tilt
position, and use that to control a program.
But you can also mount the accelerometer on a vehicle,
and use it to measure acceleration. But remember: The
signal is always disturbed when the sensor is tilted.
The code is made for an acceleration sensor called
Memsic 2125, which delivers pulses, whose widths vary
with acceleration, and with a width of 5 ms for no
acceleration. These accelerometers are sold by Parallax.
Electrokit in Sweden sells an accelerometer called
DE-ACCM2G. It has direct analog outputs for the
acceleration, so with an A/D converter, they are easy to
use. It has a range of +-2g, which is more than you need
for the joystick application, but there is a +-6g version
also. SparkFun sells, among others, an accelerometer from
Analog Devices called ADXL335, which is probably of very
high quality. It is a three axis accelerometer, while the
others mentioned ar 2 axis. The outputs are analog (I think),
The object acc.mpo, which works for the accelerometers
from Parallax, has functions to be called as follows:
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 optical sensors are
reflex detectors, which consist of a light source (IR-LED)
and a light sensitive component. 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.mpo handles two strips and two sets
of optical sensors, to determine movements in the plane.
The functions are called as follows:
This is a very simple object, that handles a three color RGB-LED. The use is maybe most for debugging. You can get a certain color, when you come to a specific place in your program, or when a variable has assumed a specific value. To make it simple to use, the object has no init function. You call the only function in the object col.mpo like this:
Here are download opportunities for object files already mentioned:
Here's an object file for objects that are so called
complex numbers.
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)
We start with this abstract and somewhat involved matter,
as it is used by some of the applications below. It is
about communication between a Propeller and a PC. Once
you have that, you can use it for building human interfaces,
for data collection and for debugging.
The PC communicates with the Propeller over an RS232 link
connected to pins 30 and 31. This link is used for
uploading and starting programs, but it can
also be used for sending data to and from the PC. As
PC:s don't have RS232 interfaces nowadays, the RS232 goes
to a device called Propstick, which contains a module
from FTDI, which converts RS232 to USB. Inside the
PC the serial communication is converted to something
called Virtual Com Ports. In some software sense, these
virtual ports look like real RS232 ports, so you can
connect serial port software to them.
Unfortunately there is no such software in Java. There
was once, and there still is for Linux and Unix. But
the Windows version has been abandoned by Sun. So
I need to use Java Native Interface
together with C code. Having done that, I have almost
made the work that Sun and Microsoft could have done
together.
If you study my C code, you can see
that I am not exactly a C expert programmer, so you are
welcome to improve my code. I have a 32 bit Borland C
compiler, so I have to compile my Java code for 32 bits,
which I do by using an older version of JDK (Java
Develpment kit). Here now are the basic pieces of code
for communicating.
Once I made a box containing a Propeller Computer,
A/D converters,
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 then I made a more modest project. It was a smaller box
containing a Propeller computer together with the standard
EEPROM and the standard 5 MHz crystal, an A/D converter,
an RGB LED for debugging etc. and circuits for voltage
supplies. Originally it had D-sub connectors, but later
I've switched over to RJ45 network connectors.
These are
nice to click in, and they work well. On the female/chassis
side they are a bit difficult to work with. They are connected
to wires like a flat cable through soldering, but it's a
bit tight there. Some suppliers sell breakout boards for
these connectors, and that's much better, but it makes it
a little more difficult to mount the connectors mechanically.
On the box I've mounted the connectors on a plexiglass bar,
but that requires some machining. The male connectors are
much easier to work with, and you might consider using
male connectors throughout and use male-to-male-adaptors.
Note then, that these are not so easy to mount. You can try
to drill and thread a hole in them, but that almost
inevitibly destroys the device.
The male connectors are cheap. You get five or so for a
dollar. And you connect the wires with a simple crimp tool
in one step without soldering or stripping cables. But you
need a flat cable with a division of 0.1 mm, and they are
not all that common. More common is 0.127 mm (1/20 inch) but
that doesn't work. You can also push single wires into
the connectors, if they are thin. That's good if you only
use few of the connections.
Here's the circuit board itself:
The picture is a little old. Since it was made, I have
mounted a few more EEPROM:s to contain more software,
though I don't use that right now. There are also some
more connections to the card.
Here, the board is put in its box, and connected to the
RJ45 connectors:
Here is the "programming side" of the box: There is a
power supply input, and a reset button, and then three
RJ 45 connectors. The leftmost of them is for programming
through the FTDI USB circuit. The middle is for connecting
to a similar box containing the RAM memory. The last
connector is for 6 of the analog inputs. On top of the box,
you can maybe see a grey little spot. That is the upper
end of a nylon screw, threaded in the lid, that acts as
ray guide for the light from the RGB LED.
On the other side of the box, there is just a row of
5 RJ45 connectors. The two leftmost are universal outputs
giving acess to 6 Propeller pins each. The second of them
also connect to two analog inputs, for use with the
touch screen. The remaining connectors use fewer of the
outputs. The rightmost connector is for connecting the
keyboard.
Bluetooth has been replaced with Zigbee, but the Zigbee
modem is now outside the box, and connected through one of the
RJ45 connectors when needed. The power amplifiers are
separate units also connected through RJ45.
The FTDI programming unit ("Prop-stick") is built into its
own little box with a USB connector and an RJ45 connector.
The white button has to be pushed while programming to
enable reset of the Propeller. When it is released, the
box can be used for RS232 communication between the
Propeller and the PC.
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 MPS code has to know that. So the MPS 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.
(This figure is slightly old, so it still has D-sub
connectors rather than RJ45 connectors)
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.
Download remote.mps.
Download zig.mpo.
This picture shows the wheel steamer
I built it together with my son, when we were in the
countryside
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.
A robot equipped with stepper motors has the advantage
that it moves with precision - as long as the hold torques
of the motors are not exceeded by obstacles on ground.
Hence, it is possible to build a navigation system based
solely on the commands given to the robot. The simplest
case is if the robot moves in either of two modes: forward
motion and turning. As long as the robot turns, you just
to update its estimated heading. As it moves forward
you can update its position in the direction of its heading.
But you can generalise this to any type of control. Then
when the robot knows where it is, you can design control
algorithms to go to given points, or to follow given tracks.
Right now, I have just designed the robot, and connected it
to the Zigbee receiver to receive commands.Here it is:
The stepper motors expect a voltage of 7.4 volts and pull
280 mA. For that the hold torque is 650gcm. It is not
terribly much, so the robot behaves best on a plane floor.
The robots are driven by two Lithium batteries connected
in series. They are wired in such a way that they are
charged in parallell which seems to work. Don't try to
charge them in series. If you do that, you need a balancing
cirquit. Also don't charge them with anything but a
Lithium battery charger. Otherwise, you risk overheating
and exploding batteries. The wheels are made in plexiglass
(in fact the other wheel is made in delrin, as I had ran
out of plexiglass), which is cut round and the smoothed
in a turning lathe, and surrounded by O-rings. I use my
standard motor driving cards (you need two for two stepper
motors) and a third card with the Propeller and the Zigbee
receiver mounted in an old Kodak film can. As I use my
standard cards, the wiring looks pretty messy. The robot
balances on two brushes. which makes it an excellent home
cleaning machine.
Here are the programs to download:
stepper.mps.
stepper.mpo.
zig.mpo.
Note how simple the main program is, as it uses the
object file stepper.mpo so effectivly.
This is a project that requries a good deal of mechanical
skills. Nevertheless it is quite interesting.
A force arm is used in virtual simulators to provide
mechanical feedback to a user, who otherwise gets his
feedback from looking at the computer screen. If the simulator
is for education, the force feedback can enhance the learning
a lot. The situation is that the operator holds some sort of
"pen" in his hand. On the screen he can see in a perspective
image the tip of the pen together with different
obstacles. When the tip touches an obstacle, a force should
be fed back to the operator through the arm.
Such an arm is not an easy thing to make, and the ones
on the market are quite expensive.
The normal principles of force arms, is to provide
forces from torques of motors. Big forces require big
torques, and that requires big currents, even though the
motors have a special design to provide high torque. The
high current problem also induces a cooling problem. If
you try to use a gear box to provide more torque, you get
a new problem: friction. You would drive the gearbox
backwards, to speed up the motor, and that gives a lot
of friction.
The story has a connection to the Swedish Gripen aircraft.
Some experts argued strongly that the pilot must be given
a force feedback in the control stick, so that he could
feel what he did. But the cooling problems forced the
decision to leave out the force feedback in the stick.
I don't think that was terribly important, but after an
accident, some people claimed that the lack of force
feedback was a major cause of the accident. I think they
were wrong.
My idea is to use geared DC-motors! I think you can come
around the problem of friction, by measuring the torque,
and creating a feedback from that to the motors. The
result is an arm, that is worse than professional arms,
but after some work, it is still quite good, and I think
it may be useful for many things,
If you have a force arm, you also have a robot arm, which
can move around to different positions automatically, and
you can do this with different methods, and also combine
position motion and force control.
Here it is:
Maybe you can see that it is only a two dimensional arm.
Everything moves in a plane. The way to create 3 dimensions
is probably to mount the whole arm arrangement on a plate,
and move that around a vertical axis.
You can also see the stick or "pen" sticking out from the
arm. It is connected to a joystick, so it would be possible
to measure the angles of the pen relative to the arm,
but I haven't done that yet.
So our first task, is to measure torque. What is torque
(moment in most other languages)? Well, if you mount a
lever arm on a motor axis, you will note that the length
of the arm is important. If you have a longer arm, you get
smaller forces. So any motor is characterized by the
product of the length of the lever arm, and the force
generated at the tip of the arm.
This product of arm length and force,
is called torque. If you have a fix lever arm length,
measuring force is the same thing as measuring torque.
There is only a fix scaling between them.
I argue strongly, that the only way to measure force, is
to give after for it. You let the force act on a spring,
and then the spring is deflected, and you can measure
the force by measuring the displacement. Ideally, you can
have a very stiff spring. That allows you to measure forces
with very little displacement, which may be a point. But
then you must be able to measure very small displacements.
So, probably there is a balance to reach. In my arm I use
a flat spring, consisting of plexiglass! It may seem to be
a pretty odd material to build springs of, but I think it
works. So, the torque bends the plexiglass spring, and
you want to measure how much, by measuring a displacement
caused by the bending. How do you do that?
Not long ago, I tried a so called pressure sensor, which
is a thin film device, which changes its resistance
depending on pressure. In that case, the displacement is
very small. But I found that they weren't very stable.
For the same constant pressure, their output varied
pretty much over time. Further, they don't measure negative
pressure, so you have to make some mechanical arrangement
to bias them with a constant pressure.
Another idea I had, was to use an optical reflex detector.
It has an LED as a light source, and picks up the reflected
light with a photo transistor. If you have a white surface,
they should give a high signal. But not if you place the
sensor too close to the surface. Then efficiency goes down,
and you can measure the deviation from the ideal distance.
It works fine, but the noise level is pretty high.
The next idea is to use a magnetic field sensor, and a
magnet. When the magnet comes closer to the sensor, the sensor
gives a stronger signal. It is a very non linear relationship,
but you can find a range, where the relation is linear
enough. The sensor is based on the Hall effect. The whole
sensor is a little integrated circuit. You need to
find a linear circuit. Most circuits are logical circuits,
which can only distinguish between magnet and no magnet.
The magnet can be a neodynium magnet if you want something
small, and as long as you can afford one; it is said that
the price for neodynium is going up. The signal has a
reasonably low noise level, and as long as you manage to
build a stable mechanical system, they are stable over
time. It is important to mount the sensor firmly. If you
put it on a small circuit board, and let it hang in the
wires, you will get stabiltiy problems.
Here's a primitive drawing of the arrangement:
Distinguish between the arm and the bar!
The arm is a U-shaped aluminum profile. It hangs over the
axis, which is a brass cylinder. The axis has
a diameter of 12 mm, so this is the size of the holes
in the arm, but they should be made with some precision,
to avoid backlash. The motor's
axis enters the axis through a hole, and is locked
to it with a stop screw.
The axis is flattened on two sides.
To it, the plexiglass spring and the bar are fixed
with a common through-going screw. Note, in the left figure,
how there is a u-shaped hole in the arm to give place
for the screw. The other end of the plexiglass spring
is attached to the arm, but with a washer or two to
avoid that the spring lies flat on to the arm's surface.
The bar is a square brass rod. This is nice and
stable. Aluminum might work, but maybe not plexiglass.
At the end of the bar, there is a steel screw, which the
magnet likes to adhere to. The magnet can be moved to
an optimal position with the screw, and then the screw
can be locked with a nut. The bar moves relative to the
arm, as the spring is bent. This is measured by the sensor.
The sensor I found is a trapetz shaped little thing. I've
mounted it firmly in a hole in a piece of plastic, which
is screwed to the arm. The hole should be
close to the surface, so it may be easiest to make the
hole first, and grind away material afterwards.
The sensor has three pins. Solder a ribbon cable to them
and lead that down the arm to the electronics.
This is one arm unit. To get a double arm, to allow
movement in the plane, we could put the next arm at
the tip of the first. But the weight of the arrangement
would probably be forbidding. So we mount the second
unit at the same base plane, and then connect that
unit to the second part of the arm through a mechanical
link. This is easy, if we mount the two units so that
they have common axis line, i.e. the two motors are
coaxial.
The link arm is a round aluminum rod. It is tied to
an aluminum plate, which goes out from arm #2 in a
right angle. For these links I use screws, that are
tightened to one of the members, and threaded into the
other. You can see this arrangement here:
The motors axes are somewhat unsteady, so I have built
a little support block in plastic where the two brass
axes can rest. You can see this in this pictures:
Schematically, we have this arrangement:
The little circle marks the end of the arm at position
(x,y). From there, the arm acts outwards with a force F
with the two components (Fx, Fy).
The position of the arm is controlled by the two angles
α and β. Note that with the link arrangement we have,
the second arm unit controls β directly. If we had put
the second arm unit at the tip of the first, that unit
would control β-α, which would be more difficult.
Now we realize, that we need to measure α and β, which
we do with potentiometers (if not anything more advanced).
But as the motor are coaxial, there is hardly space
for any potentiometers directly coupled to the motors,
so we have a link arrangement to drive the potentiometers.
Look at the photographs to see these link arms in white
plastic.
A somewhat open issue is whether the potentiometer should
be connected to the motors or to the arms themselves.
The good side of connecting the potentiometers to the
motors, is that we entirely eliminate the friction of
the potentiometers. But there is a slight difference
in position between the motor and the arm. When we
build feedback loops around the arm, this difference
can easily destroy stability. Here we have connected
the potentiometers to the arm, and hence we should look
for potentiometers with low friction.
Now, some mathematics. We can compute x and y as:
x = l1cos(α) + l2cos(β)
y = l1sin(α) + l2sin(β)
So this is a function that we would implement in our
system, so that we could base the computation of forces
on position.
But you could also differentiate this equation, to get
the relation between the rotational rates of the
motors, and the velocities of the arm tip. But it
is even more interesting to invert this relationship.
The differentiated equation is linear, and so it is
described by a matrix. That matrix can be inverted. In
doing so, you need the determinant of the matrix. It
is (after using one of these trigonometric rules):
D = -l1⋅l2sin(β-α)
When this is zero, you can't do the inversion. When is that?.
Well, it is when α=β. In that case, the arm is fully
streched out. You can wave with the arm, but if you
want to move the tip of the arm closer, it takes a great
change in α and β. Here, then is the equation:
ω1 = (1/D)(vxl2cosβ+
vzl2sinβ)
ω2 = (1/D)(-vxl1cosα-
vzl2sinα)
So now, given a velocity (vx,vz)
that we would like to give the arm tip, the equation
gives us the rotations we need from the motors. Typically
we control these just by the voltage supplied to the motors.
We may think that we have a goal point of the arm tip.
We can compute (vx,vz) so that it is
directed straight from the current position of the arm tip
to the goal point. We have to scale the velocity, so that
it depends on the distance. Now, when we start the
feedback, the arm would ideally move from any point to
the goal point along a straight line. It doesn't quite,
because of the transient behaviour, when the motors speed
up. Also saturations in the motor control amplifiers will
alter the behaviour. But sometimes it works quite nicely.
This is called kinematic control.
Before we go to dynamic control, we should mention shortly
geometric control. Then, given a position that
we would like to move to, we can use our first equation
to compute corresponding angles α and β. It is a
computation, that involves arctangents which is a little
complicated, but it can be done. Then we construct a
feedback from the α and β potentiometers to the motors,
to bring α and β to the desired values. The motion of the tip
is not along a straight line
and it is hard to compute the exact track over long
distances, but of course it works.
Dynamic control is about controlling forces, and
that is what we started to talk about. So the question is:
What is the relationship between the torques of the motors,
and forces at the arm tip? It doesn't sound all that trivial,
but it is almost trivial, if we think about a situation of
equlibrium. Let's grab the tip of the arm, and hold it
firmly, to prevent any motion. The forces it takes to
hold the arm are exactly the force by which the arm presses
onto my hand. If I released my hand, the arm tip would
move just as if it were affected by the same forces.
The forces from the motors, and the forces from my hand
are the only forces present, except gravity, which is
negligible. So we let my hand be there, and compute
the balance between the hand forces and the motor torques.
Here's the result:
Fxl2sinβ+
Fyl2cosβ = M2
Fxl1sinα+
Fzl1cosα = M1
Here, we don't need any inversion. The equations gives us
exactly what we want. Given some force
(Fx,Fz) that we want at the arm
tip, we can compute the torques immediately, and we can
achieve these torques through our torque feedback
mechanism.
Then we can make a position feedback by computing a
force from the deviation in position. But that't not
necessarily a good idea. But, let's go back to the
original idea, of pointing at a "virtual object" on a
computer screen. When we touch the object, we would
get an outward force. But that is a feedback from position
to a force. And back from the force to the position,
there are two integrations. So, there is no damping.
Fortunately, the inner mechanisms in motor control helps
contribute with some damping. The motor current controls
torque. And the motor current depends on the applied
voltage and the winding resistance. But not while the motor
moves. Then the generator effect of the motor is in
charge, and it reduces the current. This helps up
stability.
But what happens in real life? Well, if you drop a metal
ball on a table, the ball suddenly experiences an
upward force. So it accelerates upwards, and then it
bounces. But the bouncing stops, because some energy
is absorbed in the table and in the ball at each hit.
And this has to do with the characteristics of the
forces that repell the ball away from the table.
With a force arm, we can attain stability, by designing
the repelling forces somewhat smoothly. But it doesn't
work unconditionally. If we hold the arm firmly, we can
usually get a good behaviour, but if we hold the arm
more loosely, it can start oscillating. Manufacturers of
expensive force arms claim, that they have solved this
problem, but I remation sceptical. The problems are
very fundamental consequences of ordinary mechanical laws.
Now to an application: The window cleaning robot.
The normal engineering approach to this would be to have
the robot arm tip move over the plane where the window is.
Then it would have some brush or so. But if the window is
just slighly closer than we thought, we would crash the
window. And if it is just slighly farther, we would just
clean the air. What we want is a given force normal to
the window, to press the brush against the window for a
good result. In the remaining dimensions, we would move
over the surface of the window. So we want dynamic control
in one direction, and we would perhaps prefer kinematic
control in the other two. But as far as I have understood,
it is difficult to mix dynamic and kinematic control. So
we must work with dynamic control throughout. It's OK.
We can control position through force feedback. The
friction of the window will provide us with damping. We
keep imagining that we have a three dimensional arm, so
we have a force vector of
(Fx,Fy(x-xc),Fz(z-zc))
where (xc,zc) is a position that slowly moves over the
surface of the window, while Fx is a constant
force suitable for window cleaning.
As you know, I just have a two dimensional arm, so I can
just clean a one-dimensional window. Furthermore I have
laid the window down, so this is maybe a factory facility
for cleaning windows before delivery.
Here's a picture of the setup:
As you can see, the window is not even a window any more,
but a Java book. And the pen and joystick arrangement
has been replaced by a bullet. (There is a workshop
technique for making nice smooth metal sufaces, by
pressing a bullet against the surface. In Swedish, it
is called kulpening, which sounds funny even
in Swedish.)
Here are the downloads:
The chua circuit, built by Leon Chua, was the first
successful try to build an electronic circuit, that could
produce chaos. Until then, chaos had only been made in
computers, though in some cases these computers were
analog computers. I tried to mimic what Chua did in
his circuit with my arm. but so far, I haven't made it.
You have an unstable oscillation around a center. So the
tip of the arm moves in a spiral with increasing
amplitude out from the center. On its way out it will
come close to a second center, and when it comes close
enough, it will switch over to spiral about that
center. As it is now close to its center, the amplitude
of the oscillation will be small. But it will grow.
In this way, the spiral will come close to the first
center, and will oscillate around that. And so on.
The information about which center the system shall
spiral, will have to be stored separately, so it is
a (boolean) state variable. The other two state
variables are the position coordinates. So altogether,
there are three state variables. One can prove that
it is impossible to make chaos with fewer state
variables than three.
So, one would like to see the arm move erratically
around the two centers. What failed to me, was that
my motions around the centers were always much more
unstable than I expected. Probably that is because of
the long sampling timed. Those who know about
Runge Kutta's integration method might do something.
The dynamic control of an arm is actually a special case of a procedure called exact linearization. There is an established theory for how this is done and when it is at all possible by the Italian differential geometer Alberto Isidori.
Recently, I rebuilt the arm electronics, so that it has
its own dedicated computer. Then I replace the keyboard
with two manual switches, A push button controls the
debiasing of the torque sensors. and microswitch activates
the motors (through software). Furthermore, I have done
away with the display.
I have also built a second arm, which copies the position
of the first (through kinematic control). That second arm
has a little force sensor, whose force signal is fed back
to the first arm. Then you get a force feedback when the
second arm hits something. I'll come back to this at some
later time.
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 reference position.
This is computed with Pythagoras' theorem and the
itsqrt function in std.mpo 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.
Download Odo.mps
Download Odo.mpo
Download std.mpo
Download Display.mpo
The last object file is for an alphanumeric display sold
by Parallax. It lets you type characters on the LCD display
just by sending the ASCII-codes and some command codes.
But, of course, you could also use the Adafruit display
presented earlier.
This is a new version of a USB oscilloscope. It's based
on an A/D converter from MAXIM, called MAX118, which is
capable of sampling at more than 1 MHz. It has 8 bits
resolution, which isn't so much, but it simplifies
programming, as the whole result can be delivered in a
single byte. The result is delivered from the converter in
parallel form,
which partly explains the relatively high sampling
frequency.
To use that speed. requires some efficient
programming. This is done in the panalog.mpo
object file, and involves some preparatory works making
masks for adressing the converter rapidly.
Additionally, the device can log 6 bits of data sampled
directly from the input pins of the Propeller.
Data are then logged in the Propeller global RAM. There
is space for 7000 longwords, which means 28000 bytes.
This is pretty much, so you have good opportunities to follow
what happens in your system under investigation.
Data are sent over the USB to the PC
at the end of logging, and then they can be displayed
immediately with a plot program.
Here's a scetch of the cicuitry:
Note that the inputs to the A/D-converter are not drawn
in the order, they appear on the chip. You have
to consult a data sheet.
To the left, there are 4 different
analog circuits with different properties.
Here's a process and an mpo file for make the same
thing for variables inside your own Propeller software.
This allows you to plot your own variables. Put
the process into your mps program, and mention it in
your exec field. Then you should declare 4 global
variables u0, u1, u2, u3. Then you can write values
into these variables anywhere in your code, and then
these values can be plotted. To do this, open
OscNy.java on you PC. Hit the V-key on your
keyboard. The control window will display the word
"Variable", which means that you display Propeller
variables. In this mode you can't set anything else.
The sampling time has to be set "hard wired" in you
Propeller logging process. Now, hit the spacebar,
and you will see your variables plotted.
The values are stored and processed as bytes. These
are the least significant bytes of u0 ... u3.
In your Propeller program you should also declare
the area where you logg your data as
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
the sky.
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.
A commercial digital camera is an impressive thing.
It has an image sensor that gives something from 0.5 Mpixel
to 12 Mpixels. Then it has a display with maybe
1 MPixel, and there is electronics that transfers the
pixels between the two
so that you can see the image in real time. That calls for
an update rate of at least 20 Hz. 1 MPixel in color is at
least 2 MBytes (16 bits per pixel in color information). So
we have a data rate of at least 40 MBytes per second.
That is far more than you can achieve with standard serial
protocols. And it is not only to transfer the bits; you have
to get them out from the camera sensor and into the
graphical display. Furthermore, there is the JPEG
encoding of the pictures, which is far from trivial.
If we would like to do something as amateurs, the best thing
is probably to get some sort of camera sensor
with a standard RS232 or SPI output. That means that the
manufacturer of that sensor has solved most of the problems
for us. But it gives us a camera, which we can use for
things like robotics applications.
There used to be such a camera called C328. It had an auto
baud rate detection, which could maybe be nice, but I never
got it to work reliably. The newer version is called C329,
and it works better. I still have some difficulties syncing
the data, so I have a special fix for that.
A somewhat odd alternative is the latest version of
the CMUcam, developed by Carnegie Mellon University.
This version uses a Propeller processor, but it seems to be
a missuse of a Propeller. The point is, that, like all
microprocessors, the Propeller has far from enough memory
to store a whole picture. The solution would be an external
RAM. But CMU's solution is to download the entire picture
several times, and screen out a single row each time.
This gives an exposure time of a picture of 3 seconds (!)
of more.
Back to the C329! It comes in two versions, RS232 or
SPI. Probably it is a good idea to buy the SPI version,
but I didn't! The point is, that with SPI, the master, which
is the Propeller, controls the clock pulses, and can thus
get itself the data at a rate, that it can handle. With the
RS232 alternative, the camera pushes the data, and
there is always the risk, that the Propeller is flooded
with data. This rules out direct writing into SD-cards. While
the SD-card shifts write page, data are unavoidably lost.
So with the RS232 camera, data have to go to the RAM
first.
The C329, like the C328 can send you a JPEG encoded
(compressed) picture,
which is nice, if you just want to send your image to a
PC, which has facilities to make JPEG decoding. But
JPEG decoding in a microprocessor, like a Propeller, seems
to be an overcourse.
For the uncompressed image, you first
have to choose a color format. My choice is the 16 bit
format (two bytes per pixel) where red green and blue take
up 5, 6 and 5 bits respectively. Then we get "files" with
two bytes per pixel.
The "camera" comes as a breakout board with an optical
sensor and electronics, but the lens has to be ordered
separately. There is a lens holder which fits to the
breakout board. But the threading of the lens or the
holder was so poor, that I needed to make my own lens
mounting. The threading of the lens is very fine grained,
so I didn't think I could make such a threading, so
instead I mounted the lens in an O-ring, which worked
as lens holder.Then the whole thing was mounted in a
little box.
Here's the camera mounted on a "Gorilla pod":
The system now consists of the following: The camera and
its lens, a Propeller, the RAM, an SD-card and a keyboard
for control of the system, and the RGB-led. When turning
on the system, there will be an initialisation of the
camera. Unfortunately, before doing the initialisation, the
camera has to have its power off. Then, the successfull
initialisation will be signalled with a green LED signal.
Then, when the operator hits the enter key on the
keyboard, a picture will be taken and will be stored
in the RAM, and then displayed.
Now to the mysteries. The camera sends some data before
the actual picture. Many data. It seems to vary a little
too, and I haven't found out how that works. Safest is to
put everything into the RAM. If the numbers of bytes is
odd, the color bytes will change place, so the colors look
really odd. To get it right, I shift the adress to the
RAM a little, under control of the keyboard. In that way,
by displaying the picture a couple of times with different
shift, I can get a nice picture.
Then I'm almost ready to store the picture on the SD-card.
But to do this, I first have to choose a place on the card.
As mentioned, I don't have a file system on the SD-card,
so I have to choose an adress space manually, again with
the keyboard. Then I store the picture, and the RGB-led
shows again, when the storing is done. Then I can use
the picture display program, presented next, to show the
picture. And it is possible to write a program that uploads
the picture to a PC.
Here now some information about initialisation of the
camera. This is done by means of the cam.mpo
object file.
The camera wakes up with an expected baud rate
of 14400. We will change that to 155200, but it we want
to initialize the camera again, we have to bring it back
to 14400 by removing power. Then the first to do is a
syncronisation procecure. This is done with a sync command.
All commands
start with $FF $FF $FF (three bytes with only 1:s). Then
follows the command number in one byte,
and 4 bytes with parameters. Unused parameters are coded
with 0.
The sync command has number 13 ($0D) and no parameter.
The receiver of such a sync command is supposed to
respond with an acknowledge command. This has number
14 ($0E) and the first parameter is the number of the
command responded to. So we expect that response from
the camera ($FF FF FF 0E 0D 00 00 00). We wait for it 25 msec, and then
we give up, and try again, and we do that for a maximum
of 200 times. The administration of the waiting i done
in the function cam.wack. Now when sync is hopefully
successfull, the camera will send a sync command to us,
and we should respond to that with a $FF FF FF 0E 0D 00 00 00.
Then it is time to set the camera parameters. This is done
with command number 1 and the following parameters:
So far, this program is a little bit scetchy, but it allows
you to look att pictures stored on an SD-card. So far, the
program only uses single hits on the keyboard, which controls
the showing. Hence the number of pictures to show is limited
to 16. The pictures shown are of three different formats,
and the encoding of which format each picture has is put
directly into the program. So improvements are possible.
The three formats are the following:
This radio is based on a chip from Airoha called AR1010.
In a volume of 4x4x1 mm3 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. Read about that
here.
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 Si4703 radio chip is an alternative to AR1010, and
it is maybe more accessible than AR1010 nowadays. It comes
on a breakout board from Spark Fun, which contains
a radio chip, a few discrete components, including a crystal,
an earphone amplifier and plug, and connections to a computer.
Programming Si4703 is about as confusing and difficult as
programming AR1010. There is example code to fetch from
Spark Fun written for Arduino by Nathan Seidle.
But Arduino has I2C communication
built in, while with a Propeller, we have to do it ourselves.
But, we have already done that. Also I think that the
Nathan Seidle has overdone some things a little.
Apart from the example code, there is a data sheet, and
a programming manual. The programming manual is OK, but it
has to be read together with the data sheet. The necessary
information is spread somewhat randomly between the two
documents.
The device can be controlled with two communcation protocols.
One of them is clearly I2C, but this is never
mentioned, so it's called "2-wire interface". There is a
reset pin, that you bring down for reset. When you lift it
again, certain states have to be present, to take the system
to the 2-wire interface mode. There is an inverted SEN-bit,
which has to be high, which it is on the breakout board thanks
to a pull up resistor. Then the SDA bit (in I2C
terminology; it is called SDIO on the board) has to be low.
Finally a GPIO3 has to be low. That's a bit bothersome,
becaulse that pin is also a part of a crystal oscillator.
But, be calm, It is low. So bring the reset pin down,
the SDIO pin down, and then lift the reset pin. Then the
device wakes up in I2C mode, and we can start
I2C on our side by calling iic.init from
Iic.mpo.
As is usually the case, I2C devices are handled
by writing to and reading from a couple of registers, in this
case 16. But they are written and read in an unusual way.
The device has default register addresses
for reading and writing. It starts there, and then
it increments its adress counter for every 2 bytes. It's
comfortable, but it means that you can't write to a single
register without writing to a couple of others too.
For some reason I failed in programming a register read
function. It reads all right, but it somehow destroys the
register contents. Nathan Seidle advices
us never to write to registers without reading them first.
The data sheet gives you the same message. But the programming
manual says: "The data sheet tells you what the registers
contain, and you can trust that, so it is not necessary to
read the registers." So, I accepted that, and it made the
whole task a lot simpler.
Now we come to the mysterious register 7. The first bit of
this register controls the crystal oscillator. You want that,
so you would like to write that register. The programming
manual says: "Write hexadecimal 8100 there". Then the first
bit is set, as wanted, and another bit for some unknown
reason. While we write register 7 we have to write all
registers from 2 to 7, but it's OK to write 0 to all of them.
Now, the crystal oscillator wakes up, and we should give
it about half a second to stabilize.
Now, the device is in power down mode, so we have to lift
it to power up mode. We do so, by setting the last bit
in register 2 to one. It is called Power enable. For some
reason they want us to set the next highest bit too, so
we do that by writing hexadecimal 4001.
While we do that, we can write to the rest of the registers
too. Register 2 to 7 are writeable. Most bits in these
registers are set to default values, that serve us well,
but, at least, if we are Europeans, we have to adjust a
few things. To reduce noise, the transmitters send
the higher frequencies of the sound with higher gain, and
you should compensate this in the receiver. This is
called deemphasis, and there is a special bit for setting
European deemphasis, while the default is for American
deemphasis. The UHF band is different in Japan on one side,
and America and Europe on the other. The American European
standard is default, so we don't need to change anything.
Then there is the channel separation, which is 0,1MHz in
Europe and 0.2MHz in America, so I have to deviate from
the default there. That's about all. Setting of frequency
and volume, will happen later.
Now the radio is powered up. In 110 ms it is ready to use.
For some reason, the mysterious register 7 now changes
from 8100 to BC04, but that happens by itself. So no worry,
but you shouldn't set the register to BC04 directly. Then
the radio doesn't work.
All this is the content of the function radio.init
in radios.mpo. It uses its own function
radio.writeregs and various function from
iic.mpo.
Then volume is set by writing the four LSB's of register
5.
Setting frequency is only slightly more complicated. First
we have to convert frequencys to channel number. If we
give frequency in the unusual sort of dMHz, which gives
us all frequencies as integers, we only need to subract
the UHF-band-bottom frequency, which is 875 dMHz, to get
the channel. We write that to the LSB's of register 3,
where we also write the first bit to one. That will trigger
the tuning in the radio. Then we have to wait for the
radio to react, and then we send the same information
again, but with the tuning bit reset.
Here's the code for download:
I won't give all the details of this application, which
is a media player, which can play radio, MP3-files
and TV sound through full size loudspeakers. Here's
what it looks like:
As you can see, there are no knobs and buttons on the
device, except a power switch to the right. Instead it
is controlled entirely from a remote control. To see
what you have done, there are two RGB-LED's. You can
also see the MP3-player through a slot. I had to put it
that way, so that the micro-SD-cards, that contain the
music, could be pushed in. The back part of the box is
a little higher, and black, so you don't see it (do you?).
It contains the power supply and the cooling element
for the power amplifiers. On top of the box, there is a
smaller box, that contains the micro-SD-cards. They contain
the content of a heap of vinyl LP-records, that is about
2 meters high.
Here's the remote controller:
It communicates with the player over proto ZigBee. It
has two knobs, one for volume, and one for selecting
MP3 files. And four buttons for choice of Radio, MP3,
TV or nothing. And there is a power switch, to save
batteries. It consumes pretty much.
The control computer in the player is, of course, a
Propeller.
The radio is AR1010 as in the previous section. The
way this device is placed, there is a better antenna.
The MP3 player is a little board, sold by Spark Fun
Electronics (and resold in Sweden by Lawicel). The
music is loaded in micro-SD-cards on files with standardized
names TRKxxx.MP3. You choose file number xxx by sending a
command over RS232 to the board, and then the board
plays the music. There may be many of these boards around.
Choose one that let's you control it from a computer.
Then we make the whole thing electrically controllable
by using analog electronic multiplexers and electronic
volume controls.
The electronic multiplexer has the designation CD4051.
It may not be easily available any more, but some sort
of electronic multiplexers should be available also today.
More correctly put, these circuits are called analog
multiplexers, and they consist of analog switches. An
analog switch is a digitally controlled switch. with
either a low or high impedance from an input pin to an
output pin. By the way, the device is symmetric, so you
can swap the input with the output as you like. As long
as the signal that goes through the switch is well away
from the supply rails, the switch has a low resistance
in the on state. There is some resistance, and it varies
with the input voltage, but if you load the circuit with
high impedance, the on resistance is negligable, so
you can get an analog signal through with low distortion.
I supply the circuit with 12 volts, and to bring the
input signals away from the supply rails, I lift them
from ground with 6 vots from a voltage divider. That
DC component has to removed later on.
CD4051 has three adress inputs, and with them you can
choose between 8 different inputs going through to the
output. The control computer has to provide these three
adress inputs through 3 computer pins. So the computer
interface is "parallel".
The so called digital potentiometer, MCP41010, also has
analog switches. In fact it is a conventional chain of
resistors, as in "a discrete potentiometer", and analog
switches lead the signals out from some place along the
chain. The digital circuitry that handles these analog
switches is controlled over an SPI bus. (So now we have
a parallel interface for the multiplexer. SPI for the
volume control, I2C for the radio, and
RS232 for the MP3-player, and ZigBee unit, so it is a
good exercise in computer communication.) The digital
potentiometer has to be loaded with high impedance
to keep distortion down, so this section ends with an
operational amplifier OP290 in a follower configuration.
But the digital potentiometer, with its 10 kohms is good
as a high impedance load of the analog multiplexer.
The power amplifier is based on the TDA2050 power operational
amplifier as mentioned before. I use two for each channel.
One is configured as a non-inverting amplifer, and the other
as an inverting. Then I can connect the loudspeakers between
the outputs of the two amplifiers. That gives me twice the
range I can get with a single amplifier. Furthermore I can
adjust the two amplifiers, so that the difference between
the outputs is close to zero. Then I don't need any
output capacitors. But do this adjustment well! It is
said to be harmful for a loudspeaker to be driven with
DC current.
The voltage supply is a switched 12volt supply of the type
that is used for PC:s.
I enjoy this machine very much, and now I can play my
records pretty much effortlessly. No more carrying of
LP-records, and no more handling of pickups. Unfortunately,
by the time I built this, for some unknown reason, my
ears started working much worse than before, so I am not
the right person to judge the sound quality, but it's good
for me anyway.
When I mention something about this application, some
people say: "I have it in my smartphone". Such are the
conditions for us "do it youselvers" nowadays. Everything
is already in the smartphones. What is the meaning of
life, then?
On the other hand: Doing the whole thing of GPS navigation
is hardly anything for us amateurs. There are a number of
satelites out there, and they send us their opinion of
time. When we compare these times from some different
satelites, we observe, that they don't coincide. But then
we have the theory that this lack of coincidence depends
on that it takes unequally long time for the time signal to
arrive to us from the satelites. With that, we can determine
differences in
distance to the different satelites. As satelites move
very regularly up in the empty space, we know where they
are, and then we know we, ourselves, are. Down to an error
of three meters or so! But that is not an easy computation!
Errors are a little bigger if we move in a forrest (or a
city) because the signals reach us after having bounced
a little between the leaves of the foilage. This growth
in error is quite fundamental, and there isn't much we
can do about it.
Let me say something about giving positions. The earth is
a ball. Then the surface of the earth would be a sphere
if the ball were perfect. How do you indicate position on
a sphere. Well, there would be many ways to do it, but
one of the best is to give longitude and lattitude.
First, then we would need a reference point. It is natural
to let that point lie on the equator. But where? Well, it
would be a point with longitude = 0. So where is longitude
0. Well, it's at the Greenwich Observatory, or at
Constantinople, at the Cheops Pyramide or in Paris. In fact,
for some time it was both in Paris and in Greenwich, but
finally the French had to give up.
The story continues this way: Someone placed a metal plate
at the Greenwich Observatory, and engraved a fine line in it.
That was where the zeroeth longitude went by. But then the
Americans made a radio navigation system, which pretty
quickly gained great popularity, and become a world
standard. It was not until after that, that someone came
up with the great idea, that one should place a receiver
at that engraved line at the Greenwich Observatory. The
receiver said "108 meters east (or west, I don't remember)
of Greenwich". So it was
wrong! But it was much more difficult to correct the
American Radio Navigation System, than to just move
the zeroeth longitude. So now it is 108 meters off
the Greenwich Observatory.
Then you move south along that zeroeth longitude point,
until you hit the equator. As long as we have the rotation
axis of the earth, that is actually well defined. The
point we find is the reference point. It has longitude
0 and latitude 0. We can imagine a ray going from the
center of the earth, out to the reference point. Then
we rotate that ray first around the earth rotation
axis, and then around an axis perpendicular to that, so
that the ray points at some given point. Then, the two
angles are longitude and latitude for that
given point.
Now, when the earth isn't spherical, we have choices.
The choice made has to do with so called Inertial
Navigation, which in aviation is often combined with
GPS. The result is, in practice, that these rays don't
start at the center of the earth. The key idea is,
that in each point on Earth, there is a plane (called the tangent
plane of the earth's surface) whose normal is vertical.
in the sense that it falls along the
gravity vector. To be precise, that vector gives
the direction of the sum of two forces: the gravity
and the centrifugal force, that comes from the Earth's
rotation.
The net effect is that, if we materialize that plane, a
ping pong ball put on it, wouldn't roll away, but stay
where it was. Now we have a z-axis as
the normal of the plane. We can fix one more axis, the
x-axis, by letting it point North, which means that it
points into the Earth rotation axis. Then the third axis
is given as an East axis. So this is the North East Down
system. It may seem unnatural to have one axis down, but
that is required to make the whole system a right oriented
system, which is desired. Now, we can make a similar system
in the reference point at the equator. Now the story is
to rotate the reference point coordinate system into the
local North-East-Down system. After we have done that, we
can make the two systems coincidence completely with a
translation, but we don't really care about that.
The longitude and latitude are now truly rotations.
This definition requires a model of the Earth. If the
earth is so irregular, that we couldn't hope to model it
as something "mathematical", we could still go along with
huge tables and the like, but it would be very complicated.
But luckily, the Earth can be modelled pretty well as
a so called ellipsioid. The German astronomer Bessel made
such a model in the 19th century, and up till a few years
ago it was a basis for the Swedish geometric system
called RT90 and its predecessor RT38 (Rikets Triangelnät 1938).
But then, when GPS was to be born, one found it worthwhile
to make av revision, and that lead to a new ellipsoid
Earth mode called WGS84. From that the geometric system
of Sweden has been revised to something called Sweref.
These geometric systems are about defined reference points
marked out in nature, and about map projections.
But the notions of longitude and
latitude are well defined, as soon as the ellipsoid model
is given.
The problem with the longitude and latitude is that we get a
very anonymous and long series of figures. A confusion is how
"Babylonian" we should be. Things like degrees and minutes
and seconds (arc seconds) are Babylonian in style, in that
one divides by 60, rather than by 10 and 100. The compromise
is that positions are given in degrees and minutes
with decimals.
All this is delivered with figures (and decimal points,
commas and the keywords E and N for East and North) encoded
in the Ascii format and delivered as RS232.
. This information is collected into
"messages" called GGA etc. These messages belong to a
standard called NMEA.
If you are connected with your Microprocessor to a GPS
receiver, which delivers these messages, you have some
work to do. One task is to throw out all messages you
are not interested in. I took the choice to pay
attention only to the GGA-messages.
A good GPS may deliver about
10 such messages per second. You may want to keep just one
message per 2 seconds. Then you might like to acquire some
data in numerical form, rather than as text strings.
One unfortunate property of the latitude longitude system
is, that differences in longitude (from one point to
another) are not comparable to differences in latitudes.
The longitudes run together as you approach the Poles.
We can see that in a commonly used map projection called
Mercator (from a Dutch merchant called Kramer, which means
merchant, and whose name was latinized to Mercator). It
just plots points on the Earth according to their
longitude and latitude, but to keep proportions intact,
the scaling in the northerly direction grows as you
approach the Poles. Hence you can never show the Poles
themselves. In such a projection, Greenland is about
as big as South America, while in reality, Greenland
is only as big as Venezuela and Colombia together. As
another example, Norway stretches in longitude from
Marseille in France to Alexandria in Egypt. Globally
we cannot do much about this. Whichever trick we try,
we loose something to gain something else.
But in a local neigborhood of some point, we can do
a linearization of the Earth's surface, which amounts to
working on the local tangent plane there. The trick is to
measure differences in latitude and longitude relative
to a reference point, and then
scale the differences in longitude with cosine of
latitude (This holds for a spherical Earth. For a true
ellipsoidic Earth it would be a lot more complicated
but no matter). At the same time, we could scale everything
to meters. For that, we convert the angles (longitude
and latitude) to radians, and then (after scaling of
the longitude) multiply by the Earth's radius, which is
approximately 6360 kilometers. With the format of the
GGA-messages, we get the angles as an integer that
represents the longitude and latitudes in 600000:ths of
a degree.
Right now, I have one such reference point in Sweden.
The data I get can be plotted, and the plot gives me
an image of my track, which is correct in directions and
proportions, and I can sum up my distance travelled.
So these positions is what I log in my on board memory
together with time in seconds since noon at Greenwich
that day, and together with the number of satelites
used. All this fits into 3 32 bit numbers, which I store
in a flash memory.
So here's in summary what the program has to do:
This is the GPS logging program itself. The file also contains some processes so that you can verify functions over your PC. In the exec field there are som different alternatives. The one calling pcchar will show you the stream of data from the GPS receiver. The one calling pcmess will show you the GGA-messages at the rate you keep them. The version calling pcpos will show you the positions in meters. Use the program Propp.java for this. (We will return to Propp.java in a while) The version without comment marker (--) is the one that loggs data.
The program gpsread.mps communicates with the Java program Propp.java. It is presented here. The program lets you send and receive data to the PC. When data come from the PC, they act as commands to GPSread, and they make GPSread send responses to the PC. The commands (that you type in the third textfield in Propp.java:s window) are these:
Then the perhaps most interesting thing to do with
your data is to plot them with Google Earth. For that
you need a GPX-file. GPX is a format which is a special
case of the XML format. The file contains data
strings, which describe longitude and latitude.
Isn't that sad? Didn't we just transform those data to
relative positions? Well, take it easy! The mapping we
used there is invertible, specially if we are less than
510 km away from the reference point. Look into the
position function in GPSLogg.mps. It's a fairly
simple linear function (as long as we don't have overflow).
Find out what the inverse mapping is and write into
the program GPXget.java (Download information
will follow)
There are instructive comments on how to do that in
the program. It just amounts to replacing some constants
to values that you have used in your GPSlogg.mps.
Now run GPXget with the filename witout '.gps'.
This will give you your GPX-file, which has the same name
but with '.gpx'.
Now start Google Earth, and open the open menu.
There is a choice to choose so called 'gps-files' If you
do that, your new gpx-file will appear. Double click on it
and answer OK to the next question. Then Google
Earth will zoom into the area where you travelled, and
show you trip.
The program GPSget.java gives you a more straight
forward plotfile of your navigation data. Its name
is p[originalfilename].dat.
It's a readable
file, so you can look at how it is formatted in for example
Notepad. Then you can maybe find a plot program for that format
or a small revision of it. The plot will give you a
plot scaled in meters with correct proportions and directions,
if you manage to get the scaling in the two directions
equal.
To get even more interesting data, you could run the program
Dist.java. That will give you a similar file
called p[originalfilename]V.dat, and it will contain
two more variables: Distance travelled, and velocity.
If you walk, the velocity variable will seem very
noisy, but if you go downhill skiing, you can at least
see if you ski faster than you go skilifts.
Here's a picture from Google Earth:
This is a kayak tour around some islands at my sommer
place. I also made a slalom tour around the pylons of
a bridge. You can see how the track seems to be a few
meters east of the bridge. I also went up a bit into a
small creek. It may seem that I paddle on land a few times
but that's only because Google Earth has difficulties
in separating shallow water from land.
Here are the Java source file downloads
The latter three are utility classes that are needed for all four programs. But Propp.java needs more. Refer to this place for the details.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.
After having spent lots of time on waiting for Windows to start up, I decided to switch to Linux. I bought a new computer with Linux Ubuntu installed. For the Propeller, I installed a Linux Propeller environment. It works fine, but I miss the possibility to run it from a command line call. Always with Linux, one has to consider, that Linux distinguishes between small and capital letters in filenames, which creates a great deal of work.
USB has to treated a little differently in Linux. USB has to be used, as serial communication goes over USB in the so called Prop Plugs. In Windows, Java doesn't have good support for USB, so you have to use C/C++ code and so called ports. In Linux, they have the view, that a USB port is a file, called /dev/ttyUSB0. This isn't quite true, though. For a file, you have a program, that has to read a file. A port, on the other hand pushes data into the PC. That difference causes some problems sometimes, but mostly it works to read USB-data in this way. It means that the read function is blocking, while it is waiting for data from the port. Sending data to a Propeller through a write to /dev/ttyUSB0 seems to work without problems.
The Linux program screen is also a usefull tool. Screen is a very complex program with an enormous help file ("man screen"). It is a screen or window, with a process behind it. This means that you can't close the program by "crossing" the screen, because that doesn't stop the underlying process. Instead you enter a command mode with ctrl-a, and then issue a 'k' for kill. You are asked if you really want that. So the whole command is ctrl-aky. Things you type in the window, goes out on the USB, and can be received by a MPS ()pc.rec function. Things sent with an MPS-call ()pc.bsend appear on the screen so you can see the results of your MPS efforts. Then you can enter the command mode with ctrl-a, and then a colon (:). This allows you to enter less anonymous commands like 'hardcopy -h filename'. The selector -h is important, because it gives you also the data that have been scrolled out at the top of the screen. Now you have your data in a normal file. This procedure may seem a little clumsy, but it gives you a good feeling for what happens.
This switching to Linux has worked out well, and I am not going back to Windows again. It is fortunate of course, that I have used Java, which works equally well and unchanged under both operating systems.
I have mentioned something about this already. In a fully object oriented language, an object is an instance of a class. You create and name such an instance with a constructor, and then this instance is available, independantly from any other instance of that class.
In MPS this is not so. If we call a constructor (usually named initsomething, we don't get anything with any identity, so that we can distinguish one instance from another. In Java, the identity of an instance lies in a pointer, though Java had some aversion against the pointer concept, so it never mentions the word pointer.
The Ada language was not originally an object oriented language, but in the later versions, they augmented it so that it could handle instances of classes. The idea was a little like this: An instance consists of two parts: variables, which are called field varables, and functions, which are called methods. For different instances, the field variables are different, while the methods are the same. Then Ada arranged the field varables in arrays, selected with an instance index (or pointer if you don't have the aversions). Then, when you call a method, you have to supply it with the correct index, for your desired instance, so that the method could work with the right set of field variables. So practically, rather than an abstract pointer, you have a concrete index.
I tried this idea in MPS, but it did become a little costly, so right now, I don't have that array of field variables.
The field variables are in a way a representation of the state of the instance. In many cases, this state is not very dynamic, but just static. You assign values in a constructor, and then they never change. Then, when you want a new instance, you run a construtor for that. Now, the original instance is gone, so if you need it again, you have to run its constuctor again. So now your second instance is gone, but you can run its constructor again if needed.
Then, if you use these instances in different processes, you don't need to worry. The field variables are physically different variables, if they belong to diffent processors.
An example of use of this is a class for SPI communication. Different instances of the object, correspond to different SPI channels, connected to different Propeller pins. So the field varables are the different pin numbers for data out, data in, clock, and enabling devices. And all these data are static. They do not evolve during the use of the bus.
The SPI class corresponds to a file called Spio.mpo and it contains
Using batteries is sometimes handy, like when you build mobile instruments, remote controllers, robots etc. Modern LiPo batteries are good for these things. They contain a lot of charge per mass unit.
But beware: You shold only charge them with chargers designed for LiPo batteries. Also, these batteries shouldn't be charged in series. The reason is that some cells can have a lower voltage. The charger tries to give the cells the right total voltage. As a consequence, the good batteries become overcharged, The remedy to this is to use a balancer which bring charge to the bad batteries from the good ones.
I have preferred instead to charge the bateries connected in parallell, though I'm not absolutely sure that it is safer than series charging with a balancer. But so far, I have not seen any problem.
The ones you buy now contain built in protections against discharging and overcharging. If you discharge a battery too much it is no easy to charge it again. But the protection cirquits help you against that.
Here's my design for a litium battery power source.
The batteries are connected independently to four pins, to which you can couple plugs. The "use plug" connects them in series, and the voltage then goes to stabilizers which gives 5 and 3.3volts. A charge pump Intersil7660 gives you a negative voltage, which may be useful if you have analog operational amplifiers. I have omitted capacitors connected to the stabilizers, but they are now often built into stabilizer modules. For charging, you use the "charge plug" connected to an authorized charger for Litium batteries. As the batteries are now connected in parallell, you should put the charger in an 1S mode. Finally, if you want to save battery, you can connect a AC power supply with the "Supply plug". Then the batteries are disconnected from the circuitry.
Here's a supply box:
I use it for some of my designs. Others have the batteries built in, and other are driven by AC power supplies.
The GPS logg was down for some time. Without much hope I bought a new GPS receiver, of the same type as I had before. To my surprise that worked. The problem was that there had been very few position fixes for some time.
I've built the system into a little round plastic box, which I can carry in my pocket (it is not the worlds smallest plastic box, but its OK). Nothing electrical comes out of the box, and the box is waterproof.
I have also simplified the storage in the on board memory a little. The new file system for this is in the file filee2 .mpo. The files are no longer fragmented. The data are stored in a long array at consecutive adresses. The current adress for storing is saved in the EEPROM itself at a given adress (32). The data array then starts at adress 33. Below 32 is a "file catalog". The files don't have names; they just have numbers. The first adress for each file is stored at that number. Up to the reserve word 32, there are 31 such slots, which make up for the file catalog.
The point is this: If there is a power failure, but the system starts up again, the startup procedure will create a new file. It gets its place at the first free slot in the file catalog, and from there it points to the first place for data, which is at the adress after the adress stored at position 32.
We can now see that data have been distributed over more than one file, and we can paste these files together. But we can also pretend not to observe this, and just read all the data as a single long file. It will contain points of discontinuity, if the power interrupts have been long, but it may not be harmfull.
Like previously we need a reset program for clearing the file system. It resets the 31 first positions to 0 and clears the content at adress 32 to 0. In fact, it clears some more EEPROM words, just to make the action a little more visible.
More important than these things, is the switching to Linux, which requires a new procedure:
On that last point, Google Earth seems to have abandoned its services for plotting gpx-files. I found the website share.mapbbcode.org, which works just as well. Open the website, and hit the "import" button, and choose your file filename.gpx, and the system will zoom in to your track.
Most files are unchanged from previously, but filee2.mpo is new, and the Java files may have changed.
Many languages allow you to define symbols, and assign values to them, without reserving space for any variables in the computer memories. The symbols are handled by the compiler only.
I found it worthwhile to introduce this in the MPS language too. Syntactically, the symbols are single lines defining a symbol name and its value, like
badluck = 13Such definitions are placed in .mpo-files between the keywords defs and enddefs
The definitons are then loaded with a load-command
load from (Termi.mpo)i.e. the same way as a function is loaded from an .mpo-file.
*defs
Then the mps-program can use the definition with the code ?badluck The question-mark, would mean "What is the value of this symbol?". The compiler will then replace "?badluck" with the value 13.
Here we don't need to store the value 13 in a separate variable in the Propeller. But the Mps-code is more readable, as we can figure out what the number is supposed to mean, or represent. The compiled code (Propeller assembler code), on the other hand is not more readable, but it is not supposed to be.
Here's the terminal:
It is a box that contains:
The picture shows an example, where the Mandelbrot set has been drawn again, but now with a host using the terminal. After that, a program has turned on the RGB-LED with green light, but the graphical display still shows the Mandelbrot set. The camera has dimmed the light of the LED pretty much. It looks better in real life.
The orders are sent as
Morse messages.
In the image above, you can see the link as "rainbow
cable" entering at the front. It contains power, as
5 volts and ground, and a bidirectional Morse link.
On this link, the host sends orders to the
terminal, and the terminal sends acknowledgments
back to the host. (You can also see how the link is
also a bus - an order bus - which continues to some
other terminal)
The host is supposed, not to send any new order, untill the acknowledgment has arrived.
Physically, the two Morse wires connect pins 26 and 27 on the respective Propellers.
The terminal software has
The task processes are essentially loops around a series of if-statements, which check if an appropriate command has come. If so, the task is executed, usually with a call to a function. After that, the execution goes on to a common point, where the sending of acknowledgments is administrated.
Normally the acknowledgment is the command itself, but sometimes, when the host asks for some value, like the content of a memory cell, that value is returned instead. Right now, I let the acknowledgment process administrate this difference, but there is a global variable x for the value to be returned.
There is also a simple "internal acknowledgment" at the common point, in that the order variable is reset to 0.
The host helps itself with an mpo-file TermI.mpo ("Terminal interface"). It contains symbol definitions corresponding to the different commands. The terminal imports these same definitions, so that the two systems are coordinated. TermI.mpo further contains a ti.init function, which establishes the Morse communication. ti.send0 sends a command, and ti.send sends a command together with a single argument.
But TermI.mpo also contains some composite functions. This is due to the fact that a command can only have one argument. A typical example is the task to fill a rectangle on the display with a color. The terminal will need to know the boundaries of the rectangle as N(orth), S, E and W -limits, and the color. These arguments are set by orders like setN, setS,... and setcolor. A composite function
( N , S , E , W , color , )ti.fillrectcreates these suborders, and also the final order,which fills the rectangle. This makes the writing of host software easier.
There is an extra complication with all this. The reason is that a single process can't handle everything, that controls the graphical display. First of all, there is (as usual) a process for initializing the display. When its job is done, it leaves over to another process in the same processor, to do the rest of the job. But now we need yet another process to handlle the display.
The display in my case is handled through an SPI protocol. It means that pins are connected to pins on the display for clock, MOSI, MISO and enabling.
It is easy to see, that a Propeller has 32 pins (GPIO-pins). But in fact it has 32 x 8 pins, 32 for each processor. They are connected to the physical pins through a network, which essentially or:s the 8 different pins together. Now if a pin for some processor is 1, then no other processor can make itself heard; the output is 1 in every case.
So, what we have to do, is to disconnect a processor's output pin, when that processor doesn't want to communicate over that pin. This amounts to changing that pin into an input pin. For the display, we have a gra.connect function, which makes output pins. But now we also need a gra.disconnect function to make input pins
When the terminal software wants to make something with the display, it connects to the display. But the other process has to disconnect itself.
This is handled with an "internal order" in the form a global variable, called dproc (for "display process") When a process notices that dproc doesn't point to itself, it disconnects itself from the display. It also resets dproc to 0 as an "internal acknowledge". All this is an extra if-statement in the taskprocess' loop.
The connecting process, say number 1, does its job by calling a little function as ( 1 )setdproc.
With this, the terminal works exactly as one would wish. After it has sent its acknoledgment, it is ready to handle any order. It doesn't need to be turned off, ever. You can reload the host with new code, and run it directly without resetting the terminal. (You can see this in the picture, where one host program has drawn on the display, and another has turned on the green light. Both these effects persisted, so that I could photograph them.)
The terminal hardware is displayed here:
At the left is the Propeller's own EEPROM. It needs a pull up resistor, which is omitted in the figure.
At the far left, you see the input from the host, including ground and 5v, and the bidirectional bus between the host and the terminal, which is connected to pins 26 and 27. (There is a diode at one of the wires. I will comment on that later). The host delivers 5v which has to be reduced to 3.3v. (I could deliver 3.3v from the host, but I fear that I could overload the host's 3.3v stabilizer.) Then, there are 3 SPI-buses for communication withThe RAM and SD-card share a single SPI-bus with identical clock and datapins, which is OK, as these pins are driven by different processes. You can't use these two buses simultaneously, but the terminal software never does two things simultaneously.
The RAM consists of four chips, and thus needs four chip enable wires. The SD-card does with just one
The keyboard is a network of switches. The figure below shows one of the 12 switches, the one closed when key "0" is pressed. These switches connect one row line and one collum line. The numbering of these lines is shown in the figure. The numbering is a little iregular, but it seems to be an "international de facto standard".
The output from the collums send voltages to the Propeller, and these inputs require some pull down resistors, as is shown in the previous figure. In the software downloads, you can find an algorithm for finding out which button - if any - has been pressed.
Finally, there is a catchkey process running in parallell with everything else, and which maintains a value of the global variable key which is the current value of any key pressed on the keybord (if no key is pressed, it delivers 15). A getkey order will deliver this value as an acknowledgement to the host.
That same process also handles the RGB-LED, helped by an object file col.mpo. It contains two functions:
The following orders could be found in Termi.mpo as definitions. I split them into some categories. Texts within [ ] are comments.
(In this list, I have placed the arguments of the command after the command, unlike my convention in MPS.)
sdflush means the following. When writing to the SD card, you first write to a buffer in the Propeller. The buffer is written to the card, when it is full. sdflush means that the buffer is written anyway. read, write, sdread and sdwrite include that the adress is incremented.Text can be written to the display in the following way:
Termtest.mps is a test or demonstration program. Look into it and try to guess what it tests.
Term.mps is the terminal software. TermI.mpo is the interface between Termtest.mps or any other host program and Term.mps.
Analog inputs and output might be nice parts of a terminal. But the terminal box is full, and most of the Propeller's pins are used. So I made a new, analog, terminal. It is not so picturesque, but I will still show a picture of it further down.
Here, instead, a hardware diagram of it.
It has
To the upper left, you can see the orderlink to the host. Here I will explain the diode in the acknowledgment line back to the host. We have two terminals now. And both want to send acknowledgments. The Morse communication "rests" at zero. Hence, to be able to send messages from two or more sources, we need to or the signals together. The diodes are parts of an "oldfashioned" hardware or-gate. Another component required is a parallell resistor at the host's input pin. Without it, the impedance of the propeller's CMOS input, might very well exceed the backward impedance of the diodes.
The ADC and DAC are straight forward SPI-components. The ADC has 8 input channels. You choose them with the SPI protocol. In the order, the channel choice comes as an argument. The DAC has two outputs. You choose the channel with two different commands. Both take the value to convert as an argument.
There are four "free" analog channels, going to input pins of the terminal. There is one channel connected to a potentiometer with a knob at the panel. Two analog channels are reserved for the touch screen. All four outputs of the touchscreen are connected to Propeller pins, but two of them also go to two analog channels. They are controlled from functions in the Touch.mpo object file. How they work is described here. (In fact, I thought that the touchscreen was broken. These Nintendo screens are not easy to find nowadays. But, I tested it, and it worked!)
The power amplifiers are parts of so called H-bridges, each with two amplifiers. They come in pairs in modules. I have two such modules, so I have a total of 8 such amplifier, but I have only connected 6 of them. They should be regarded as "binary", so you feed them with either 0 or 3.3 volts. (What else could you? They come from Propeller GPIO-pins!)
They could be used to control motors through PWM (pulse width modulation). They could also be used to control stepper motors. This is done in separate paralell processes, which can be turned on and off with orders from the host.
The parameters to these processes are set in a task process. There are three pulse width fackors called pw1, pw2 and pw3 for three different motors. And there is an angle set value xc for the stepper motors. The stepper motor process has a state x, corresponding to xc. It is the angle of the motor measured in units of the motor step size. When x and xc differ, then the process steps the motor and increments x, which goes on untill x=xc. Hence xc is a motor angle command, though with an undefined null point.
Here now, a list of orders to the Analog Terminal:
Just a reminder: If the host wants to send an order adcget(channel), it makes the following function call:
( ?adcget , channel , )ti.send
The output from the touchscreen can be called xy. If it zero, then the touchscreen isn't touched. Oterwise you can find x and y with:
xy >>8 ->y
xy &355 ->x
Here finally, the promised picture of the Analog Terminal, sitting under the Terminal. They cooperate on the task of drawing a picture from the touchscreen on the display.
You have seen this before, but now this is made as an application of the Terminal Order System.
(The terminal has a foot, so that it slants a little outwards, to make the reading of the display easier.)
The program is called Rita (draw in Swedish), and can be downloaded here
The serial RAM of the terminal is too slow for some purposes. Hence I have also built circuits for a parallel RAM (PRAM). So far, there is not space for this hardware in the terminal box, but that may change.
From a systems point of view, a PRAM is a simple component. You give it an adress and a datum, and activate a write enable signal (WE). Then you can give the same adress, and activate an output enable signal (OE), then the datum written, will appear at the same pins of the memory chip.
The PRAM used is called bs62lv1027 and is from Brilliance Semiconductors in China or Taiwan. It contains 1 Mbit in the form of 131000 bytes (128 kBytes). That requires 17 bits for adressing. To that comes 8 bits of data I/O and one OE and one WE. That is very much, if we also want a Propeller to something else. So I decided to add a special memory Propeller. If we call the other Propeller the host, we divide the labour between the two like this:
A host Propeller and the memory Propeller arranged on two separate cirquit boards are shown here:
So, now the memory Propeller is just a simple adressing
slave.
Like the object file TermI.mpo, there is a file MemI.mpo,
with functions for handling the PRAM.The Morse code for
setting the base adress, is pushed in in the row of
Morse codes for handling the terminal. I think it would
be possible to build a Morse bus for communication between
host, terminal and memory, but so far, I have separated
the communication lines.
Here are the functions of MemI.mpo
Memtest.mps is a test and demonstration program. It stores and remembers ascii codes for characters from '0' and up to '?'. There are some unused processes, that you can try. runtest types the text "Eva Skarman" every time you hit a key. writereadtest is a process that rights and reads the memory in a single process. MemI.mpo is an objectfile for handling the memory from the host. MemA.mps is the code for the memory Propeller (the "adress slave").
Once, I happened to be too generous with supply voltage to my digital camera C329. So, it went to its fathers. Then I thought it would be interesting to buy the SPI-version of it instead of the RS232 version. This turned out to be quite an adventure.
Getting hold of the camera wasn't so easy, and I haven't found any competitor. At the same time, the manufacturer seems to be very anonymous. They have published a users manual for the RS232 version, and then they publish almost the same users manual for the SPI version. But the difference between the two interfaces is important.
In the new manual, they teach us how to change the baud rate of the camera, while a SPI device doesn't have a baud rate. The host simply determines the baud rate, as it provides all the clock pulses. Borrowed from the RS232 is also a sync command. A sync command is completely irrelevant for the SPI-protocol. Then, I thought, that they maybe have a formal requirement on a sync command, just to start the camera. So I wrote sync command software, hopefully to delete, when everything works. So, now I have deleted all that sync stuff!
So now I have an init routine, that sets up the properies of the camera. And I have a get routine, to ask for a picture. You find these in the code to download. Then the picture will come flying over the SPI-line, but before that comes and acknowledge signal, and a data signal, telling you about the size of the image (which you could well calculate youself, based on your get-order).
But then, and some people on the internet agree on that, it happens either, that no picture ever comes, or that not even the acknowledge comes. Everything you clock in is just zeroes. The recommended trick here, is to try again. Send the get command again, and see what happens. 4 or 5 tries may be needed. I wonder why that is so.
This retrying is part of the code, so you don't need to do anything manually.
A problem with the previous camera was, that it was difficult to see, where the bytes from the actual picture started. There used to be a heap of extra bytes of unknown origin. With SPI this was a little easier. If you start to catch the bytes quickly enough after you sent the get command, you will see a number of zero bytes. The first byte received, which is non zero, is usually the first correct byte from the camera.
Color information from each pixel takes up 16 bits, i.e. 2 bytes. So if you drop one byte, you get out of phase with the color information, so you get false colors. That happens sometimes, and the only thing I know to do about it, is to try again (manually now).
From then on, everything is fairly simple:
I use the screen program in Linux to get the data. The principle is the same as for the new GPS. Then I can draw the picture with the Camera.java program with the file name as argument. Here's the download:
Camera.javaYou need the std.package. Handle that as for the new GPS
Well, "universal" is a strong word. So what is it?
You can just anticipate a black box, which is a power supply as desribed earlier. It delivers -5,0,3.3 and 5 volts through a rainbow cable, and a barely visible connector on the left side. The power source in the box is two Litium batteries. Most signals come in through the Dsub9 connector. The knob next to the right is an analog potentiometer, which chooses modes for the instrument. The buttons on the right side of the panel, are used for control of the programs. We call them b1 (at the bottom), b2, b3 and b4. The button top left on the panel is for reset of the software. The display shows the resistance of 5.6kΩ resistance built in to the system. There is also a 2.2μF capacitor. You can disconnect these components with the switches to the left, so that you can measure external "unknown" components. They are to be connected to pins beween the switches and the Dsub connector.
A simple MPS program can't contain all that, so the box has four EEPROMs, each with its own program for the different services. Choose service with the knob to the right, with values 0..3. After having moved the knob, press the reset button to the left on the panel. Then a program is loaded from one the four EEPROMs
Here then an account for the four different pieces of software in the EEPROMs.
This is a simpler version of the USB oscilloscope I have presented earlier. It has two analog channels, with some analog preprocessing. It is not as ambitious as the earlier system. Basically it is just two voltage followers to raise the impedance of the Analog to Digital Converters (ADC). The ADC:s are simpler than the ones presented before. They have a lower sampling frequency, and are controlled by SPI. Also, If you are more ambitious, you should have two rotary switches with resistive voltage dividers, to provide different ranges. Furthermore, there are four purely digital inputs. The bit pattern can be displayed either as four individual bits, och as a hexadecimal number. These connections go directly into the Propeller input pins, but maybe you should have some protective circuits. The Propeller inputs don't tolerate much overvoltage.
You control the function from the PC. First, open the Linux screen program. The instrument should be up and running the USB oscilloscope software (knob position 0). Hit a key, and your data will come flying.There are 5 different sampling rates:
~1μs, 10μs, 100μs, 1ms and 10ms.
The first of these is the fastest possible, and it is
pretty close to 1μs but not exactly. But the system measures
times, so the plotting becomes very exact anyway.
The system samples 7000 samples, so 10ms gives you
70 seconds of measurements.
There are 5 modes.
When you are ready to logg something, start the Linux screen program on your pc and hit the appropriate one of the keys given in the mode table above. Then data are logged, and then data are rolling in on the screen window. First comes time information, so that the time scale on the plots can be established. Then come all the data. On the screen they appear as hexadecimal numbers, two per byte, but the figures over 9 are encoded with :;<=>? rather than ABCDEF.
Now type ctrl-a : hardcopy -h hex.dat.
Then run Osc.java without argument, and you get the plot. A little of how the plotting works can be found here.
Here's the analog cirquitry, based mainly of an OP290 operational amplifier (two ampliers in a chip). It's a follower cirquit with 15kΩ resistance. 0Ω could maybe do as well, but perhaps the 15kΩ resistance enhances stability. The input resistance of 2MΩ is necessary. Without it, the input floats around freely, probably because the ADC pumps out some current. The 100kΩ resistor reduces gain a little, so that the range +-5 volts can be contained. I have also marked out the protection resistor between the ADC and the Propeller. Without it, and driving the ADC with 5 volts, the Propeller input could be destroyed.
The digital instrument measures voltages, and that is done exactly with analog cirquitry presented above. But it also measures resistances and capacitances. This is done with an RC oscillator. To build such an oscillator is quite easy:
You use a gate with hysteresis. SN74HC14 is a high speed CMOS gate, which is very fast, so you can get high frequencies. The symbol for the cirquit used in the picture, tells you what hysteresis is. The state of the system circles around in a rectangle. The frequeny is proportional to 1/RC.
But the hysteresis levels for these CMOS gates are a little bit unstable, so I decided to use an analog comparator cirquit, LM311, instead. It is fast enough, unless we try to measure small capacitors. These should generate high frequencie, and the LM311 doesn't quite manage that, so it might be an SN74HC14 instead, if that is interesting. Comparators "traditionally" have an open collector output, so I need a pull-up resistor, here of 1kΩ. The three resistors of 39kΩ and 22kΩ, make up for a positive feedback network, resulting in a very well defined hysteresis range. Then R and C again define the oscillation frequency proportional to 1/RC
Now, we have a built in R and C, so we get a fixed period time and a fixed frequency, which we can measure, as the output of the oscillator goes into our Propeller. Then we can disconnect R, and plug in a measurment object. But we maintain our reference C, and then we can compute R. And we can do the same, to measure a capacitor. Furthermore, if we remove these reference components, and inject a signal into the cirquit, we can measure the frequency and period time of that signal (provided it is periodic of course).
We switch mode with the left of the two knobs, and then we can see the result on the display. The units displayed should tell us which mode we are in.
The program tries to scale the results, and select units, so that it shall be easy to understand the result.
This program is really quite simple. You can improve it a lot, e.g. introduce minutes (now everything is just in seconds). It has two modes, and they are selected by the left knob. Turned to the left, it invokes the stop watch, to the right the egg clock. Now remember that the buttons to the rigth, from down an up are called b1, b2, b3 and b4.
In stop watch mode, b1 starts the timing, b2 stops and b3 resets time to zero. You see the time on the display in cs = s/100.
In egg clock mode you move a starting time up with b1. If you go too far, you can move it down with b2. b3 starts the countdown. When time passes zero, a buzzer beeps for 1 second.
Well,... you need to have big pockets! But you can miniaturize the thing if you want. On the other hand, the idea would be that a battery driven little instrument could be easier to carry around than a PC or a standard oscilloscope. But, the display is small and has a low resolution, and I haven't put any work into writing numerical data to the display; you just see a curve.
You start the logging with button b1, and then data
are logged in the Propeller's global memory (same as for
the USB oscilloscope). Then the display is erased, which
takes most of time used, and then a curve evolves.
As the display resolution is
low compared to the 7000 points we logg, most signals will
be heavily undersampled. But then we can expand the figure
with a factor of 2, for every hit we make on b3.
We can compress the picture again with button b4.
While we do these expansions and compressions, we see all
the versions of the picture at the same time. This looks
a little messy, but we have some chance to see what
happens. When we want to see the picture clearly, we
hit b2 to erase the screen, and then the latest version
of the curve will appear.
This overdrawing is helpfull, as we don't have to wait
for erasing beween all the pushes on b3 and b4.
In this picture, you can see a logging of the instrument's RC oscillator signal. The image is expanded a couple of times. The period of that signal is slightly less than 1ms. There is no choice of voltage range; it is fixed to 0..5 volts.
I found it handy to build the USB oscilloscope into a separate box:
It has two chargeble Litium batteries, and a little label, that gives the codes for the different modes and sampling rates. On the back it has a connection for charging the batteries, and the connection for a propstick for the PC communication.
Connect your signals to the D-sub connector, your PC to the propstick, open a Screen window on the PC, hit the appropriate key on your PC, and see you data come flying. Save your data with this command in your Screen window:
CtrlA : hardcopy -h hex.datThen call the program Osc.java, which reads data from that file hex.dat, and displays the result. It allows you to zoom into the plot. Here's an example:
This is an analog plot with two signals. They come from the RC oscillator in the Universal Instrument. So it's a square wave and a sawtooth wave. You can se a sampling effect where you get staircases where the squarwave jumps up and down, and you can see some disturbances, like the spike in the sawtooth. At the top of the square wave you can see that the line is slanting. That's because the comparator has open collector output, so you put a resistor up there, and it gives a "non zero time constant". The accuracy in voltage (given in mV) is as good as my calibration of it. The accuracy in time (which is given in μs) is as good as the Propellers crystal, i.e. very good. The frequency of the signal is 85 Hz, which can be measured from the plot with great accuracy.
You can recognize that triangular wave from the "pocket oscilloscope".
Here a digital example, which may be even more interesting. A USB oscilloscope is actually very effective for analyzing digital communication. We try to use the I2C protocol to communicate with a camera called OV7670. It didn't work, partly because I never connected that camera, but in fact I've never seen a sign of life from it. But we can at least see the host computers efforts with the communication.
We have a plot, and now we have zoomed into the plot to see the beginning of a conversation:
The red curve is the clock signal (sck). The blue curve is the serial data line (sda). First we see how the blue line falls while the red line is high. That should maybe be forbidden, but it is interpreted as a start pattern. Then comes a blue curve spike. Maybe it shouldn't be there, but it comes when there is no clockpulse on, so it is harmless. It is followed by the bit pattern for hexadecimal $42, which is the official I2C adress for this type of camera. Then the slightly longer clockpulse is for clocking in an acknowledge signal from the camera. It should be a zero on the blue line, but it never comes.
The camera has a bundle of registers, that we want to read. So we send the number of such a register, which happens to be $4B. Again an acknowledge clock pulse, and still no acknowledge signal. Finally we see a stop signal followed by a start signal (blue lines moving up and down during the duration of the clock pulses.
(Firstly, the stop and start patterns seen in the previous plot, appears again). Now adresses have been sent, and we want the camera to know, that we want to read from it. So we send the $42 again but now augmented with a readbit 1, so we send $43,
The result then is 8 bits being 1, which makes up for the hexadecimal number $FF. But then (miraculously?) we get an acknowledgment 0. But this is no miracle. This is an acknowledgment that the host should send, in thankfullness for the data it got. And it did send that acknowledgment!
In December 1813 Ludwig van Beethoven organized a concert, not with his own music, but with a "Jubileumskonzert" by Ignaz Joseph Pleyel. It was a chamber orchestra accompanying an Automatic Trumpeteer, designed and built by Johann Nepomuk Mälzel.
The trumpeteer was a wooden doll playing a real trumpet hardware. Trumpets at that time, had no valves, so they could only be played with so called "natural tones". Those tones were generated with a vibrating reed placed in the airflow into the trumpet. The programming was made in a mechanical arrangement, somewhat like a punched card.
The concert was reperformed lately, now with the programming made in a microprocessor.
My automatic trumpeteer is even simpler:
To the right, there is a loudspeaker and a power amplifier, which is a kit from Thailand. The box is a computer controlled tone generator, which generates sine or trianglewave outputs (sine waves are a little dull to listen to) with very accurate frequencies. Volume is also controlled, and the tones are also damped out with a chosen time constant. So, then, this is maybe rather an automatic piano.
The "piggy back" on the box, is the machine, that produces the commands to the tone generator. These commands are controlled from a file, which describes the music in terms of musical tones. I use the standard names of tones like C,D..A,H followed by an octave designation. A white space is for the standard octave containing A = 440Hz. A - is for the lower octave, and ' is for the higher. Then follows a white space or a 'b' for lowering the tone. So this is a piano. We dont distinghish between G# and Ab. The scale is the welltempered scale made famous by Bach in his "Das Wohltemperierte Klavier", but probably invented by Simon Stevin. It has 12 tones over an octave separated with a factor of the 12th root of 2. Then, the length of a tone is given in 1/32 fractions of a full note.
These notes are given on a file *.mus, which is transformed into a more numerical file *.myd. I have some file systems, like those based on SDH-cards, but right now, I just import these data using the global data concept. It means that the music I play, is compiled into the code.
The music computer sends frequency and volume commands as Morse codes to the tone generator. The Morse code for frequency gives the frequencies in Hz. The decay of the tones is made by the tone generator with a time constant received in a "damp" command from the music computer. The physical length of a full tone is controlled by the music computer by the pace in which it sends the commands.
The tone generator first makes a ramp that goes from the smallest 32bit value to the biggest. You get such a ramp by adding 429500 to a variable every 100μs. That gives a ramp of 1s. Then you can get higher frequencies by multiplying 429500 with your desired frequency. The 100μs period is made with a wait instruction, but the waittime is adjusted for the overhead involved in the loop.
Then this ramp is sent through a sine routine which is based on a sine table in the ROM of the Propeller. The triangular wave is made by sending the ramp through an absolute value instruction. Then, these signals have to be moved to swing around 0 before the amplitude modulation, and then moved up again to hit the middle of the conversion range of the Digital to Analog Converter, I'm using. It's an SPI based DAC, with maybe a little to low sampling frequency. Higher tones get a little undersampled.
I'm sorry for having been too lazy to provide you with a sound file. I didn't have access to Ignaz Joseph Pleyel's Jubileums concert, so instead I play a theme, "Polowetsian dance" from the opera "Furst Igor" by Alexandr Borodin.
Machines like these seem to lack a talent to play music in an enjoyable way. The same holds for Mälzels automatic trumpeteer.