// Simulation of my submission for the final project for the 2021
// HackadayU course 'Raspberry Pi Pico and RP2040 - The Deep Dive
// This simulation runs Pong on the Raspberry Pi Pico, using a
// custom PIO-based composite video peripheral
// Alan Reed, 2021
#include <stdio.h>
#include "pico/stdlib.h"
#include <stdlib.h>
#include "hardware/timer.h"
#include "hardware/gpio.h"
#include "connections.h"
#include "pong.h"
// Use alarm 0
#define ALARM_NUM 0
#define ALARM_IRQ TIMER_IRQ_0
// Manual timer initialisation as the timer SDK functions don't seem to work on sim
// Code borrowed from Pico Examples repo
static void alarm_in_us(uint32_t delay_us) {
// Enable the interrupt for our alarm (the timer outputs 4 alarm irqs)
hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
// Set irq handler for alarm irq
irq_set_exclusive_handler(ALARM_IRQ, alarm_irq);
// Enable the alarm irq
irq_set_enabled(ALARM_IRQ, true);
// Enable interrupt in block and at processor
// Alarm is only 32 bits so if trying to delay more
// than that need to be careful and keep track of the upper
// bits
uint64_t target = timer_hw->timerawl + delay_us;
// Write the lower 32 bits of the target time to the alarm which
// will arm it
timer_hw->alarm[ALARM_NUM] = (uint32_t) target;
}
static void alarm_irq(void) {
// Clear the alarm irq
hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM);
// Assume alarm 0 has fired
alarm_in_us(PONG_FRAME_INTERVAL_ms * 1000);
pong_tick();
}
void button_cb(unsigned int gpio, uint32_t events) {
if (events & GPIO_IRQ_EDGE_RISE) {
if (gpio == PLAYER1_BUTTON_UP || gpio == PLAYER1_BUTTON_DOWN) {
pong_move_player(1, PONG_DIRECTION_STOP);
}
else if (gpio == PLAYER2_BUTTON_UP || gpio == PLAYER2_BUTTON_DOWN) {
pong_move_player(2, PONG_DIRECTION_STOP);
}
} else if (events & GPIO_IRQ_EDGE_FALL) {
switch(gpio) {
case PLAYER1_BUTTON_UP:
pong_move_player(1, PONG_DIRECTION_UP);
break;
case PLAYER1_BUTTON_DOWN:
pong_move_player(1, PONG_DIRECTION_DOWN);
break;
case PLAYER2_BUTTON_UP:
pong_move_player(2, PONG_DIRECTION_UP);
break;
case PLAYER2_BUTTON_DOWN:
pong_move_player(2, PONG_DIRECTION_DOWN);
break;
}
}
}
void setup() {
Serial1.begin(115200);
// stdio_init_all();
gpio_set_function(SERIAL_RX_PIN, GPIO_FUNC_UART);
gpio_set_function(SERIAL_TX_PIN, GPIO_FUNC_UART);
Serial1.print("Pi Pico Pong\r\n");
Serial1.print("Created by Alan Reed\r\n");
pong_init();
irq_set_enabled(TIMER_IRQ_3, false);
// struct repeating_timer timer;
// add_repeating_timer_ms(PONG_FRAME_INTERVAL_ms, pong_gametick_callback, NULL, &timer);
gpio_pull_up(PLAYER1_BUTTON_DOWN);
gpio_pull_up(PLAYER1_BUTTON_UP);
gpio_pull_up(PLAYER2_BUTTON_DOWN);
gpio_pull_up(PLAYER2_BUTTON_UP);
gpio_set_irq_enabled_with_callback(PLAYER1_BUTTON_DOWN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &button_cb);
gpio_set_irq_enabled_with_callback(PLAYER1_BUTTON_UP, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &button_cb);
gpio_set_irq_enabled_with_callback(PLAYER2_BUTTON_DOWN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &button_cb);
gpio_set_irq_enabled_with_callback(PLAYER2_BUTTON_UP, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &button_cb);
// Set the tick timer going
alarm_in_us(PONG_FRAME_INTERVAL_ms * 1000);
}
void loop() {
pong_update();
}