ECE5730 Final Project
A Project By Spencer Davis (sd954), Ming He (hh759), Joash Shankar (jcs556)
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.
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.
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.
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. |
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.
The code for this lab was either developed using previous laboratory assignments written by Professor Land and Professor Adamns as a starting point or was entirely developed for this assignment.
Professor Land: 4 - Bit Color
Course Code: IMU Interface, Debouncing, Fixed Point Arithmetic, Protothreads, Direct Digital Synthesis
We have made a device similar to the Etch-A-Sketch, but since we have included several different features and made a completely different interface, we are not infringing upon trademark rights. However, because of this, this project is neither patentable nor sellable.
The group approves this report for inclusion on the course website. The group approves the video for inclusion on the course youtube channel.