Etch-A-Sketch

ECE5730 Final Project
A Project By Spencer Davis (sd954), Ming He (hh759), Joash Shankar (jcs556)


Demonstration Video


Introduction

We have created an experience similar to the Etch-A-Sketch toy using the Raspberry Pi Pico as the host. This final project uses various aspects and peripherals introduced in all three laboratory assignments. From the first lab, we used our knowledge of (direct digital synthesis) for sound generation, (button debouncing) for user input on a keypad, and (fixed point arithmetic) for fast computation of floating point numbers. From the second lab, we have pulled knowledge of the (VGA driver) to allow the user to see what they are drawing on a screen. We have integrated the (IMU) into our design from the final lab to allow for the shake-and-erase feature of a typical Etch-A-Sketch.

Our Etch-A-Sketch “game” offers the user an extended suite of tools previously unavailable to someone using an Etch-A-Sketch toy. We have added the ability to place filled or outlined pre-drawn shapes to aid artistic ingenuity. The user can also change the cursor's color, allowing up to 10 different hues.

This project utilizes a few peripherals offered by the RP2040, such as the PIO state machines and DMA, to name a few. These Co-processors free up the main processor’s time, allowing it to compute more difficult tasks in parallel.

The user has four means of interacting with the Etch-A-Sketch. The first two potentiometers control the cursor's x and y positions. As the user turns the potentiometers, the cursor will move accordingly, with the left potentiometer controlling the x coordinate and the right controlling the y. The third is a keypad where the user can navigate a menu and select the various options, such as cursor color, pre-drawn shapes, and shape fill. Lastly, the user can shake the device to erase the contents of the drawing space.


Project Objective:

This project aimed to design and implement the Etch-A-Sketch on a Raspberry Pi Pico. This version would offer extended capabilities offering the user the ability to place pre-drawn shapes to aid in the ease of drawing.

play handle diagram picture

Project Model

VGA screen picture

VGA Screen


High-level Design

Rationale and sources of project idea

We decided to create this well-known toy at a digital level, particularly intrigued by thinking how we can use potentiometers as cursors and the IMU to clear the screen, while also providing the nostalgia this kid’s toy invokes.

Background math

Logical Structure

The program starts by initializing the various communication protocols, drivers and (non-preemptive round-robin scheduler) we use for threads. Our Raspberry Pi communicates with the DAC via SPI, and with the IMU via I2C. The program has 3 threads. The first thread is responsible for getting IMU accelerometer values and ADC values. It does this every 20000 micro seconds. The second thread is responsible for debouncing keypad presses. The last thread is responsible for drawing at the cursor and is signaled by the thread that gets ADC values.

Below is a list of all functions present in our program as well as important variables that govern our code behavior.

Name Description
main() This function is responsible for initializing on-board peripherals as well as the second core and non-preemptive round-robin scheduler. This also sets up the repeating timer for sound generation.
core1_entry() This is responsible for setting up the scheduler on the second core.
accelAndADCThread() This thread is responsible for getting a new accelerometer magnitude from the IMU, and new x/y coordinates from the potentiometers. This thread runs every 20,000 microseconds.
repeating_sound_timer_callback() This 40 kHz repeating timer is responsible for generating sound when the user shakes the board, erasing the screen.
protothread_vga() This thread is responsible for drawing the cursor at the location indicated by the potentiometers. This thread is signaled by accelAndADCThread() through a semaphore called vga_semaphore.
protothread_debounce() This thread is responsible for debouncing the button. If the thread determines that the button has been pressed, it will verify by iterating through the debouncing state machine. Once it is confirmed the button has been pressed and is stable, the current button that is pressed is passed to processButtonPress.
processButtonPress() This function takes the button that was pressed on the keypad as an input and determines based on a case structure what action should be taken. Depending on the menu the user is in, various keys can have multiple meanings. For example, in FIGURE XXX, if the user is on the color screen, button 1 would mean they would like to select the color Red, but on the shapes screen, it would mean they would like to select the wide rectangle. This main menu they are on is monitored using the variable currentMenueState and depending on that, the appropriate action is taken.
keypadConfig() This function initializes the various GPIO pins responsible for the keypad’s functionality.
spiConfig() This function is responsible for setting up the SPI channel for communication with the DAC.
init_adc() This sets up the two adc channels that control the x and y position of the cursor.
read_adc() This function reads a specific ADC channel and returns the value read by the processor.
map_value() This function converts ADC readings to x and y coordinates.
read_pots() This function reads the value of both potentiometers by calling read_adc and map_value.
drawBounds() This draws the white box around where the user draws.
drawSideMenu / drawColorMenu / drawShapesMenu() These functions draw the menu on the right half of the screen.
soundConfig() This function generates the sin table and amplitude modulation variables use for sound generation.
drawTriangle / drawPentagon / drawDiamond / drawStar / drawRightTriangle() These helper functions draw their respective shapes at the cursor’s position.
clearMenu() This function erases the current menu in preparation for a new one.
changeColor() This function maps keypad presses to specific colors.
addShape() This function processes keypad entry and converts it to a shape. It also handles out-of bounds placing to prevent any part of the shape from moving outside of the drawing screen.
getRandomInteger() This function gets a random integer.
copyRect / pasteRect() These functions are responsible for copying a section of the screen and pasting it back from vga_data_array_old.
copyPixel / pastePixel() These functions copy and paste specific pixels to and from vga_data_array_old.
x_coord / y_coord These are the x and y coordinates of the cursor.
currShape This is the current shape the user has selected.
currColor This is the current color the user has selected.
currentMenuState This is the current menu shown on the right half of the screen.
vga_data_array_old This is the double buffer of the section of the screen the user is drawing. This allows the user the ability to move a shape around the screen without destroying the contents of the screen.
isShaken This indicates that the user has shaken the board.
fillShapes This indicates the user has selected the option to draw filled shapes.

Program/Hardware Design

Program Details

VGA data array

Translating the analog input from potentiometers to precise screen coordinates for smooth cursor movement

Hardware details

hardware schematic

Hardware Schematic


Results

Speed of execution

Accuracy

Safety in the design

Inclusivity


Conclusions & Future Work

Our design meets the expectations set in the proposal. A future improvement our group would like to include is additional filled-in shapes. The few shapes that were filled in were able to be generated quite easily, but due to time constraints, shapes like the star or the triangle were not given this feature. Second, our group would like to use the DMA channels to move data from the ADC’s to the program without CPU cycles. There isn’t an inherent reason to do so as the program runs into no timing issues, it would just be interesting to do.

Intellectual property considerations


Appendix A

The group approves this report for inclusion on the course website. The group approves the video for inclusion on the course youtube channel.

Additional Appendices

Download etchASketch code ZIP File