Handy Board 2 Documentation
1. Introduction
Figure 1.1: Handy Board 2 Prototype |
 |
Handy Board 2 is a state of the art robot controller. It has been
designed to be a drop-in replacement of its predecessor. The original
Handy Board was created about 15 years ago and is used world wide by
students and hobbyists. However, many people feel they have reached the
limits of the original Handy Board.
Features
- 66Mhz ARM Thumb Processor
- 256KB internal SRAM
- 8MB Flash Program Memory
- 14 Analog Inputs
- 14 Digital Inputs
- 8 Digital Outputs
- 4 H-bridge Motor Controllers
- 2 Cricket bus ports
Overview of Student Work
In the Spring of 2004 George
Pantazopoulos did a directed study where he researched the
microchips to use and then he designed the entire circuit.
In the Spring of 2005, Andrew Chanler
did a directed study where he put some finishing touches on the
circuit, designed the printed circuit board art work, got the board
manufactured and built the first prototypes.
All work for this project has been done at Dr. Fred Martin's
Engaging Computing Lab in the Computer Science Department at the University of Massachusetts Lowell.
2. Hardware Design
Most of the Hardware design was done by George Pantazopoulos during
2004. In the spring of 2005, George and Andrew worked together to
finish the hardware design. We added the motor circuit, the RJ11
connector, the piezo, and cricket bus support to the schematics.
Note: All schematics and board layout art work was designed using
Eagle CAD from cadsoft.de |
Figure 2.1: Handy Board 2 Architechure |
 |
PCBoard Layout
This was a very difficult task! I hand routed the power traces
near the motors and regulators. I also hand routed all of the
power traces of the processor and flash memory.
I learned a lot
about
Eagle CAD during this process. One thing that helped me reach 100%
during auto route was to change the design rules so that vias have to be
farther away from SMD pads. What would happen is the processor would
get surrounded by vias and then the vias would block traces from
connecting to the pads. By keeping the vias away from the pads, this
left room for the autorouter to figure out how to connect all the
signals to the pads. Another lesson learned is that you can not use
polygons to fill in an area with copper until the auto router has
already routed all signals. If you draw the polygons first, you get a
message that says "Polygons fell apart" and then when you hit the rats
nest button you will see lots of unrouted signals.
Manfacture the Boards
We used Advanced Circuit's
$33 each deal to get three boards manufactured. And we ordered all the
parts from Digikey and
Mouser. To view the parts list,
click here. The version of the board layout that we had
manufactured for the first prototypes can be found in
~andrew/eagle/my_work/HandyArm/Rumble/Rumble_1.19-100percent.brd
and the openoffice part list spread sheet is in the same directory and
named Rumble_1.19_parlist.sxc
3. Bringing up the First Board
The first thing to do was so bring up the different voltage
regulators and verify that they are functioning. This was very straight
forward and worked imediately. Next we had to get the processor on the
board. I knew we had to use solder paste and the hot air station in the
inner-lab. To get some practice, I desoldered some chips off of a
random junk board and tried resoldering them with the paste. After
doing this a few times I felt confident in soldering the board. The
actual amount of solder paste you need to use is very small.
Fine Pitch Surface Mount Soldering
- Sqeeze out a thin thread of paste and then try to smeer it evenly
around the pads around with the tip of the suringe.
- Place the chip on the pads and use tweezers to get it
perfectly lined up.
- Attach the pencil tip to the hot air station, set the
temperature to XXX degrees celcius, and put the air speed pretty low.
- Preheat the board and activate the flux in the solder paste. To do
this, hold the hot air pump about 2 or 3 inches above the chip and hold
it there for 2 minutes.
- The solder paste should turn from gritty to glossy/shinny. That
means its ready.
- Set the air speed even slower and lower the tool in close to a
corner of the chip and the solder should wick up onto the legs of the
chip and the pads. As it wicks up, move along the edge until the entire
side is done.
- Then do the same for the other sides of the chip and you are done!
Warning: If the hot air station temperature is set too high, you
will destory the chips you are soldering! |
Next I soldered down the CPU LED which is connected directly to one
of the PIO pins of the processor. Then it was time to try and talk to
the chip through JTAG.
4. JTAG Interface
Wiggler Hardware
Figure 4.1: Wiggler JTAG Schematic |
 |
We are using a homemade Wiggler JTAG circuit whose design came from
Hardware Recycling
Initiative (HRI). We used a 541 buffer instead of a 244 buffer
because we had some 541's laying around the lab. The only difference
between the two buffer chips is the pin out. The other place our JTAG
circuit differs from the schematic is that we are using an invertor
instead of a transistor on the NRST line. This needs to be changed
because right now our inverter could be driving the line high while
something on the board (like the processor itself) could be trying to
drive it low. It must have been late when we built that circuit.
Figure 4.2: Our Wiggler Ciruit on Breadboard |
 |
Click here for full size image of Circuit.
JTAG Software
Jtager is the best
open source jtag software I have found yet. It uses a really nice
command line interface that keeps a history and has other features of
the readline library. One thing I have not figured out how to do yet
is in circuit debugging with gdb.
Important: For the rest of this document, code examples for loading
things into the prototype must be run from the jtager command
line. |
Note: While installing jtager, after you run make and make
install, then you need to copy a file called jtager.conf to
/etc/jtager/ and you can find this file in the source
subdirectory labeled extras. Also you need to set the core
variable inside of jtager.conf to ARM7TDMI |
Note: You must be the root user when running jtager. |
Another tool that I got working is ARMTOOL. You can find out more
about this tool at HRI's
JTAG FAQ.I got this working before I tried jtager. The problem
with this tool is that everytime you run it, it causes the board
to reset.
What didn't work
OCD Commander for Windows says that it supports
the wiggler jtag interface, however it did not work. I am glad it
didn't work because I moved on to test open source tools that we can use
in linux.
5. Driver
A major part of the project was to create the software to use each on
board component. I called this code Driver. It is basically a library
of functions to talk to each component on the system bus. I had some
major issues with poor solder joints on almost all the data bus lines
and several of the address bus lines. I learned how to debug this
using the osciloscope.
Flash Memory
void clear_flash(short *a);
void burn_flash(short *addr, short *data, int size);
The flash is 16-bit half-word addressable. You cannot write a given address more than once without erasing it inbetween writes. The other caveat is that when you erase part of flash you have to erase an entire 128k page. So when you call clear_flash() it will erase the 128k page that contains the address that is passed to it.
Note: The size parameter passed to burn_flash() is the number of 16-bit half-words to be written.
|
Warning: I have not tested these functions with any interrupts enabled. If users are going to be writing data into flash, perhaps interrupts should be disabled while the write is going on. So the question is will the timer interrupt break writing/erasing flash? |
Digital I/O
int digital(int x);
void digital_output(unsigned char x);
int start_button();
int stop_button();
void start_press();
void stop_press();
All of these functions control the digital input and output latches on the system bus. The start and stop button functions work identical to the Interactice C functions. Also digital_ouput() takes one byte and writes it to the latch. Later functions could be created to set/clear the individual bits on the digital outputs, but this is fine for now.
Motor Control
void fd(int x);
void bk(int x);
void stop(int x);
void coast(int x);
void alloff();
void allstop();
void motor(int x, int speed);
These should look very familiar to the Interactive C Handy Board motor functions. One feature of our design in the Handy Board 2 is active braking. The stop() and allstop() functions enable the braking. The coast() and alloff() functions turn power off and let the motors spin freely.
Note: The speed parameter to motor() is a number from 0 to 7. And the this pwm control uses a method created by George. Also I have not tested out the pwm to see how well the different power levels work.
|
LCD Display
void lcd_string( const char *s);
The LCD driver is very cool! The display is updated by the system interrupt. The interrupt simple copies the LCD's buffer to the display. And the user code writes the buffer with lcd_string(). This is a huge performance boost because the user code can write the buffer extremely fast and then go back to sensing and acting. However the original Handy Board would stop executing user code until the entire string was written to the lcd hardware.
Another interesting thing about my LCD driver is that it automatically wraps around the end of the buffer and in the original handyboard, you would have to print a '\n' character to cause it to go back to the begining of the LCD display. My LCD driver also supports any LCD display from 1x8 to 4x20! And the way it is implemented, it scrolls the display upwards with each line that is written. Just the way a unix terminal behaves.
One thing I would like to implement in the future is the ability to save a specified number of lines instead of just buffering the size of the display. This would help in debugging. The user could go back and view the LCD log to see what their program was doing. Also, I could implement a way to halt a program and go into a debug mode where the knob controls scrolling up and down in the log to see things the scrolled off the top of the display. Also give the ability to write the LCD log to a location in flash so that even if the board crashes and power dies, you could still view the log later. It would be very easy to implement this LCD log.
Note: To change driver to use a different size LCD screen, set the two #define lines near the top of driver.h
|
Other Functions
void init_system();
This is a crusial function that enables the system timer interrupt and also sets up a lot of variables for the different peripherals controlled by Driver.
void beep(int rate);
This function turns the Piezo on. Right now the highest pitch tone you can generate is 500hz because the system interrupt generates the squarewave and the system interrupt is 1000hz.
void msleep(unsigned long length);
This function sleeps for a given number of milliseconds.
6. CRT0.S
This is the piece of code that starts execution. It creates a vector table at the beginning of ram, sets the
external bus registers, and performs the memory remap. Then it initializes the stack for each of those interrupt
modes and the regular stack. The next thing it does is call main.
There are still somethings that need to be done in this code. Globals need to be initialized by copying the data
section into ram. Also the bss section needs to be zeroed. The last thing that needs to be done is call
init_system() right before main() so that every use program does not need that at the top of their
main(). There are probably more things that need to be done if you are writing C++ code. Like figure out how
to call the constructors of global objects.
Note: Before the remap is executed, only the first megabyte of flash memory is accessible. |
7. Linker Scripts
Code listing 7.1: Linker Script to Run Everything Out of RAM |
MEMORY
{
/* 0x000 to 0x040 is for vecotors and such */
/* 0x040 to 0x100 is for driver's ram */
ram : ORIGIN = 0x00000040 , LENGTH = 0x10000 - 0x40
rom : ORIGIN = 0x00010000 , LENGTH = 0x30000
}
SECTIONS
{
. = 0x00040;
__bss_start__ = .;
.bss : { *(.bss) } >ram
__bss_end__ = .;
_end = .;
end = .;
. = 0x10000;
.text : { *(.text) *(.glue_7t) *(.glue_7)} >rom
.data : { *(.data) } >rom
.rodata : { *(.rodata) *(.rodata.str1.4) } >rom
}
|
Code listing 7.2: Linker Script to Execute out of Flash |
MEMORY
{
/* 0x000 to 0x040 is for vecotors and such */
/* 0x040 to 0x100 is for driver's ram */
ram : ORIGIN = 0x00000100 , LENGTH = 262144 - 0x100
rom : ORIGIN = 0x10000000 , LENGTH = 8M
}
SECTIONS
{
. = 0x00040;
.data : { *(.data) } >ram
__bss_start__ = .;
.bss : { *(.bss) } >ram
__bss_end__ = .;
. = 0x10000000;
.text : { *(.text) *(.glue_7t) *(.glue_7) } >rom
.data : { *(.data) } >rom
.rodata : { *(.rodata) *(.rodata.str1.4) } >rom
}
|
8. Memory Maps
Write Address Map After REMAP is executed
| Address Range |
Peripheral |
| 0x00000000 - 0x0003FFFF |
Internal RAM |
| 0x10000000 - 0x107FFFFF |
Flash Memory |
| 0x20080000 - 0x2008FFFF |
LCD Latch |
| 0x20090000 - 0x2009FFFF |
Motor Latch 1 |
| 0x200A0000 - 0x200AFFFF |
Motor Latch 2 |
| 0x200B0000 - 0x200BFFFF |
Digital Output Latch |
| 0x200C0000 - 0x200CFFFF |
Analog to Digital Converter |
| 0x200D0000 - 0x200DFFFF |
ADC Channel Select Latch |
| 0xFFC00000 - 0xFFFFFFFF |
On-Chip Peripherals |
Read Address Map After REMAP is executed
| Address Range |
Peripheral |
| 0x00000000 - 0x0003FFFF |
Internal RAM |
| 0x10000000 - 0x107FFFFF |
Flash Memory |
| 0x20080000 - 0x2008FFFF |
Digital Input Latch 2 |
| 0x20090000 - 0x2009FFFF |
Digital Input Latch 1 |
| 0x200C0000 - 0x200CFFFF |
Analog to Digital Converter |
| 0xFFC00000 - 0xFFFFFFFF |
On-Chip Peripherals |
Read and Write Address Map Before REMAP is
executed
| Address Range |
Peripheral |
| 0x00000000 - 0x000FFFFF |
Flash Memory |
| 0x00300000 - 0x0033FFFF |
Internal RAM |
| 0xFFC00000 - 0xFFFFFFFF |
On-Chip Peripherals |
9. Example Program that uses Driver
This program will beep a tone and turn a motor on while either the start or stop buttons are being pressed down. The first important thing is the init_system() function. This enables the system timer interrupt which is a needed for the LCD, motor PWM, beep, and msleep(). It also sets up various variables that are in RAM that Driver needs. Other than that, everything else should look very familiar to a Interactive C Handy Board program.
Code listing 9.1: code listing for demo.c |
#include "driver.h"
#include "rumble.h"
int main()
{
init_system();
lcd_string( "Rumble\n" );
while (1)
{
if ( !start_button() )
{
beep(440);
fd(0);
lcd_string( "Engaging\n" );
while(!start_button());
coast(0);
beep(0);
}
if ( !stop_button() )
{
beep(440);
fd(3);
lcd_string( "Computing Lab\n" );
while(!stop_button());
coast(3);
beep(0);
}
}
return 0;
}
|
10. Building the Example Program
11. Running the Example Program
12. Errata
13. What's next?
14. Links
15. About this Doc
This document was written in an xml format designed by the people who created Gentoo Linux. To learn how to create similar documents, read Gentoo Linux XML Guide and Documentation Development Tips & Tricks.
|