Project to continue for the semester
From Physical Programming
Contents |
The beginning
After having the Peggy2.0 brought to my attention I was quite interested in its ability to be programmed to display text, images and skill permitting- video- so I continued with the exploration of it.
What is the Peggy2.0?
Peggy2.0 is the second version of the Peggy board- an LED pegboard display that can drive up to 625 LEDs in a 25x25 LED square.
It can run on batteries or external power, it’s programmable, open source and hackable (there’s an area for extra components to be added and extra holes for access to microcontroller pins).
The LEDs can be soldered into the printed circuit board with each LED location numbered by its row and column location. Each spot has room for a 10mm LED, although 5mm and 3mm LEDs reportedly work just as well.
The Peggy2.0 gives you a choice on what you want to do with it.
With the instructions we received with the Peggy board, the first option was to produce a static “pegboard” display which would light up LED’s in whatever locations we placed them in with a fairly uniform current applied to each. E.g. we could place pins in a triangle shape and it would light up a triangle.
However the Peggy allows for further functionality by allowing specific LEDs to be lit up, simple animations to be run or an interactive display can be created. For this functionality the display needs to be reprogrammed through one of two interfaces provided with the board.
- The first is a 6-pin ISP (In-System Programmer) interface which lets you program the board using an in-system programmer such as the USB tinyISP which is supported through the AVR-GCC toolchain (Microcontrollers that can take high level C language code).
- The second is through Arduino programming which uses an FTDI USB-TTL serial interface cable that allows fast connection of microprocessors to the USB interface.
What was needed:
HARDWARE
- Peggy 2.0 board with as many LED's as possible (max 625)
- PC to Arduino connection cable- TTL-USB
- USB BUB board
- Arduino to Peggy board connection- analog 4 & 5 pins wired to SDA and SCL pins on the Peggy and a 3rd wire to connect ground between the two
- Arduino, preferably newer version- Atmega168
- A PC
SOFTWARE
Download:
- Processing
- Arduino software
- Peggy2 library
- Other example libraries as needed
The Hardware Specifics
On the bottom left hand side of the Peggy board there are the spots for two LED driver chips (see Image 1 below). The microcontroller uses these to control the rows of the display.
Image 1
Then there is the USB-TTL interface (Image 1 above) where you can insert a USB-TTL cable and program or communicate with the Peggy like you can with an Arduino. Basically it is where you make the connection to the PC via USB and feed power to the microcontroller. In order for us to connect the computer to the Peggy2.0 we had to firstly plug the USB-TTL cable into a USB-BUB serial board (Image 2 below) that plugged into the 6-pin connector.
Image 2
Next down is the clock area (Image 3 below):
A crystal oscillator- that is an electronic circuit which uses the mechanical resonance of a vibrating crystal to create a signal with a precise frequency which provides a clock signal.
Two little helper ceramic capacitors that are 18pF (18 picofarads or 18 trillionths of a farad!), which can determine the resonant frequency and quality factor in a circuit.
Image 3
To the right of the clock is the User Interface (Image 3) (an ATmega168 microcontroller) which is basically a small computer with program memory and can operate at low clock frequencies enabling low power consumption.
Image 4
To the right of it is the Proto area (Image 4) for hackers to attach additional components at their will.
Below this is the AVR-ISP interface (Image 4) which is a 6-pin connector you can attach to your AVR in-system programmer.
At the bottom left hand side are the tactile button switches (Image 5). Reset and off buttons come standard, although there is an optional button called ‘Any’ that can be used for activating other functions through reprogramming.
Image 5
To the right of the board are ‘Demultiplexer’ helper chips (Image 6) (also called a file splitter that splits files and sends them to decoders to be decoded). The microcontroller uses to drive the columns of the display.
Image 6
Below these are the locations of the external power jack and switch input (Image 6), with the switch choosing the power source. For battery power the switch is on to the right and for external power on to the left.
Above the LED driver chips for the rows, are two 1000ohm resistors and below the microcontroller is a 5.1k (5100ohm) resistor (Image 7).
Image 7
Directly below where the LED’s start is a row of transistors and below them is a row of resistors (Image 8).
Image 8
To the left of the LED drivers for the rows, the left of the microcontroller, either side of the capacitor and above the LED drivers for the columns are 0.1uF ceramic capacitors (Image 9).
Image 9
Serial Data Connection
Up until now we have been able to connect from a MAC to the Peggy through USB-TTL (following the evil mad scientist page that describes how to connect) and this has allowed us to run example sketches from libraries using the Arduino API.
With little time left we realised it would be great if we could run processing sketches or even quartz composer files to the Peggy to be able to show our own work.
We discovered that the Peggy microcontroller could not decipher the data we ran through the USB-TTL from a processing sketch we sent.
This lead to realising that in order to send serial data from processing or quartz composer, we needed to use a serial-TWI converter sketch in Arduino which meant we had to change our connection to the Peggy. This now meant PC to USB to Arduino then have two analog wires attached from the Arduino to the microcontroller on the Peggy, and a ground wire (as I initially researched).
Our connections have dealt with USB-TTL serial cable that connects to the digital pins of the Arduino and Peggy Microcontroller.
For our TWI communication to work we investigated the serial-TWI theory.
On the stock Peggy board, there are unused SDA/SCL pins. On the printed circuit board (PCB) of the Peggy, some serial clock pins (SCL) are unconnected and the serial data (SDA) pin is optionally used for the B5 button but it's normally open. What this means is that those pins can be used for I2C (2-Wire or TWI) communication without needing to modify the Peggy board so it can accept serial communication from a PC/Mac.
This is where the Arduino comes in, a form of Serial-to-I2C translator that connects to the Peggy by three wires.
A computer pushes data serially to the Arduino (via USB connection) which then pushes the same data to the Peggy through I2C.
We connected wires from the analog pins on the Arduino to the Peggy microcontroller, more specifically the Arduino analog 4 and 5 pins wired to the SDA and SCL pins on the Peggy.
A third wire is required to connect the ground between the two boards.
PEGGY OPERATION THEORY
A timer interrupt refreshes the LED display by sequencing through the rows and sending serial peripheral interface (SPI) output to the chips that drive the LED's.
A main program loop services the TWI registers, receiving TWI data and combining it into a frame buffer.
INTERFACING POINTS
The firmware for both the Peggy and Arduino should be installed before connecting the two.
The two pins of each device will be directly wired together, they can't be set as an output on either of the devices or there'll be a short circuit and one or both of the auto voltage regulators (AVR) will be damaged.
So after many hours spent playing around with the TWI connection, we have been unable to get Processing sketches to appear on the Peggy, but have been able to get Arduino sketches to upload.
Helpful links:
http://www.synbio.org.uk/component/content/article/46-instrumentation-news/1203-arduino-8x8-led-display-board.html?directory=257
http://www.evilmadscientist.com/article.php/PeggyArdLib
http://www.evilmadscientist.com/article.php/programpeggy2
http://ragtag.info/
While waiting for the Peggy2.0 to arrive
What has been done
Until the Peggy arrives I can't send any demo programs so I've spent the time investigating the scripts of demo's to try and gain an understanding of the commands used for varied tasks that can be sent to the peggy2.0.
I have come across some useful information that has been helpful for understanding functions within the Arduino environment.
- Creating a frame buffer
A frame buffer is an object in memory that holds one monochrome image that can be displayed on the Peggy. In order to display things on the Peggy, you need to allocate at least one frame buffer. (Internally, the data in a frame buffer--four bytes per row-- is arranged as an array of 25 long integers. However, you don't actually need to know that in order to use them.)
For an animation that has four frames that are switched between, you want to use four frame buffers. You can have one or several different frame buffers (limited by the amount of available RAM), each of which needs to have a different name. Normally, frame buffers are created at the beginning of the program, right after the #includes.
A new frame buffer is declared by using the keyword "Peggy2." To make a new frame buffer named Fred, we would call
Peggy2 Fred;
If you wanted four frame buffers (named frame1, frame2, frame3, and frame4), you could create them like so:
Peggy2 frame1;
Peggy2 frame2;
Peggy2 frame3;
Peggy2 frame4;
- Hardware initialization
Separately from creating the frame buffer, we also have to make sure that the Peggy hardware is ready for us. Do this by putting the command XXXX.HardwareInit(); (where XXXX is the name of any one of your frame buffers) within your setup() section.
The setup() section is a part of the Arduino Sketch that's only run once at the beginning; the other half-- the loop() section that comes after it is repeated forever.
Your setup() section might look like this, for example:
void setup()
{
frame1.HardwareInit();
}
That's it for initialization: make (at least) one frame buffer and do the hardware initialization. What remains are functions and procedures that can be executed at your discretion later in the setup()section or in the loop() section.
- RefreshAll();
In order to draw the contents of a frame buffer on the Peggy, you can issue a command of the form
FrameBufferName.RefreshAll(unsigned int refreshNum),
which takes an (unsigned) integer argument that says how many times to draw it on the screen. For a fast, single update of your frame buffer named Fred, you might put the following in your loop() section:
Fred.RefreshAll(1);
while for a more complex arrangement, you might have
frame1.RefreshAll(2);
frame2.RefreshAll(8);
which would draw both frames frame1 and frame2 on the Peggy. By the persistence of vision effect, you would see both frames frame1 and frame2 at the same time, drawn on top of each other. And, since frame2 is drawn for longer, (with the same brightness) it would appear brighter than the image in frame1.
- Clear();
You can completely zero out an existing frame buffer named Fred by issuing the command
Fred.Clear();
Example usage:
if (n > 100)
frame2.Clear();
- SetPoint
The SetPoint function is used to turn on a given pixel of a given frame buffer. The syntax is
FrameBufferName.SetPoint(unsigned short x, unsigned short y).
As before, this function acts on a specific frame buffer. The (x,y) coordinates are the usual type for computer graphics: origin in the upper left corner, with column/row location given by the ordered pair of unsigned integers, which should in this case be in the range 0-24.
Example usage, to turn on pixel located at (x,y) = (4, 10), in a frame buffer named Ginger:
Ginger.SetPoint(4,10);
- ClearPoint
The ClearPoint function is used to turn off a given pixel of a given frame buffer. The syntax is
FrameBufferName.ClearPoint(unsigned short x, unsigned short y).
Very much like SetPoint, above. Example usage, to turn off pixel located at (x,y) = (4, 10), in a frame buffer named Ginger:
Ginger.ClearPoint(4,10);
See the code examples for additional usage demonstrations.
- WriteRow
The WriteRow function allows you to write an entire row of a given frame buffer. The syntax is
FrameBufferName.WriteRow(unsigned short row, unsigned long rowdata).
This is a more advanced routine that may possibly be useful in some circumstances. It writes an entire row of data to the buffer at a time, where each bit from position 0 to 24 represents the LED position in the row. WriteRow is fast, but may not actually save time once you format your data to take advantage of that. Under most circumstances, it is more straightforward and reasonably efficient to use the WritePoint function instead.
Example usage, to turn on pixel located at (x,y) = (4, 10), in a frame buffer named Ginger:
Ginger.WriteRow(10, 16);
Why? It's row 10, and the LED 4 is given by 2^4 = 16.
Second example, to turn on pixels 3-18 in row number 10:
Ginger.WriteRow(10, (unsigned long) 65535 << 3);
- WritePoint
The WritePoint function allows you to turn a point on or off logically. The syntax is
BufferName.WritePoint(unsigned short x, unsigned short y, unsigned short Value); .
If Value equals one (or is any nonzero value), then the point at coordinates (x,y) will be turned on in the buffer named BufferName. Otherwise-- if Value equals zero-- then the point at coordinates (x,y) will be turned off in the buffer named BufferName.
A very powerful routine, since you can turn on or turn off a single point depending on the value of a variable or outcome of a comparison.
Example usage, to turn on a pixel located at (x,y) = (2, 10), in a frame buffer named Ginger:
Ginger.WritePoint(2, 10, 1);
Second example, to turn off a pixel located at (x,y) = (4, 10):
Ginger.WritePoint(4, 10, 0);
- GetPoint
The GetPoint function allows you to check if a point is on or off.
uint8_t BufferName.GetPoint(unsigned short x, unsigned short y); .
Returns 1 if the pixel at coordinates (x,y) is on, or 0 if the pixel is off at coordinates (x,y) , in the buffer named BufferName.
Example usage, to see if the pixel at (x,y) = (2, 10), in a frame buffer named Ginger, is on or off:
unsigned int j; j = Ginger.GetPoint(2, 10);
- Line
The Line function allows you to draw a line between two points. The syntax is
BufferName.Line(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2); .
Draw a line from (x1,y1) to (x2,y2) in the buffer named BufferName.
Example usage, to draw a line from (0,0) to (24,24), in a frame buffer named Ginger:
Ginger.Line(0,0,24,24);
Second example, to turn off a pixel located at (x,y) = (4, 10):
Ginger.WritePoint(4, 10, 0);
- MoveTo and LineTo
These functions allow you to move around an (invisible) cursor and use it to selectively draw.
BufferName.MoveTo(unsigned short x, unsigned short y); .
Move (invisible) cursor to position from (x,y) in the buffer named BufferName. Used in conjunction with LineTo to make lines where you want them.
Example usage, to draw a line from (0,0) to (24,24) and from (0,24) to (24,0), in a frame buffer named Ginger:
Ginger.MoveTo(0,0); Ginger.LineTo(24,24); Ginger.MoveTo(0,24); Ginger.LineTo(24,0);
BufferName.LineTo(unsigned short x, unsigned short y); .
Drag line from current cursor position to new position. Update cursor position as well. Move cursor to position from (x,y) in the buffer named BufferName. Used in conjunction with MoveTo to make lines where you want them.
Example usage, to draw a line from (0,0) to (24,24) and from (0,24) to (24,0), in a frame buffer named Ginger:
Ginger.MoveTo(0,0); Ginger.LineTo(24,24); Ginger.MoveTo(0,24); Ginger.LineTo(24,0);
Currently I'm using this information as a reference for when I examine different codes.
Another thing I have looked into is the LED intensity that some Peggy2.0 demo's have exhibited.
After finding out that LEDs are binary- either on or off- I wondered how they can vary in intensity. The way this works is due to persistence of vision. If you flash one LED every 40milliseconds for a minute, and flash another next to it every 10 milliseconds for a minute, the human eye will blur the super fast flashing and the faster flashing one will appear brighter. This is also known as pulse width modulation.
The way I figured this to work with the Peggy is best explained through an example. You have four frame buffers- which control which LEDs are on or off.
Buffer zero is set to 8 repeats, buffer one is set to 4, buffer two is set to 2 and buffer three is set to 1.
LEDs in buffer zero will be brighter as they have been on 8 times longer than those in buffer three.
By turning on the same LED in more than one buffer, you get the other levels. So an LED turned on in buffer zero, one, two and three will be on 8+4+2+1 times and will be brightest. The next brightest would be turned on in buffer zero, one and two, so 8+4+2 times.
Taking delivery
After taking delivery of the Peggy2.0 and realising that the LED's did not come standard, we started to install the 10mm yellow ones that we bought.
The following image depicts the underside of the Peggy board with the LED pins inserted through before snipping the pins and soldering.
This next image shows the front of the Peggy board with most LED's inserted.
After soldering in the LED's we connected the Peggy to a MAC and followed instructions (http://www.evilmadscientist.com/article.php/PeggyArdLib) to send a test pattern to the board. After compiling the example sketch in Arduino, we progressed to uploading it. We initially got no response and this was quite a worry. By method of elimination we managed to select the right serial port under the Tools menu in Arduino, but it came down to simply turning the 6 pin adapter on the end of the USB BUB 180 degrees and after a second try, success! After this we have experimented with different sketches, some have come up with error reports that we don't have the programming experience to understand how to repair, although we have found some that we were able to manipulate slightly.


