Skip to content

Instantly share code, notes, and snippets.

@imax9000
Last active Aug 26, 2021
Embed
What would you like to do?
SECTIONS {
__vector_20 = __vector_20_override;
}
#include <Arduino.h>
#define BS_B _BV(0)
#define BS_START _BV(1)
#define BS_SELECT _BV(2)
#define BS_A _BV(3)
#define BS_LEFT _BV(0)
#define BS_DOWN _BV(1)
#define BS_UP _BV(2)
#define BS_RIGHT _BV(3)
namespace pin {
const int up = 4;
const int down = 3;
const int left = 2;
const int right = 5;
const int A = 9;
const int B = 8;
const int select = 6;
const int start = 7;
// These are fixed: port manipulation code assumes that they have specific
// values and won't adjust automatically if these constants are chagned.
const int left_b = 17;
const int down_start = 16;
const int up_select = 15;
const int right_a = 14;
// ISR assumes that these are on PORTD.
const int ab_scan = 21;
const int dpad_scan = 20;
}; // namespace pin
volatile uint8_t buttons_state = 0xF;
volatile uint8_t dpad_state = 0xF;
void updateButtonState(int pin, uint8_t button, volatile uint8_t *state) {
if (digitalRead(pin)) {
*state |= button;
Serial.print("Button ");
Serial.print(pin);
Serial.println(" released");
} else {
*state &= ~button;
Serial.print("Button ");
Serial.print(pin);
Serial.println(" pressed");
}
}
// Custom linker script replaces PORTD ISR with this.
ISR(__vector_20_override) {
PORT_t *portStruct = portToPortStruct(PD);
uint8_t int_flags = portStruct->INTFLAGS;
if (digitalPinToBitMask(pin::ab_scan) & int_flags) {
PORTD.OUT = (PORTD.OUT & (~0xF)) | (buttons_state & 0xF);
portStruct->INTFLAGS = digitalPinToBitMask(pin::ab_scan);
}
if (digitalPinToBitMask(pin::dpad_scan) & int_flags) {
PORTD.OUT = (PORTD.OUT & (~0xF)) | (dpad_state & 0xF);
portStruct->INTFLAGS = digitalPinToBitMask(pin::dpad_scan);
}
}
void setup() {
Serial.begin(9600);
pinMode(pin::left_b, OUTPUT);
pinMode(pin::down_start, OUTPUT);
pinMode(pin::up_select, OUTPUT);
pinMode(pin::right_a, OUTPUT);
pinMode(pin::ab_scan, INPUT_PULLUP);
pinMode(pin::dpad_scan, INPUT_PULLUP);
digitalWrite(pin::left_b, HIGH);
digitalWrite(pin::down_start, HIGH);
digitalWrite(pin::up_select, HIGH);
digitalWrite(pin::right_a, HIGH);
// Configure the port to receive interrupts. No handler specified, since we
// override the handler for the whole port.
attachInterrupt(digitalPinToInterrupt(pin::ab_scan), nullptr, FALLING);
attachInterrupt(digitalPinToInterrupt(pin::dpad_scan), nullptr, FALLING);
// Input button pins
for (int pin = 2; pin <= 9; pin++) {
pinMode(pin, INPUT_PULLUP);
}
attachInterrupt(
pin::A, []() { updateButtonState(pin::A, BS_A, &buttons_state); },
CHANGE);
attachInterrupt(
pin::B, []() { updateButtonState(pin::B, BS_B, &buttons_state); },
CHANGE);
attachInterrupt(
pin::select,
[]() { updateButtonState(pin::select, BS_SELECT, &buttons_state); },
CHANGE);
attachInterrupt(
pin::start,
[]() { updateButtonState(pin::start, BS_START, &buttons_state); },
CHANGE);
attachInterrupt(
pin::up, []() { updateButtonState(pin::up, BS_UP, &dpad_state); },
CHANGE);
attachInterrupt(
pin::down, []() { updateButtonState(pin::down, BS_DOWN, &dpad_state); },
CHANGE);
attachInterrupt(
pin::left, []() { updateButtonState(pin::left, BS_LEFT, &dpad_state); },
CHANGE);
attachInterrupt(
pin::right,
[]() { updateButtonState(pin::right, BS_RIGHT, &dpad_state); }, CHANGE);
}
void loop() {}
BOARD := arduino:megaavr:nona4809:mode=off
PORT ?= $(wildcard /dev/cu.usbmodem*)
.PHONY: all upload build format
all: build
format:
clang-format -i $$(find . -name \*.cpp -o -name \*.ino -o -name \*.h)
build: format
arduino-cli compile --fqbn $(BOARD) --build-property compiler.c.elf.extra_flags=isr_override.ld .
upload: format
arduino-cli compile --fqbn $(BOARD) --build-property compiler.c.elf.extra_flags=isr_override.ld --upload --port $(PORT) .
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment