|
|
|
|
|
|
|
|
|
|
|
#include "Arduino.h" |
|
|
|
|
|
#include "pins_arduino.h" |
|
|
|
|
|
#include "debug/printf.h" |
|
|
|
|
|
|
|
|
|
|
|
static void dummy_isr() {}; |
|
|
|
|
|
typedef void (*voidFuncPtr)(void); |
|
|
|
|
|
|
|
|
|
|
|
// TODO: define these properly in core_pins.h - don't waste memory |
|
|
|
|
|
#define CORE_MAX_PIN_PORT1 31 |
|
|
|
|
|
#define CORE_MAX_PIN_PORT2 31 |
|
|
|
|
|
#define CORE_MAX_PIN_PORT3 31 |
|
|
|
|
|
#define CORE_MAX_PIN_PORT4 31 |
|
|
|
|
|
|
|
|
|
|
|
voidFuncPtr isr_table_gpio1[CORE_MAX_PIN_PORT1+1] = { [0 ... CORE_MAX_PIN_PORT1] = dummy_isr }; |
|
|
|
|
|
voidFuncPtr isr_table_gpio2[CORE_MAX_PIN_PORT2+1] = { [0 ... CORE_MAX_PIN_PORT2] = dummy_isr }; |
|
|
|
|
|
voidFuncPtr isr_table_gpio3[CORE_MAX_PIN_PORT3+1] = { [0 ... CORE_MAX_PIN_PORT3] = dummy_isr }; |
|
|
|
|
|
voidFuncPtr isr_table_gpio4[CORE_MAX_PIN_PORT4+1] = { [0 ... CORE_MAX_PIN_PORT4] = dummy_isr }; |
|
|
|
|
|
|
|
|
|
|
|
#define DR 0 |
|
|
|
|
|
#define GDIR 1 |
|
|
|
|
|
#define PSR 2 |
|
|
|
|
|
#define ICR1 3 |
|
|
|
|
|
#define ICR2 4 |
|
|
|
|
|
#define IMR 5 |
|
|
|
|
|
#define ISR 6 |
|
|
|
|
|
#define EDGE 7 |
|
|
|
|
|
|
|
|
|
|
|
FASTRUN |
|
|
|
|
|
void irq_anyport(volatile uint32_t *gpio, voidFuncPtr *table) |
|
|
|
|
|
{ |
|
|
|
|
|
uint32_t status = gpio[ISR] & gpio[IMR]; |
|
|
|
|
|
gpio[ISR] = status; |
|
|
|
|
|
while (status) { |
|
|
|
|
|
uint32_t index = __builtin_ctz(status); |
|
|
|
|
|
table[index](); |
|
|
|
|
|
status = status & ~(1 << index); |
|
|
|
|
|
//status = status & (status - 1); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
FASTRUN |
|
|
|
|
|
void irq_gpio1(void) |
|
|
|
|
|
{ |
|
|
|
|
|
irq_anyport(&GPIO1_DR, isr_table_gpio1); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
FASTRUN |
|
|
|
|
|
void irq_gpio2(void) |
|
|
|
|
|
{ |
|
|
|
|
|
irq_anyport(&GPIO2_DR, isr_table_gpio2); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
FASTRUN |
|
|
|
|
|
void irq_gpio3(void) |
|
|
|
|
|
{ |
|
|
|
|
|
irq_anyport(&GPIO3_DR, isr_table_gpio3); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
FASTRUN |
|
|
|
|
|
void irq_gpio4(void) |
|
|
|
|
|
{ |
|
|
|
|
|
irq_anyport(&GPIO4_DR, isr_table_gpio4); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void attachInterrupt(uint8_t pin, void (*function)(void), int mode) |
|
|
|
|
|
{ |
|
|
|
|
|
if (pin >= CORE_NUM_DIGITAL) return; |
|
|
|
|
|
//printf("attachInterrupt, pin=%u\n", pin); |
|
|
|
|
|
volatile uint32_t *gpio = portOutputRegister(pin); |
|
|
|
|
|
volatile uint32_t *mux = portConfigRegister(pin); |
|
|
|
|
|
//volatile uint32_t *pad = portControlRegister(pin); |
|
|
|
|
|
uint32_t mask = digitalPinToBitMask(pin); |
|
|
|
|
|
|
|
|
|
|
|
voidFuncPtr *table; |
|
|
|
|
|
switch((uint32_t)gpio) { |
|
|
|
|
|
case (uint32_t)&GPIO1_DR: |
|
|
|
|
|
table = isr_table_gpio1; |
|
|
|
|
|
attachInterruptVector(IRQ_GPIO1_0_15, &irq_gpio1); |
|
|
|
|
|
attachInterruptVector(IRQ_GPIO1_16_31, &irq_gpio1); |
|
|
|
|
|
NVIC_ENABLE_IRQ(IRQ_GPIO1_0_15); |
|
|
|
|
|
NVIC_ENABLE_IRQ(IRQ_GPIO1_16_31); |
|
|
|
|
|
break; |
|
|
|
|
|
case (uint32_t)&GPIO2_DR: |
|
|
|
|
|
table = isr_table_gpio2; |
|
|
|
|
|
attachInterruptVector(IRQ_GPIO2_0_15, &irq_gpio2); |
|
|
|
|
|
attachInterruptVector(IRQ_GPIO2_16_31, &irq_gpio2); |
|
|
|
|
|
NVIC_ENABLE_IRQ(IRQ_GPIO2_0_15); |
|
|
|
|
|
NVIC_ENABLE_IRQ(IRQ_GPIO2_16_31); |
|
|
|
|
|
break; |
|
|
|
|
|
case (uint32_t)&GPIO3_DR: |
|
|
|
|
|
table = isr_table_gpio3; |
|
|
|
|
|
attachInterruptVector(IRQ_GPIO3_0_15, &irq_gpio3); |
|
|
|
|
|
attachInterruptVector(IRQ_GPIO3_16_31, &irq_gpio3); |
|
|
|
|
|
NVIC_ENABLE_IRQ(IRQ_GPIO3_0_15); |
|
|
|
|
|
NVIC_ENABLE_IRQ(IRQ_GPIO3_16_31); |
|
|
|
|
|
break; |
|
|
|
|
|
case (uint32_t)&GPIO4_DR: |
|
|
|
|
|
table = isr_table_gpio4; |
|
|
|
|
|
attachInterruptVector(IRQ_GPIO4_0_15, &irq_gpio4); |
|
|
|
|
|
attachInterruptVector(IRQ_GPIO4_16_31, &irq_gpio4); |
|
|
|
|
|
NVIC_ENABLE_IRQ(IRQ_GPIO4_0_15); |
|
|
|
|
|
NVIC_ENABLE_IRQ(IRQ_GPIO4_16_31); |
|
|
|
|
|
break; |
|
|
|
|
|
default: |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint32_t icr; |
|
|
|
|
|
switch (mode) { |
|
|
|
|
|
case CHANGE: icr = 0; break; |
|
|
|
|
|
case RISING: icr = 2; break; |
|
|
|
|
|
case FALLING: icr = 3; break; |
|
|
|
|
|
case LOW: icr = 0; break; |
|
|
|
|
|
case HIGH: icr = 1; break; |
|
|
|
|
|
default: return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TODO: global interrupt disable to protect these read-modify-write accesses? |
|
|
|
|
|
gpio[IMR] &= ~mask; // disable interrupt |
|
|
|
|
|
*mux = 5; // pin is GPIO |
|
|
|
|
|
gpio[GDIR] &= ~mask; // pin to input mode |
|
|
|
|
|
uint32_t index = __builtin_ctz(mask); |
|
|
|
|
|
table[index] = function; |
|
|
|
|
|
if (mode == CHANGE) { |
|
|
|
|
|
gpio[EDGE] |= mask; |
|
|
|
|
|
} else { |
|
|
|
|
|
gpio[EDGE] &= ~mask; |
|
|
|
|
|
if (index < 15) { |
|
|
|
|
|
uint32_t shift = index * 2; |
|
|
|
|
|
gpio[ICR1] = (gpio[ICR1] & ~(3 << shift)) | (icr << shift); |
|
|
|
|
|
} else { |
|
|
|
|
|
uint32_t shift = (index - 16) * 2; |
|
|
|
|
|
gpio[ICR2] = (gpio[ICR2] & ~(3 << shift)) | (icr << shift); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
gpio[ISR] = mask; // clear any prior pending interrupt |
|
|
|
|
|
gpio[IMR] |= mask; // enable interrupt |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void detachInterrupt(uint8_t pin) |
|
|
|
|
|
{ |
|
|
|
|
|
if (pin >= CORE_NUM_DIGITAL) return; |
|
|
|
|
|
volatile uint32_t *gpio = portOutputRegister(pin); |
|
|
|
|
|
uint32_t mask = digitalPinToBitMask(pin); |
|
|
|
|
|
gpio[IMR] &= ~mask; |
|
|
|
|
|
} |
|
|
|
|
|
|