Program Design
The software portion of the project is divided into 3 different parts: Mouse (PS/2) interface (on MCU1), Painting (on MCU2), and NTSC interface (on MCU2).
Mouse (PS/2) Interface
As stated in the high level design, we extensively referenced to Adam Chapwaske's PS/2 Mouse/Keyboard Protocol page to write our code. We wrote all of our code in C. The mouse interface resides on MCU1, and port D is used to communicate with the mouse.
The PS/2 interface is serial, and each byte is sent in a packet that includes a start bit, data byte, stop bit, parity bit, and acknowledge of receipt bit. We basically wrote two main functions: send and receive. The send function initiates a send to the mouse, and sychronizes to the clock generated by the mouse to send a command byte, and also takes care of all the metabits needed. The receive is similar, and is is triggered by the int0 interrupt. The mouse initiates communication by starting the clock and pulling down on int0, and the interrupt routine synchronizes with the mouse clock and clocks in the data one byte at a time.

Figure 2: Host to Mouse communication. (from Adam Chapwaske's
PS/2 Mouse/Keyboard Protocol page)

Figure 3: Mouse to Host communication. (from Adam Chapwaske's
PS/2 Mouse/Keyboard Protocol page)
Our program begins by resetting the mouse, and setting it to stream mode with data reporting on. In this mode, the mouse will continuously report updates on its movement counters whenever it senses a change in the counters.
Once we initialized the mouse and set it to streaming mode, we update the software x and y coordinates based on the incoming stream of counter changes. We also update the click state of the mouse. All this information is then sent to MCU2 using ports A, B (for x and y coordinates), and C (for the click state).
Some challenges faced in the beginning was in synchronizing to the mouse's clock (about 10kHz), and using the right amount of delay times to communicate to the mouse.
Painting Program
The paint program resides on MCU2. It is fully integrated with the NTSC interface program, and is executed in the vertical sync period of the NTSC to avoid introducing any video artifacts. Every frame of the video, the paint program polls ports A,B, and C to obtain the current mouse position and click state.
In the default mode, the user will see the cursor as a point on the screen. They will be able to move the point around in the work area, and paint through the use of various tools available. Our paint program has the following tools:
- Free-drawing: Allows user to draw a trail when the left mouse button is held down.
- Line: User clicks on 2 points to draw a line between them.
- Rectangle: User clicks on 2 points to draw a box with the corners on the 2 points.
- Circle: User clicks on 2 points to specify the radius of a circle that is drawn.
- Eraser: Like free-drawing mode except it will erase at the mouse cursor.
- Clear: Clears the entire work area.
- Cut/Copy: User selects a portion of the picture to cut or copy.
- Spray Paint: Sets random pixels within a rectangle. User holds down button to keep spraying.
- Polygon: Essentially a continuous line tool, user clicks middle button to complete polygon.
We employed simple two-state machines to detect button clicks on all three of the mouse's buttons. The left button code puts the tool into action, the right button code changes the tool, and the middle mouse button changes the brush size in free-drawing and eraser modes.
For the line, rectangle, circle, cut/copy, and polygon tool we employed another two-state machine to keep track of the number of clicks the user has clicked. The first click sets the starting point for the tool, and the second click initiates the action of the tool. We kept the coordinates of the clicks in an array, one for x and one for y.
For most of the tools, liberally employed the video_pt
and video_line functions that came with the
NTSC interface program provided in lab 4. Many of the tools, such
as the freedraw, rectangle, and line tools were simple to interpret
using a subset of these functions to draw the screen buffer.
A challenge during the paint program was to make everything as modular as possible, however, this was not always possible. One struggle was to be able to make the tool and brush size changes to be graceful (ie. leaving no trails or unintended artifacts behind). This required us to keep track of many clicks and pixel states. During the beginning of the project, in order to successfully move a point around without leaving a trail, we updated a state variable everytime when moving to a new pixel in order to redraw the pixel without changing it when the cursor left the pixel. In the end, we decided to just to invert the pixels that the mouse cursor was on: this greatly simplified the states, since the state of the pixels are essentially upkeeped by inversion. When leaving the pixels, we simply inverted the pixels again.
The circle tool turned out to cost us too much time in the vertical sync, and would create artifacts when drawing. We decided to disable the timers (and therefore, the video) when drawing the circle, and reenabling them after we are done. This resulted in a blinking of the video when drawing circles, but without any video artifacts left behind.
In order to clear the whole screen, we decided to reset the whole system (#asm('jmp 0')). This was the quickest solution, since erasing every point one at a time would take too long.
In order to cut/copy and paste correctly, we moved the data based on where the user decided to place the copy. For example, if the user places the buffer to the right, we copy from right to left to avoid erasing/altering pixels before copying them. Basically, four conditionals are used to test the cases.
For the spray tool, we used a uniform random number generator
to set a certain percentage of pixels in 5x5 grid:
a=rand()%3;
if(a==1)
//set the current pixel
This would result in setting 33% of pixels in the grid on average.
We also set the spray paint to paint every 5 frames.
Our program is still sensitive particularly to changes in the mouse position state while finishing an operation. For example, if you move the mouse really fast as you change the brush size, our program fails to erase the brush image entirely. This is due to the fact that the variable are being updated while we are erasing the brush beforehand. This is not too distracting as long as the user is careful in handling the mouse. Making the drawing engine cleaner is a possible future extension to the project.
NTSC Interface
For the NTSC interface, we basically changed the code provided to us in Lab 4 of ECE476 Spring 2004 (the oscilloscope lab). In particular, we deleted the animation and sound portion of the program and added our paint program in the vertical sync portion (starting at line 231 of the video).
Hardware Design
We used two MCU's: one to interface with the mouse, and the other to interface with the TV.

Figure 4: MCU1 and connections to Mouse.

Figure 5: Inter-MCU connections and TV connection.
MCU1 is connected to the mouse via Port D. D.0 and D.1 are used to communicate to the mouse, while D.2 and D.3 are used for receiving information. The circuit connecting to the mouse is sometimes called an open collector. Basically, in a nominal state, the Data and Clock are pulled high. When we communicate, we send bit patterns by pulling these nodes low using the two transistors (a similar circuit is also present inside the mouse to pull these two lines low).
The two MCU's are connected via Ports A,B, and C. Ports A and B transmit the x and y coordinates of the mouse to MCU2, respectively. Port C transmits the click state of the mouse. MCU2 is connected to the TV using a two level digital to analog filter (basically two voltage dividers). This is used to generate the necessary sync pulses needed by the NTSC standard.
For the purposes of this project, we made a board for MCU1 instead of using an AVR board. MCU2 still resided on its original board.
One of the greater challenges in connecting components was connecting wires to each pin of the mouse PS/2 port. The pins are very small and close together, so we used some wire crimpers to crimp the four wires to the pins. This proved to be effective, but sensitive. Throughout testings, we had to make sure that these wires were not touching or coming loose. For a longer term project, we would probably buy an official PS/2 port connector or cut the wire before the pinouts and connect directly to them.