Uses the external interrupt controller. Careful about pin mapping.
Signed-off-by: Keith Packard <keithp@keithp.com>
#ifndef _AO_EXTI_H_
#define _AO_EXTI_H_
-#define AO_EXTI_MODE_RISING 1
-#define AO_EXTI_MODE_FALLING 2
+#define AO_EXTI_MODE_RISING SAMD21_EIC_CONFIG_SENSE_RISE
+#define AO_EXTI_MODE_FALLING SAMD21_EIC_CONFIG_SENSE_FALL
#define AO_EXTI_MODE_PULL_NONE 0
#define AO_EXTI_MODE_PULL_UP 4
#define AO_EXTI_MODE_PULL_DOWN 8
#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);
}
#define SAMD21_DMAC_DESC_BTCTRL_STEPSIZE_X64 6UL
#define SAMD21_DMAC_DESC_BTCTRL_STEPSIZE_X128 7UL
+struct samd21_eic {
+ vuint8_t ctrl;
+ vuint8_t status;
+ vuint8_t nmictrl;
+ vuint8_t nmiflag;
+ vuint32_t evctrl;
+ vuint32_t intenclr;
+ vuint32_t intenset;
+
+ vuint32_t intflag;
+ vuint32_t wakeup;
+ vuint32_t config[2];
+};
+
+extern struct samd21_eic samd21_eic;
+
+#define samd21_eic (*(struct samd21_eic *) 0x40001800)
+
+#define SAMD21_NUM_EIC 16
+
+#define SAMD21_EIC_CTRL_ENABLE 1
+#define SAMD21_EIC_CTRL_SWRST 0
+
+#define SAMD21_EIC_STATUS_SYNCBUSY 7
+
+#define SAMD21_EIC_NMICTRL_NMIFILTEN 3
+#define SAMD21_EIC_NMICTRL_NMISENSE 0
+
+#define SAMD21_EIC_NMIFLAG_NMI 0
+
+#define SAMD21_EIC_EVCTRL_EXTINTEO(n) (n)
+
+#define SAMD21_EIC_INTENCLR_EXTINT(n) (n)
+
+#define SAMD21_EIC_INTENSET_EXTINT(n) (n)
+
+#define SAMD21_EIC_INTFLAG_EXTINT(n) (n)
+#define SAMD21_EIC_WAKEUP_WAKEUPEN(n) (n)
+#define SAMD21_EIC_CONFIG_N(n) ((n) >> 3)
+#define SAMD21_EIC_CONFIG_SENSE(n) (((n) & 7) << 2)
+#define SAMD21_EIC_CONFIG_FILTEN(n) (SAMD21_EIC_CONFIG_SENSE(n) + 3)
+#define SAMD21_EIC_CONFIG_SENSE_NONE 0
+#define SAMD21_EIC_CONFIG_SENSE_RISE 1
+#define SAMD21_EIC_CONFIG_SENSE_FALL 2
+#define SAMD21_EIC_CONFIG_SENSE_BOTH 3
+#define SAMD21_EIC_CONFIG_SENSE_HIGH 4
+#define SAMD21_EIC_CONFIG_SENSE_LOW 5
+#define SAMD21_EIC_CONFIG_SENSE_MASK 7UL
+
struct samd21_nvmctrl {
vuint32_t ctrla;
vuint32_t ctrlb;
#define samd21_evsys (*(struct samd21_evsys *) 0x42000400)
+#define SAMD21_EVSYS_CONTROL_SWRST 0
+#define SAMD21_EVSYS_CONTROL_GCLKREQ 4
+
+#define SAMD21_EVSYS_CHANNEL_CHANNEL 0
+
+#define SAMD21_EVSYS_CHANNEL_SWEVT 8
+
+#define SAMD21_EVSYS_CHANNEL_EVGEN 16
+#define SAMD21_EVSYS_CHANNEL_EVGEN_NONE 0x00
+#define SAMD21_EVSYS_CHANNEL_EVGEN_RTC_CMP(i) (0x01 + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_OVF 0x03
+#define SAMD21_EVSYS_CHANNEL_EVGEN_PER(i) (0x04 + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_EXTINT(i) (0x0c + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_DMAC_CH(i) (0x1e + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC0_OVF 0x22
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC0_TRG 0x23
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC0_CNT 0x29
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC0_MCX(i) (0x25 + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC1_OVF 0x29
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC1_TRG 0x2a
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC1_CNT 0x2b
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC1_MCX(i) (0x2c + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC2_OVF 0x2e
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC2_TRG 0x2f
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC2_CNT 0x30
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC2_MCX(i) (0x31 + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TC3_OVF 0x33
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TC3_MC(i) (0x34 + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TC4_OVF 0x36
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TC4_MC(i) (0x37 + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TC5_OVF 0x39
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TC5_MC(i) (0x3a + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TC6_OVF 0x3c
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TC6_MC(i) (0x3d + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TC7_OVF 0x3f
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TC7_MC(i) (0x40 + (i))
+#define SAMD21_EVSYS_CHANNEL_EVGEN_ADC_RESRDY 0x42
+#define SAMD21_EVSYS_CHANNEL_EVGEN_ADC_WINMON 0x43
+#define SAMD21_EVSYS_CHANNEL_EVGEN_AC_COMP0 0x44
+#define SAMD21_EVSYS_CHANNEL_EVGEN_AC_COMP1 0x45
+#define SAMD21_EVSYS_CHANNEL_EVGEN_AC_WIN0 0x46
+#define SAMD21_EVSYS_CHANNEL_EVGEN_DAC_EMPTY 0x47
+#define SAMD21_EVSYS_CHANNEL_EVGEN_PTC_EOC 0x48
+#define SAMD21_EVSYS_CHANNEL_EVGEN_PTC_WCOMP 0x49
+#define SAMD21_EVSYS_CHANNEL_EVGEN_AC_COMP2 0x4a
+#define SAMD21_EVSYS_CHANNEL_EVGEN_AC_COMP3 0x4b
+#define SAMD21_EVSYS_CHANNEL_EVGEN_AC_WIN1 0x4c
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC3_OVF 0x4d
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC3_TRG 0x4e
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC3_CNT 0x4f
+#define SAMD21_EVSYS_CHANNEL_EVGEN_TCC3_MCX(i) (0x50 + (i))
+
+#define SAMD21_EVSYS_CHANNEL_PATH 24
+#define SAMD21_EVSYS_CHANNEL_PATH_SYNCHRONOUS 0
+#define SAMD21_EVSYS_CHANNEL_PATH_RESYNCHRONIZED 1
+#define SAMD21_EVSYS_CHANNEL_PATH_ASYNCHRONOUS 2
+
+#define SAMD21_EVSYS_CHANNEL_EDGESEL 26
+#define SAMD21_EVSYS_CHANNEL_EDGESEL_NO_EVT_OUTPUT 0
+#define SAMD21_EVSYS_CHANNEL_EDGESEL_RISING_EDGE 1
+#define SAMD21_EVSYS_CHANNEL_EDGESEL_FALLING_EDGE 2
+#define SAMD21_EVSYS_CHANNEL_EDGESEL_BOTH_EDGES 3
+
+#define SAMD21_EVSYS_USER_USER 0
+#define SAMD21_EVSYS_USER_USER_DMAC_CH(n) (0x00 + (n))
+#define SAMD21_EVSYS_USER_USER_TCC0_EV(n) (0x04 + (n))
+#define SAMD21_EVSYS_USER_USER_TCC0_MC(n) (0x06 + (n))
+#define SAMD21_EVSYS_USER_USER_TCC1_EV(n) (0x0a + (n))
+#define SAMD21_EVSYS_USER_USER_TCC1_MC(n) (0x0c + (n))
+#define SAMD21_EVSYS_USER_USER_TCC2_EV(n) (0x0e + (n))
+#define SAMD21_EVSYS_USER_USER_TCC2_MC(n) (0x10 + (n))
+#define SAMD21_EVSYS_USER_USER_TC(n) (0x12 + (n))
+#define SAMD21_EVSYS_USER_USER_ADC_START (0x17)
+#define SAMD21_EVSYS_USER_USER_ADC_SYNC 0x18
+#define SAMD21_EVSYS_USER_USER_AC_COMP0 0x19
+#define SAMD21_EVSYS_USER_USER_AC_COMP1 0x1a
+#define SAMD21_EVSYS_USER_USER_DAC_START 0x1b
+#define SAMD21_EVSYS_USER_USER_PTC_STCONV 0x1c
+#define SAMD21_EVSYS_USER_USER_AC_COMP2 0x1d
+#define SAMD21_EVSYS_USER_USER_AC_COMP3 0x1e
+#define SAMD21_EVSYS_USER_USER_TCC3_EV(n) (0x1f + (n))
+#define SAMD21_EVSYS_USER_USER_TCC3_MC(n) (0x21 + (n))
+
+#define SAMD21_EVSYS_USER_CHANNEL 8
+#define SAMD21_EVSYS_USER_CHANNEL_NONE 0
+#define SAMD21_EVSYS_USER_CHANNEL_NUM(n) ((n) + 1)
+
+
+#define SAMD21_EVSYS_CHSTATUS_USRRDY(n) (((n) & 7) | (((n) & 8) << 1))
+#define SAMD21_EVSYS_CHSTATUS_CHBUSY(n) (((n) & 7) | (((n) & 8) << 1) | 8)
+
/* sercom */
struct samd21_sercom {