// 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();
}
pico:GP0
pico:GP1
pico:GND.1
pico:GP2
pico:GP3
pico:GP4
pico:GP5
pico:GND.2
pico:GP6
pico:GP7
pico:GP8
pico:GP9
pico:GND.3
pico:GP10
pico:GP11
pico:GP12
pico:GP13
pico:GND.4
pico:GP14
pico:GP15
pico:GP16
pico:GP17
pico:GND.5
pico:GP18
pico:GP19
pico:GP20
pico:GP21
pico:GND.6
pico:GP22
pico:RUN
pico:GP26
pico:GP27
pico:GND.7
pico:GP28
pico:ADC_VREF
pico:3V3
pico:3V3_EN
pico:GND.8
pico:VSYS
pico:VBUS
tv1:IN
tv1:SYNC
tv1:GND
tv1:VCC
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
btn4:1.l
btn4:2.l
btn4:1.r
btn4:2.r