#include <ao.h>
#include <ao_exti.h>
-struct samd21_exti {
- void (*callback)(void);
- uint8_t port;
- uint8_t pin;
+struct ao_samd21_exti {
+ void (*callback)(void);
+ struct samd21_port *port;
+ uint8_t pin;
};
-#if 0
-static struct samd21_exti ao_samd_exti[SAMD21_NUM_EVSYS];
+static struct ao_samd21_exti ao_samd21_exti[SAMD21_NUM_EIC];
+
+static uint8_t
+pin_id(struct samd21_port *port, uint8_t pin)
+{
+ /* Why, atmel, why? */
+ if (port == &samd21_port_a) {
+ switch (pin) {
+ case 24:
+ case 25:
+ case 27:
+ return pin - 12;
+ case 28:
+ case 30:
+ case 31:
+ return pin - 20;
+ default:
+ break;
+ }
+ }
+
+ /* most pins use exti mapped to their pin number directly (mod 16) */
+ return pin & 0xf;
+}
-static uint32_t ao_exti_inuse;
-#endif
void
-samd21_evsys_isr(void)
+samd21_eic_isr(void)
{
+ uint32_t intflag = samd21_eic.intflag;
+ uint8_t id;
+
+ for (id = 0; id < SAMD21_NUM_EIC; id++) {
+ uint32_t mask = (1 << id);
+
+ if (intflag & mask) {
+ samd21_eic.intflag = mask;
+ if (ao_samd21_exti[id].callback)
+ (*ao_samd21_exti[id].callback)();
+ }
+ }
+}
+
+static void
+_ao_exti_set_sense(uint8_t id, uint8_t mode)
+{
+ uint8_t sense = mode & (SAMD21_EIC_CONFIG_SENSE_RISE | SAMD21_EIC_CONFIG_SENSE_FALL);
+ uint8_t n = SAMD21_EIC_CONFIG_N(id);
+ uint32_t config;
+
+ config = samd21_eic.config[n];
+ config &= ~(SAMD21_EIC_CONFIG_SENSE_MASK << SAMD21_EIC_CONFIG_SENSE(id));
+ config |= (sense << SAMD21_EIC_CONFIG_SENSE(id));
+ samd21_eic.config[n] = config;
}
void
ao_exti_setup (struct samd21_port *port, uint8_t pin, uint8_t mode, void (*callback)(void))
{
- (void) port;
- (void) pin;
- (void) mode;
- (void) callback;
-#if 0
- uint8_t id = pin_id(port,pin);
- uint8_t pint;
- uint8_t mask;
- uint8_t prio;
-
- for (pint = 0; pint < SAMD21_NUM_EVSYS; pint++)
- if ((ao_exti_inuse & (1 << pint)) == 0)
- break;
+ uint8_t id = pin_id(port,pin);
+ struct ao_samd21_exti *exti = &ao_samd21_exti[id];
- if (pint == SAMD21_NUM_EVSYS)
+ if (exti->port)
ao_panic(AO_PANIC_EXTI);
if (!(mode & AO_EXTI_PIN_NOCONFIGURE))
ao_enable_input(port, pin, mode);
ao_arch_block_interrupts();
- mask = (1 << pint);
- ao_exti_inuse |= mask;
- ao_pint_enabled &= (uint8_t) ~mask;
-
- ao_pint_map[id] = pint;
- ao_exti_callback[pint] = callback;
- /* configure gpio to interrupt routing */
- lpc_scb.pintsel[pint] = id;
+ exti->port = port;
+ exti->pin = pin;
+ exti->callback = callback;
/* Set edge triggered */
- lpc_gpio_pin.isel &= ~mask;
+ _ao_exti_set_sense(id, mode);
- ao_pint_enabled &= (uint8_t) ~mask;
- ao_pint_mode[pint] = mode;
- _ao_exti_set_enable(pint);
-
- /* Set interrupt mask and rising/falling mode */
-
- prio = AO_LPC_NVIC_MED_PRIORITY;
- if (mode & AO_EXTI_PRIORITY_LOW)
- prio = AO_LPC_NVIC_LOW_PRIORITY;
- else if (mode & AO_EXTI_PRIORITY_HIGH)
- prio = AO_LPC_NVIC_HIGH_PRIORITY;
-
- /* Set priority and enable */
- lpc_nvic_set_priority(LPC_ISR_PIN_INT0_POS + pint, prio);
- lpc_nvic_set_enable(LPC_ISR_PIN_INT0_POS + pint);
ao_arch_release_interrupts();
-#endif
}
void
ao_exti_set_mode(struct samd21_port *port, uint8_t pin, uint8_t mode)
{
- (void) port;
- (void) pin;
- (void) mode;
-#if 0
- uint8_t id = pin_id(port,pin);
- uint8_t pint = ao_pint_map[id];
+ uint8_t id = pin_id(port,pin);
ao_arch_block_interrupts();
- ao_pint_mode[pint] = mode;
- _ao_exti_set_enable(pint);
+ _ao_exti_set_sense(id, mode);
ao_arch_release_interrupts();
-#endif
}
void
ao_exti_set_callback(struct samd21_port *port, uint8_t pin, void (*callback)(void))
{
- (void) port;
- (void) pin;
- (void) callback;
-#if 0
uint8_t id = pin_id(port,pin);
- uint8_t pint = ao_pint_map[id];
- ao_exti_callback[pint] = callback;
-#endif
+ ao_arch_block_interrupts();
+ ao_samd21_exti[id].callback = callback;
+ ao_arch_release_interrupts();
}
void
ao_exti_enable(struct samd21_port *port, uint8_t pin)
{
- (void) port;
- (void) pin;
-#if 0
uint8_t id = pin_id(port,pin);
- uint8_t pint = ao_pint_map[id];
- uint8_t mask = 1 << pint;
ao_arch_block_interrupts();
- ao_pint_enabled |= mask;
- _ao_exti_set_enable(pint);
+ samd21_eic.intenset = 1 << id;
+ /* configure gpio to interrupt routing */
+ samd21_port_pmux_set(port, pin, SAMD21_PORT_PMUX_FUNC_A);
ao_arch_release_interrupts();
-#endif
}
void
ao_exti_disable(struct samd21_port *port, uint8_t pin)
{
- (void) port;
- (void) pin;
-#if 0
uint8_t id = pin_id(port,pin);
- uint8_t pint = ao_pint_map[id];
- uint8_t mask = 1 << pint;
ao_arch_block_interrupts();
- ao_pint_enabled &= (uint8_t) ~mask;
- _ao_exti_set_enable(pint);
+ samd21_eic.intenclr = 1 << id;
+ /* configure gpio to interrupt routing */
+ samd21_port_pmux_clr(port, pin);
ao_arch_release_interrupts();
-#endif
}
void
ao_exti_init(void)
{
+ samd21_gclk_clkctrl(0, SAMD21_GCLK_CLKCTRL_ID_EIC);
+
+ /* Reset */
+ samd21_eic.ctrl = (1 << SAMD21_EIC_CTRL_SWRST);
+
+ while (samd21_eic.status & (1 << SAMD21_EIC_STATUS_SYNCBUSY))
+ ;
+
+ /* Wire up interrupts */
+ samd21_nvic_set_enable(SAMD21_NVIC_ISR_EIC_POS);
+ samd21_nvic_set_priority(SAMD21_NVIC_ISR_EIC_POS, 3);
+
+ /* Enable */
+ samd21_eic.ctrl = (1 << SAMD21_EIC_CTRL_ENABLE);
}