This program was my attempt to plot a given equation on a VGA screen using Prof. Hunter Adam's VGA Library for the RaspberryPi Pico. The resources for the project include the C SDK User Guide, the RP2040 Datasheet and Prof. Hunter's website.
I chose the following equation to plot on the VGA screen:
\begin{align} \left(sin\left(a \times \frac{\pi}{10}\right) + x\right)^2 + \left(cos\left(a \times \frac{\pi}{10}\right) + y\right)^2 = 0.7|x|y + 1 \end{align}Here, different values of $a$ give different graphs, which when put together give the shape of a heart.
Using desmos, the plotted equation looks as shown.
/*
* Parth Sarthi Sharma (pss242@cornell.edu)
* Code based on examples from Raspberry Pi Foundation.
* This code is an implementation of a custom heart function
* on the Raspberry Pi Pico to draw a pattern.
*/
#include <stdio.h> //The standard C library
#include <math.h> //The standard math library
#include "pico/stdlib.h" //Standard library for Pico
#include "hardware/pio.h" //The hardware PIO library
#include "hardware/dma.h" //The hardware DMA library
#include "pico/time.h" //The pico time library
#include "hardware/gpio.h" //The hardware GPIO library
#include "pico/multicore.h" //The pico multicore library
#include "vga_graphics.h" //The graphics library
#define HEIGHT 480 //Height of the VGA screen
#define WIDTH 640 //Width of the VGA screen
#define PI 3.14159265358 //The value of PI
void core1_entry() { //The program running on core 1
double error = 0.01, step = 0.01, x, y, a, ans; //The error, step, x coordiante, y coordinate, iterator, and the answer variables
for(a = 11; a <= 20; a += 0.5){ //For x in range [11, 20] with 0.5 step size
for(x = -3; x < 3; x += step){ //For x in range [-3, 3) with 0.01 step size
for(y = -3; y < 3; y += step){ //For y in range [-3, 3) with 0.01 step size
ans = pow((sin(a * PI / 10.0) + x), 2.0) + pow((cos(a * PI / 10.0) + y), 2.0) - (0.7 * fabs(x) * y); //Solve for the equation
if((ans < 1 + error) && (ans > 1 - error)){ //If the solution is within the given error limits
fillCircle((50 * x) + (WIDTH / 2), (HEIGHT / 2) - (50 * y), 1, RED); //Draw a red circle to create an enlarged image
}
}
}
}
}
int main(){ //The program running on core 0
double error = 0.01, step = 0.01, x, y, a, ans; //The error, step, x coordiante, y coordinate, iterator, and the answer variables
stdio_init_all(); //Initialize all of the present standard stdio types that are linked into the binary
initVGA(); //Initialize the VGA screen and functions
multicore_launch_core1(core1_entry); //Reset core1 and enter the core1_entry function on core 1 using the default core 1 stack
for(a = 1; a <= 10; a += 0.5){ //For x in range [1, 10] with 0.5 step size
for(x = -3; x < 3; x += step){ //For x in range [-3, 3) with 0.01 step size
for(y = -3; y < 3; y += step){ //For y in range [-3, 3) with 0.01 step size
ans = pow((sin(a * PI / 10.0) + x), 2.0) + pow((cos(a * PI / 10.0) + y), 2.0) - (0.7 * fabs(x) * y); //Solve for the equation
if((ans < 1 + error) && (ans > 1 - error)){ //If the solution is within the given error limits
fillCircle((50 * x) + (WIDTH / 2), (HEIGHT / 2) - (50 * y), 1, RED); //Draw a red circle to create an enlarged image
}
}
}
}
}
The code has a VGA library which has been explained really nicely by Prof. Adams and the main file.
The main crux of the program lies in the fact that I needed to compute the equation within a given error as trying to find the exact solution can be really computationally expensive. Therefore, I divided the x-coordinates and the y-coordinates into a series of small steps and computed the equation on using those coordinates. If the answer is within the given error limit, draw a red circle at the given location.
cmake_minimum_required(VERSION 3.13)
include(pico_sdk_import.cmake)
project(HeartEquation-project)
pico_sdk_init()
add_executable(HeartEquation)
pico_enable_stdio_usb(HeartEquation 1)
pico_enable_stdio_uart(HeartEquation 1)
pico_generate_pio_header(HeartEquation ${CMAKE_CURRENT_LIST_DIR}/hsync.pio)
pico_generate_pio_header(HeartEquation ${CMAKE_CURRENT_LIST_DIR}/vsync.pio)
pico_generate_pio_header(HeartEquation ${CMAKE_CURRENT_LIST_DIR}/rgb.pio)
target_sources(HeartEquation PRIVATE HeartEquation.c vga_graphics.c)
target_link_libraries(HeartEquation PRIVATE pico_stdlib hardware_pio hardware_dma hardware_adc hardware_irq pico_time pico_multicore)
pico_add_extra_outputs(HeartEquation)