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.
Appendix B
- xk52: Working on buttons for drawing alive cells, also working on the Conway’s Game of Life Pi and random pattern.
- wy339: Working on the algorithm for Conway’s Game of Life and algorithm for Mandelbrot plot; working on the zoom-in box for Mandelbrot plot and potentiometer for changing the zoom area.
- xc539: Working on the sound generation for both Conway’s Game of Life and Mandelbrot plot; also working on the menu page and choice button for selecting visualisation and return-to-menu button.
Appendix C: Code
/**
* Hunter Adams (vha3@cornell.edu)
*
* This demonstration animates two balls bouncing about the screen.
* Through a serial interface, the user can change the ball color.
*
* HARDWARE CONNECTIONS
* - GPIO 16 ---> VGA Hsync
* - GPIO 17 ---> VGA Vsync
* - GPIO 18 ---> 470 ohm resistor ---> VGA Green
* - GPIO 19 ---> 330 ohm resistor ---> VGA Green
* - GPIO 20 ---> 330 ohm resistor ---> VGA Blue
* - GPIO 21 ---> 330 ohm resistor ---> VGA Red
* - RP2040 GND ---> VGA GND
*
* RESOURCES USED
* - PIO state machines 0, 1, and 2 on PIO instance 0
* - DMA channels (2, by claim mechanism)
* - 153.6 kBytes of RAM (for pixel color data)
*
*/
#include //The standard C library
#include //C stdlib
#include
#include "pico/stdlib.h" //Standard library for Pico
#include //The standard math library
#include "hardware/gpio.h" //The hardware GPIO library
#include "pico/time.h" //The pico time library
#include "hardware/irq.h" //The hardware interrupt library
#include "hardware/pwm.h" //The hardware PWM library
#include "hardware/pio.h" //The hardware PIO library
// #include "TFTMaster.h" //The TFT Master library
#include "hardware/dma.h"
#include "hardware/spi.h" //The hardware SPI library
#include "hardware/sync.h"
// Include protothreads
#include "pico/multicore.h"
#include "pt_cornell_rp2040_v1_3.h"
#include "vga16_graphics.h"
#include "hardware/adc.h"
#define size 2
#define FRAME_RATE 33000
#define WIDTH 640
#define HEIGHT 480
#define MAX_ITER 500
#define WIDTH_DISPLAY 528
volatile int alive_count = 0;
volatile int alive = 0;
int count;
static char text1[40];
int frequencies[4] = {261, 293, 329, 392};
uint8_t menu_choice = 0;
float x_min = -2.0, x_max = 1.0;
float y_min = -2.0, y_max = 1.0;
static unsigned char cell_array[WIDTH_DISPLAY/size][HEIGHT/size] ;
static char cell_array_next[WIDTH_DISPLAY/size][HEIGHT/size] ;
uint8_t start_init = 1; // flag to indicate if the initial state is set
// mouse control
#define PIN_LEFT 8
#define PIN_UP 9
#define PIN_DOWN 10
#define PIN_RIGHT 11
#define PIN_CONFIRM 12
#define BUTTON_PIN 14
#define ADC_PIN 26
#define default_curser_x 120
#define default_curser_y 160
int curser_x = default_curser_x;
int curser_y = default_curser_y;
// potentiometer
#define DEFAULT_SIZE 5
#define min_zoom_size 1
#define max_zoom_size 10
#define zoom_unit_size 11
int potentio_read;
int potentio_read_prev;
int zoom_size_prev;
int zoom_size_set = DEFAULT_SIZE;
int zoom_start_x;
int zoom_start_y;
int zoom_end_x;
int zoom_end_y;
typedef enum {
RESET,
BUTTON_NOT_PRESSED,
BUTTON_MAYBE_PRESSED,
BUTTON_PRESSED,
BUTTON_MAYBE_NOT_PRESSED
} ButtonState;
static ButtonState button_state_switch = RESET;
static ButtonState button_state_left = RESET;
static ButtonState button_state_right = RESET;
static ButtonState button_state_up = RESET;
static ButtonState button_state_down = RESET;
static ButtonState button_state_confirm = RESET;
int button_value_switch = -1;
int button_value_up = -1;
int button_value_down = -1;
int button_value_left = -1;
int button_value_right = -1;
int button_value_confirm = -1;
static int possible_switch = -1;
static int possible_left = -1;
static int possible_right = -1;
static int possible_up = -1;
static int possible_down = -1;
static int possible_confirm = -1;
static int button_control = -1;
static int up_control = 0;
static int down_control = 0;
static int left_control = 0;
static int right_control = 0;
static int confirm_control = 0;
static int button_control_prev = -1;
float previous_left = 1, previous_right = 1, previous_up = 1, previous_down = 1;
float acc = 1.2;
float x[WIDTH] = {0};
float y[HEIGHT] = {0};
int count = 0;
//////////
// Beep
// Low-level alarm infrastructure we'll be using
#define ALARM_NUM 0
#define ALARM_IRQ 0
// Macros for fixed-point arithmetic (faster than floating point)
typedef signed int fix15 ;
#define multfix15(a,b) ((fix15)((((signed long long)(a))*((signed long long)(b)))>>15))
#define float2fix15(a) ((fix15)((a)*32768.0))
#define fix2float15(a) ((float)(a)/32768.0)
#define absfix15(a) abs(a)
#define int2fix15(a) ((fix15)(a << 15))
#define fix2int15(a) ((int)(a >> 15))
#define char2fix15(a) (fix15)(((fix15)(a)) << 15)
#define divfix(a,b) (fix15)( (((signed long long)(a)) << 15) / (b))
//Direct Digital Synthesis (DDS) parameters
#define two32 4294967296.0 // 2^32 (a constant)
#define Fs 50000
#define DELAY 20 // 1/Fs (in microseconds)
// the DDS units - core 0
// Phase accumulator and phase increment. Increment sets output frequency.
volatile unsigned int phase_accum_main_0;
volatile unsigned int phase_incr_main_0 = (400.0*two32)/Fs ;
// DDS sine table (populated in main())
#define sine_table_size 256
fix15 sin_table[sine_table_size] ;
// Values output to DAC
int DAC_output_0 ;
int DAC_output_1 ;
// Amplitude modulation parameters and variables
fix15 max_amplitude = int2fix15(1) ; // maximum amplitude
fix15 attack_inc ; // rate at which sound ramps up
fix15 decay_inc ; // rate at which sound ramps down
fix15 current_amplitude_0 = 0 ; // current amplitude (modified in ISR)
fix15 current_amplitude_1 = 0 ; // current amplitude (modified in ISR)
// Timing parameters for beeps (units of interrupts)
#define ATTACK_TIME 250
#define DECAY_TIME 250
#define SUSTAIN_TIME 10000
#define BEEP_DURATION 6500
#define BEEP_REPEAT_INTERVAL 50000
#define TONE_DURATION 10000
// State machine variables
volatile unsigned int count_0 = 0 ;
// SPI data
uint16_t DAC_data_1 ; // output value
uint16_t DAC_data_0 ; // output value
// DAC parameters (see the DAC datasheet)
// A-channel, 1x, active
#define DAC_config_chan_A 0b0011000000000000
// B-channel, 1x, active
#define DAC_config_chan_B 0b1011000000000000
//SPI configurations (note these represent GPIO number, NOT pin number)
#define PIN_MISO 4
#define PIN_CS 5
#define PIN_SCK 6
#define PIN_MOSI 7
#define LDAC 8
#define LED 25
#define SPI_PORT spi0
//GPIO for timing the ISR
#define ISR_GPIO 2
static void alarm_irq(void) {
int frequency;
// Assert a GPIO when we enter the interrupt
gpio_put(ISR_GPIO, 1) ;
// Clear the alarm irq
hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM);
// Reset the alarm register
timer_hw->alarm[ALARM_NUM] = timer_hw->timerawl + DELAY ;
if ( button_control == 0 || button_control == 1 ) {
// DDS phase and sine table lookup
frequency = (int)(sqrt(count)*10);
phase_accum_main_0 += (int)((frequency*two32)/Fs) ;
DAC_output_0 = fix2int15(multfix15(current_amplitude_0,
sin_table[phase_accum_main_0>>24])) + 2048 ;// Add 2048 to center it from range (-2048,2048) to (0,4096)
// Ramp up amplitude (ATTACK_TIME = 250)
if (count_0 < ATTACK_TIME) {
current_amplitude_0 = (current_amplitude_0 + attack_inc) ;
}
// Ramp down amplitude (DECAY_TIME = 250)
else if (count_0 > BEEP_DURATION - DECAY_TIME) {
current_amplitude_0 = (current_amplitude_0 - decay_inc) ;
}
// Mask with DAC control bits
DAC_data_0 = (DAC_config_chan_B | (DAC_output_0 & 0xfff)) ;
// SPI write (no spinlock b/c of SPI buffer)
spi_write16_blocking(SPI_PORT, &DAC_data_0, 1) ;
// Increment the counter
count_0 += 1 ;
if (count_0 == BEEP_DURATION) {
count_0 = 0 ;
current_amplitude_0 = 0 ;
}
}
else if ( button_control == 2 ) {
static int current_freq_idx = 0;
// Set new frequency at start of beep
frequency = frequencies[current_freq_idx];
// DDS phase and sine table lookup
phase_accum_main_0 += (int)((frequency * two32) / Fs);
DAC_output_0 = fix2int15(multfix15(current_amplitude_0,
sin_table[phase_accum_main_0 >> 24])) + 2048;
// Ramp up
if (count_0 < ATTACK_TIME) {
current_amplitude_0 += attack_inc;
}
// Ramp down
else if (count_0 > BEEP_DURATION - DECAY_TIME) {
current_amplitude_0 -= decay_inc;
}
// Mask with DAC control bits and send
DAC_data_0 = (DAC_config_chan_B | (DAC_output_0 & 0xfff));
spi_write16_blocking(SPI_PORT, &DAC_data_0, 1);
count_0 += 1;
if (count_0 == BEEP_DURATION) {
count_0 = 0;
current_amplitude_0 = 0;
// Move to next frequency in the list (loop around)
current_freq_idx = (current_freq_idx + 1) % 4;
}
}
// De-assert the GPIO when we leave the interrupt
gpio_put(ISR_GPIO, 0) ;
}
void change_zoom_size(){
if (button_control == 2 ){
adc_select_input(0);
potentio_read = adc_read();
zoom_size_prev = zoom_size_set;
if (potentio_read != potentio_read_prev) {
zoom_size_set = (int)min_zoom_size + (int)((potentio_read-13)*(max_zoom_size-min_zoom_size)/(4095-13));
zoom_size_set = zoom_size_prev + (int)((zoom_size_set - zoom_size_prev)>>1);
potentio_read_prev = potentio_read;
}
}
}
void drawcell (int x, int y, int value) {
for (int i = 0; i < size; i++){
for (int j = 0; j < size; j++){
drawPixel(size*x+i, size*y+j, value*WHITE);
}
}
cell_array[x][y] = value;
}
int live_x[50] = {0};
int live_y[50] = {0};
int live_count = 0;
void draw_curser( ){
if (button_control == 1 || button_control == 0) {
if (live_x[live_count] != curser_x*size || live_y[live_count] != curser_y*size) {
printf("move cursor\n");
drawPixel(live_x[live_count]-1, live_y[live_count]-1, BLACK);
drawPixel(live_x[live_count]+1, live_y[live_count]+1, BLACK);
drawPixel(live_x[live_count]+1, live_y[live_count]-1, BLACK);
drawPixel(live_x[live_count]-1, live_y[live_count]+1, BLACK);
live_count++;
live_x[live_count] = curser_x*size;
live_y[live_count] = curser_y*size;
if (live_count == 50) {
live_count --;
}
}
drawPixel(curser_x*size, curser_y*size, YELLOW);
drawPixel(curser_x*size-1, curser_y*size-1, YELLOW);
drawPixel(curser_x*size+1, curser_y*size+1, YELLOW);
drawPixel(curser_x*size+1, curser_y*size-1, YELLOW);
drawPixel(curser_x*size-1, curser_y*size+1, YELLOW);
}
// else if (button_control == 2){
// drawPixel(curser_x, curser_y, YELLOW);
// }
}
void draw_zoomin(){
if (button_control == 2){
int zoom_length = zoom_unit_size * zoom_size_set;
drawRect(curser_x, curser_y, zoom_length, zoom_length, MAGENTA );
zoom_start_x = curser_x;
zoom_start_y = curser_y;
zoom_end_x = curser_x + zoom_length;
zoom_end_y = curser_y + zoom_length;
}
}
void menu() {
if (button_control == -1) {
sprintf(text1, "1.Conway Game of Life - Pi");
setCursor(30, 10);
if (menu_choice == 0) {
setTextColor2(BLACK, WHITE);
} else {
setTextColor2(WHITE, BLACK);
}
setTextSize(1);
writeString(text1);
sprintf(text1, "2.Conway Game of Life - Random");
setCursor(30, 20);
// setTextColor2(WHITE, BLACK);
if (menu_choice == 1) {
setTextColor2(BLACK, WHITE);
} else {
setTextColor2(WHITE, BLACK);
}
setTextSize(1);
writeString(text1);
sprintf(text1, "3.Mandelbrot Set");
setCursor(30, 30);
// setTextColor2(WHITE, BLACK);
if (menu_choice == 2) {
setTextColor2(BLACK, WHITE);
} else {
setTextColor2(WHITE, BLACK);
}
setTextSize(1);
writeString(text1);
}
}
const char* conway_title[] = { "Conway", "Game", "of", "Life" };
const char* mandelbrot_title[] = { "Mandel-","brot", "Set" };
void draw_title_area( const char* title_words[], int word_count ) {
// Fill the rightmost 112-pixel-wide strip with white
// fillRect(528,0,112,480,WHITE);
// Display one word per line, left-aligned in the white strip
for (int i = 0; i < word_count; i++) {
sprintf(text1, "%s", title_words[i]);
setCursor(530, 100 + i * 30); // vertical spacing, adjust as needed
setTextColor2(BLACK, WHITE);
setTextSize(2);
writeString(text1);
}
}
void draw_title(){
if (button_control == 0 || button_control == 1){
draw_title_area(conway_title, 4);
}else if (button_control == 2){
draw_title_area(mandelbrot_title, 3);
}
}
void mandelbrot() {
if(button_control == 2) {
fillRect(0, 0, WIDTH_DISPLAY, HEIGHT, BLACK);
float Zre, Zim, Cre, Cim ;
float Zre_sq, Zim_sq ;
int n, i, j ;
for (i = 0; i < WIDTH_DISPLAY; ++i) {
for (j = 0; j < HEIGHT; ++j) {
Zre = Zim = Zre_sq = Zim_sq = 0;
Cre = x[i] ;
Cim = y[j] ;
n = 0 ;
while (Zre_sq + Zim_sq < 4 && n < MAX_ITER) {
Zim = 2 * Zre * Zim + Cim;
Zre = Zre_sq - Zim_sq + Cre;
Zre_sq = Zre * Zre;
Zim_sq = Zim * Zim;
n++;
}
if (n >= MAX_ITER) {drawPixel(i, j, BLACK) ;}
else if (n >= (MAX_ITER>>1)) {drawPixel(i, j, WHITE); }
else if (n >= (MAX_ITER>>2)) {drawPixel(i, j, YELLOW); }
else if (n >= (MAX_ITER>>3)) {drawPixel(i, j, MED_GREEN); ;}
else if (n >= (MAX_ITER>>4)) {drawPixel(i, j, RED); }
else if (n >= (MAX_ITER>>5)) {drawPixel(i, j, DARK_ORANGE); }
else if (n >= (MAX_ITER>>6)) {drawPixel(i, j, ORANGE); }
else {drawPixel(i, j, PINK);}
}
}
}
}
// ====================================================================
// = button FSM =
// ====================================================================
void button_pressing_switch( )
{
switch (button_state_switch)
{
case RESET:
button_value_switch = gpio_get(BUTTON_PIN);
button_state_switch = BUTTON_NOT_PRESSED;
break;
case BUTTON_NOT_PRESSED:
if (button_value_switch == 0){
button_value_switch = gpio_get(BUTTON_PIN);
button_state_switch = BUTTON_NOT_PRESSED;
}
else{
possible_switch = button_value_switch;
button_value_switch = gpio_get(BUTTON_PIN);
button_state_switch = BUTTON_MAYBE_PRESSED;
}
break;
case BUTTON_MAYBE_PRESSED:
if (button_value_switch == possible_switch){
button_value_switch = gpio_get(BUTTON_PIN);
button_state_switch = BUTTON_PRESSED;
if (button_control == -1) {
menu_choice = (menu_choice + 1) % 3;
}
else {
button_control = -1;
}
}
else{
button_value_switch = gpio_get(BUTTON_PIN);
button_state_switch = BUTTON_NOT_PRESSED;
}
break;
case BUTTON_PRESSED:
if (button_value_switch == possible_switch){
button_value_switch = gpio_get(BUTTON_PIN);
button_state_switch = BUTTON_PRESSED;
}
else{
button_value_switch = gpio_get(BUTTON_PIN);
button_state_switch = BUTTON_MAYBE_NOT_PRESSED;
}
case BUTTON_MAYBE_NOT_PRESSED:
if (button_value_switch == possible_switch) {
button_value_switch = gpio_get(BUTTON_PIN);
button_state_switch = BUTTON_PRESSED;
}
else {
button_value_switch = gpio_get(BUTTON_PIN);
button_state_switch = BUTTON_NOT_PRESSED;
}
break;
default:
button_value_switch = -1;
possible_switch = -1;
break;
}
}
void button_pressing_left()
{
switch (button_state_left)
{
case RESET:
button_value_left = gpio_get(PIN_LEFT);
button_state_left = BUTTON_NOT_PRESSED;
break;
case BUTTON_NOT_PRESSED:
if (gpio_get(PIN_LEFT) == 0) {
button_value_left = gpio_get(PIN_LEFT);
button_state_left = BUTTON_NOT_PRESSED;
}
else {
possible_left = button_value_left;
button_value_left = gpio_get(PIN_LEFT);
button_state_left = BUTTON_MAYBE_PRESSED;
}
break;
case BUTTON_MAYBE_PRESSED:
if (button_value_left == possible_left) {
button_value_left = gpio_get(PIN_LEFT);
left_control = 1;
// Optionally reset other controls
right_control = 0;
up_control = 0;
down_control = 0;
confirm_control = 0;
curser_x -= previous_up;
previous_up *= acc;
previous_down = 1;
previous_left = 1;
previous_right = 1;
button_state_left = BUTTON_PRESSED;
}
else {
button_value_left = gpio_get(PIN_LEFT);
button_state_left = BUTTON_NOT_PRESSED;
}
break;
case BUTTON_PRESSED:
if (button_value_left == possible_left) {
button_value_left = gpio_get(PIN_LEFT);
button_state_left = BUTTON_PRESSED;
}
else {
button_value_left = gpio_get(PIN_LEFT);
button_state_left = BUTTON_MAYBE_NOT_PRESSED;
}
break;
case BUTTON_MAYBE_NOT_PRESSED:
if (button_value_left == possible_left) {
button_value_left = gpio_get(PIN_LEFT);
button_state_left = BUTTON_PRESSED;
}
else {
button_value_left = gpio_get(PIN_LEFT);
button_state_left = BUTTON_NOT_PRESSED;
}
break;
default:
button_value_left = -1;
possible_left = -1;
break;
}
}
void button_pressing_right()
{
switch (button_state_right)
{
case RESET:
button_value_right = gpio_get(PIN_RIGHT);
button_state_right = BUTTON_NOT_PRESSED;
break;
case BUTTON_NOT_PRESSED:
if (gpio_get(PIN_RIGHT) == 0) {
button_value_right = gpio_get(PIN_RIGHT);
button_state_right = BUTTON_NOT_PRESSED;
}
else {
possible_right = button_value_right;
button_value_right = gpio_get(PIN_RIGHT);
button_state_right = BUTTON_MAYBE_PRESSED;
}
break;
case BUTTON_MAYBE_PRESSED:
if (button_value_right == possible_right) {
button_value_right = gpio_get(PIN_RIGHT);
right_control = 1;
// Optionally reset other controls
left_control = 0;
up_control = 0;
down_control = 0;
confirm_control = 0;
curser_x += previous_right;
previous_right *= acc;
previous_down = 1;
previous_up = 1;
previous_left = 1;
button_state_right = BUTTON_PRESSED;
}
else {
button_value_right = gpio_get(PIN_RIGHT);
button_state_right = BUTTON_NOT_PRESSED;
}
break;
case BUTTON_PRESSED:
if (button_value_right == possible_right) {
button_value_right = gpio_get(PIN_RIGHT);
button_state_right = BUTTON_PRESSED;
}
else {
button_value_right = gpio_get(PIN_RIGHT);
button_state_right = BUTTON_MAYBE_NOT_PRESSED;
}
break;
case BUTTON_MAYBE_NOT_PRESSED:
if (button_value_right == possible_right) {
button_value_right = gpio_get(PIN_RIGHT);
button_state_right = BUTTON_PRESSED;
}
else {
button_value_right = gpio_get(PIN_RIGHT);
button_state_right = BUTTON_NOT_PRESSED;
}
break;
default:
button_value_right = -1;
possible_right = -1;
break;
}
}
void button_pressing_up()
{
switch (button_state_up)
{
case RESET:
button_value_up = gpio_get(PIN_UP);
button_state_up = BUTTON_NOT_PRESSED;
break;
case BUTTON_NOT_PRESSED:
if (gpio_get(PIN_UP) == 0) {
button_value_up = gpio_get(PIN_UP);
button_state_up = BUTTON_NOT_PRESSED;
}
else {
possible_up = button_value_up;
button_value_up = gpio_get(PIN_UP);
button_state_up = BUTTON_MAYBE_PRESSED;
}
break;
case BUTTON_MAYBE_PRESSED:
if (button_value_up == possible_up) {
button_value_up = gpio_get(PIN_UP);
up_control = 1;
// Optionally reset other controls
left_control = 0;
right_control = 0;
down_control = 0;
confirm_control = 0;
curser_y -= previous_up;
previous_up *= acc;
previous_down = 1;
previous_left = 1;
previous_right = 1;
button_state_up = BUTTON_PRESSED;
}
else {
button_value_up = gpio_get(PIN_UP);
button_state_up = BUTTON_NOT_PRESSED;
}
break;
case BUTTON_PRESSED:
if (button_value_up == possible_up) {
button_value_up = gpio_get(PIN_UP);
button_state_up = BUTTON_PRESSED;
}
else {
button_value_up = gpio_get(PIN_UP);
button_state_up = BUTTON_MAYBE_NOT_PRESSED;
}
break;
case BUTTON_MAYBE_NOT_PRESSED:
if (button_value_up == possible_up) {
button_value_up = gpio_get(PIN_UP);
button_state_up = BUTTON_PRESSED;
}
else {
button_value_up = gpio_get(PIN_UP);
button_state_up = BUTTON_NOT_PRESSED;
}
break;
default:
button_value_up = -1;
possible_up = -1;
break;
}
}
void button_pressing_down()
{
switch (button_state_down)
{
case RESET:
button_value_down = gpio_get(PIN_DOWN);
button_state_down = BUTTON_NOT_PRESSED;
break;
case BUTTON_NOT_PRESSED:
if (gpio_get(PIN_DOWN) == 0) {
button_value_down = gpio_get(PIN_DOWN);
button_state_down = BUTTON_NOT_PRESSED;
}
else {
possible_down = button_value_down;
button_value_down = gpio_get(PIN_DOWN);
button_state_down = BUTTON_MAYBE_PRESSED;
}
break;
case BUTTON_MAYBE_PRESSED:
if (button_value_down == possible_down) {
button_value_down = gpio_get(PIN_DOWN);
down_control = 1;
// Optionally reset other controls
left_control = 0;
right_control = 0;
up_control = 0;
confirm_control = 0;
curser_y += previous_down;
previous_down *= acc;
previous_left = 1;
previous_up = 1;
previous_right = 1;
button_state_down = BUTTON_PRESSED;
}
else {
button_value_down = gpio_get(PIN_DOWN);
button_state_down = BUTTON_NOT_PRESSED;
}
break;
case BUTTON_PRESSED:
if (button_value_down == possible_down) {
button_value_down = gpio_get(PIN_DOWN);
button_state_down = BUTTON_PRESSED;
}
else {
button_value_down = gpio_get(PIN_DOWN);
button_state_down = BUTTON_MAYBE_NOT_PRESSED;
}
break;
case BUTTON_MAYBE_NOT_PRESSED:
if (button_value_down == possible_down) {
button_value_down = gpio_get(PIN_DOWN);
button_state_down = BUTTON_PRESSED;
}
else {
button_value_down = gpio_get(PIN_DOWN);
button_state_down = BUTTON_NOT_PRESSED;
}
break;
default:
button_value_down = -1;
possible_down = -1;
break;
}
}
uint8_t change_man = 0;
void button_pressing_confirm()
{
switch (button_state_confirm)
{
case RESET:
button_value_confirm = gpio_get(PIN_CONFIRM);
button_state_confirm = BUTTON_NOT_PRESSED;
break;
case BUTTON_NOT_PRESSED:
if (gpio_get(PIN_CONFIRM) == 0) {
button_value_confirm = gpio_get(PIN_CONFIRM);
button_state_confirm = BUTTON_NOT_PRESSED;
}
else {
possible_confirm = button_value_confirm;
button_value_confirm = gpio_get(PIN_CONFIRM);
button_state_confirm = BUTTON_MAYBE_PRESSED;
}
break;
case BUTTON_MAYBE_PRESSED:
if (button_value_confirm == possible_confirm) {
button_value_confirm = gpio_get(PIN_CONFIRM);
confirm_control = 1;
// Optionally reset other controls
left_control = 0;
right_control = 0;
up_control = 0;
down_control = 0;
if (button_control == -1) button_control = menu_choice;
else if (button_control == 2) change_man = 1;
else if (button_control == 0 || button_control == 1) {
for(int j = 0; j < live_count; j++) {
drawPixel(live_x[live_count]+1, live_y[live_count]+1, BLACK);
drawPixel(live_x[live_count]+1, live_y[live_count]-1, BLACK);
drawPixel(live_x[live_count]-1, live_y[live_count]+1, BLACK);
drawPixel(live_x[live_count], live_y[live_count], BLACK);
drawcell(live_x[j]/size, live_y[j] /size, 1);
live_x[j] = -1;
live_y[j] = -1;
}
live_count = 0;
}
button_state_confirm = BUTTON_PRESSED;
}
else {
button_value_confirm = gpio_get(PIN_CONFIRM);
button_state_confirm = BUTTON_NOT_PRESSED;
}
break;
case BUTTON_PRESSED:
if (button_value_confirm == possible_confirm) {
button_value_confirm = gpio_get(PIN_CONFIRM);
button_state_confirm = BUTTON_PRESSED;
}
else {
button_value_confirm = gpio_get(PIN_CONFIRM);
button_state_confirm = BUTTON_MAYBE_NOT_PRESSED;
}
break;
case BUTTON_MAYBE_NOT_PRESSED:
if (button_value_confirm == possible_confirm) {
button_value_confirm = gpio_get(PIN_CONFIRM);
button_state_confirm = BUTTON_PRESSED;
}
else {
button_value_confirm = gpio_get(PIN_CONFIRM);
button_state_confirm = BUTTON_NOT_PRESSED;
}
break;
default:
button_value_confirm = -1;
possible_confirm = -1;
break;
}
}
// ==============================================================================
// button fsm end
// ==============================================================================
void random_initial(){
if ( button_control == 1 && start_init) {
start_init = 0;
for (int i = 0; i < WIDTH_DISPLAY/size; i++){
for(int j = 0; j < HEIGHT/size; j++){
srand(time_us_32()); // Use microsecond timer to seed
int rand_bit = rand() % 2;
drawcell(i, j, rand_bit);
}
}
}
}
void pi_initial(){
int x_offset[4] = {50, 120, 50, 120}; // starting x position
int y_offset[4] = {70, 70, 150, 150}; // starting y position
int height = 50; // height of vertical legs
int bar_width = 40; // width of the top bar
if (button_control == 0 && start_init) {
start_init = 0;
for (int i = 0; i < 4; i++){
int left_x = x_offset[i];
int right_x = x_offset[i] + bar_width - 1;
// Top horizontal bar (solid)
for (int x = 0; x < bar_width; x++) {
drawcell(x_offset[i] + x, y_offset[i], 1);
}
// Left vertical leg
for (int y = 1; y < height - 1; y++) {
drawcell(left_x, y_offset[i] + y, 1);
}
// Bottom outward curve for left leg
drawcell(left_x - 1, y_offset[i] + height - 2, 1);
drawcell(left_x - 2, y_offset[i] + height - 1, 1);
// Right vertical leg
for (int y = 1; y < height - 1; y++) {
drawcell(right_x, y_offset[i] + y, 1);
}
// Bottom outward curve for right leg
drawcell(right_x + 1, y_offset[i] + height - 2, 1);
drawcell(right_x + 2, y_offset[i] + height - 1, 1);
}
}
}
int is_alive(int x, int y) {
int cnt = 0;
if (x > 0 & y > 0 & x < (WIDTH_DISPLAY/size-1) & y < (HEIGHT/size-1)) {
cnt = cell_array[x-1][y-1] + cell_array[x-1][y]
+ cell_array[x-1][y+1] + cell_array[x][y-1] + cell_array[x][y+1]
+ cell_array[x+1][y-1] + cell_array[x+1][y] + cell_array[x+1][y+1];
}
else if ( x == 0 && y == 0) {
cnt = cell_array[x][y+1] + cell_array[x+1][y] + cell_array[x+1][y+1];
}
else if ( x == (WIDTH_DISPLAY/size-1) && y == (HEIGHT/size-1)) {
cnt = cell_array[x-1][y-1] + cell_array[x-1][y] + cell_array[x][y-1];
}
else if ( x == 0 && y == (HEIGHT/size-1)) {
cnt = cell_array[x][y-1] + cell_array[x+1][y-1] + cell_array[x+1][y];
}
else if ( x == (WIDTH_DISPLAY/size-1) && y == 0) {
cnt = cell_array[x-1][y] + cell_array[x-1][y+1] + cell_array[x][y+1];
}
else if ( x == 0) {
cnt = cell_array[x][y-1] + cell_array[x][y+1]
+ cell_array[x+1][y-1] + cell_array[x+1][y] + cell_array[x+1][y+1];
}
else if ( y == 0) {
cnt = cell_array[x-1][y] + cell_array[x-1][y+1]
+ cell_array[x][y+1] + cell_array[x+1][y] + cell_array[x+1][y+1];
}
else if (x == (WIDTH_DISPLAY/size-1)) {
cnt = cell_array[x-1][y-1] + cell_array[x-1][y]
+ cell_array[x-1][y+1] + cell_array[x][y-1] + cell_array[x][y+1];
}
else if (y == (HEIGHT/size-1)) {
cnt = cell_array[x-1][y-1] + cell_array[x-1][y]
+ cell_array[x][y-1] + cell_array[x+1][y-1] + cell_array[x+1][y];
}
if (cnt == 3 && cell_array[x][y] == 0) {
cell_array_next[x][y] = 1;
}
else if (cnt > 3 || cnt < 2) {
cell_array_next[x][y] = 0;
}
return cell_array_next[x][y];
}
void update_alive(){
for (int i = 0; i< (WIDTH_DISPLAY/size); i++){
for (int j = 0; j < (HEIGHT/size); j++){
alive = is_alive (i,j);
if ( alive )
alive_count++;
}
}
count = alive_count;
}
void update_cell(){
for (int i = 0; i< (WIDTH_DISPLAY/size); i++){
for (int j = 0; j < (HEIGHT/size); j++){
if (cell_array[i][j] != cell_array_next[i][j]) {
if (cell_array_next[i][j]){
drawcell(i, j, 1);
}
else{
drawcell(i, j, 0);
}
}
cell_array[i][j] = cell_array_next[i][j];
}
}
}
// core 0: update alive
// static PT_THREAD (protothread_update_alive(struct pt *pt))
// {
// PT_BEGIN(pt);
// static int begin_time ;
// static int spare_time ;
// first_generation();
// while(1){
// update_alive();
// PT_YIELD_usec(1000) ;
// }
// PT_END(pt);
// } // alive thread
// core 1: animation
static PT_THREAD (protothread_anim(struct pt *pt))
{
PT_BEGIN(pt);
static int begin_time ;
static int spare_time ;
// first_generation();
// random_initial();
while(1){
if (button_control == -1) {
menu();
PT_YIELD_usec(5000);
continue;
}
alive_count = 0;
if (button_control != button_control_prev) {
x_min = -2;
x_max = 1;
y_min = -1;
y_max = 1;
button_control_prev = button_control;
fillRect(0, 0, WIDTH, HEIGHT, BLACK);
memset(cell_array, 0, sizeof(cell_array));
memset(cell_array_next, 0, sizeof(cell_array_next));
start_init = 1;
curser_x = default_curser_x;
curser_y = default_curser_y;
fillRect(528,0,112,480,WHITE);
if(button_control == 2){
for (int i = 0; i < WIDTH_DISPLAY; i++) {
x[i] = x_min + (x_max - x_min) * i / (WIDTH_DISPLAY - 1);
}
for (int i = 0; i < HEIGHT; i++) {
y[i] = y_min + (y_max - y_min) * i / (HEIGHT - 1);
}
mandelbrot();
}
}
if (change_man) {
float x_c, y_c;
float x1, x2 = 0;
float y1, y2 = 0;
x1 = x_min + zoom_start_x * (x_max - x_min) / WIDTH_DISPLAY;
x2 = x_min + zoom_end_x * (x_max - x_min) / WIDTH_DISPLAY;
y1 = y_min + zoom_start_y * (y_max - y_min) / WIDTH_DISPLAY;
y2 = y_min + zoom_end_y * (y_max - y_min) / WIDTH_DISPLAY;
x_c = (x1 + x2) / 2;
y_c = (y1 + y2) / 2;
x_min = x_c - (x2 - x1) / 2;
x_max = x_c + (x2 - x1) / 2;
y_min = y_c - (y2 - y1) / 2;
y_max = y_c + (y2 - y1) / 2;
for (int i = 0; i < WIDTH_DISPLAY; i++) {
x[i] = x_min + (x_max - x_min) * i / (WIDTH_DISPLAY - 1);
}
for (int i = 0; i < HEIGHT; i++) {
y[i] = y_min + (y_max - y_min) * i / (HEIGHT - 1);
}
mandelbrot();
change_man = 0;
}
pi_initial();
random_initial();
update_alive();
update_cell();
draw_curser();
draw_zoomin();
draw_title();
PT_YIELD_usec(1000) ;
}
PT_END(pt);
} // animation thread
static PT_THREAD (protothread_btn(struct pt *pt))
{
PT_BEGIN(pt);
static int begin_time ;
static int spare_time ;
// first_generation();
// random_initial();
while(1){
button_pressing_switch();
button_pressing_up();
button_pressing_down();
button_pressing_right();
button_pressing_left();
button_pressing_confirm();
alarm_irq();
// button_value = gpio_get(BUTTON_PIN)
PT_YIELD_usec(1000) ;
}
PT_END(pt);
} // btn thread
static PT_THREAD (protothread_mouse(struct pt *pt))
{
PT_BEGIN(pt);
static int begin_time ;
static int spare_time ;
// first_generation();
// random_initial();
while(1){
change_zoom_size();
PT_YIELD_usec(1000) ;
}
PT_END(pt);
}
void core1_main(){
// Add animation thread
pt_add_thread(protothread_anim);
pt_schedule_start ;
}
int main(){
stdio_init_all(); //Initialize all of the present standard stdio types that are linked into the binary
adc_init();
adc_gpio_init(ADC_PIN);
// initialize button gpio
gpio_init(BUTTON_PIN);
gpio_init(PIN_UP);
gpio_init(PIN_DOWN);
gpio_init(PIN_LEFT);
gpio_init(PIN_RIGHT);
gpio_init(PIN_CONFIRM);
gpio_set_dir(BUTTON_PIN, GPIO_IN);
gpio_set_dir(PIN_UP, GPIO_IN);
gpio_set_dir(PIN_DOWN, GPIO_IN);
gpio_set_dir(PIN_LEFT, GPIO_IN);
gpio_set_dir(PIN_RIGHT, GPIO_IN);
gpio_set_dir(PIN_CONFIRM, GPIO_IN);
initVGA(); //Initialize the hardware for the TFT
// tft_begin(); //Initialize the TFT
fillRect(0, 0, WIDTH, HEIGHT, BLACK); //Fill the entire screen with black colour
// initialize the array
// Beep
// Initialize SPI channel (channel, baud rate set to 20MHz)
spi_init(SPI_PORT, 20000000) ;
// Format (channel, data bits per transfer, polarity, phase, order)
spi_set_format(SPI_PORT, 16, 0, 0, 0);
// Map SPI signals to GPIO ports
gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);
gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
gpio_set_function(PIN_CS, GPIO_FUNC_SPI) ;
// Map LDAC pin to GPIO port, hold it low (could alternatively tie to GND)
gpio_init(LDAC) ;
gpio_set_dir(LDAC, GPIO_OUT) ;
gpio_put(LDAC, 0) ;
// Setup the ISR-timing GPIO
gpio_init(ISR_GPIO) ;
gpio_set_dir(ISR_GPIO, GPIO_OUT);
gpio_put(ISR_GPIO, 0) ;
// set up increments for calculating bow envelope
attack_inc = divfix(max_amplitude, int2fix15(ATTACK_TIME)) ;
decay_inc = divfix(max_amplitude, int2fix15(DECAY_TIME)) ;
// Build the sine lookup table
// scaled to produce values between 0 and 4096 (for 12-bit DAC)
int ii;
for (ii = 0; ii < sine_table_size; ii++){
sin_table[ii] = float2fix15(2047*sin((float)ii*6.283/(float)sine_table_size));
}
// Enable the interrupt for the alarm (we're using Alarm 0)
hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM) ;
// Associate an interrupt handler with the ALARM_IRQ
irq_set_exclusive_handler(ALARM_IRQ, alarm_irq) ;
// Enable the alarm interrupt
irq_set_enabled(ALARM_IRQ, true) ;
// Write the lower 32 bits of the target time to the alarm register, arming it.
timer_hw->alarm[ALARM_NUM] = timer_hw->timerawl + DELAY ;
//Beep end
// start core 1
multicore_reset_core1();
multicore_launch_core1(&core1_main);
// add threads
pt_add_thread(protothread_btn);
// pt_add_thread(protothread_update_alive);
pt_add_thread(protothread_mouse);
// start scheduler
pt_schedule_start ;
}