From: Keith Packard Date: Tue, 8 Nov 2022 06:22:26 +0000 (-0800) Subject: samd21: Wire up pin interrupts X-Git-Tag: 1.9.13~1^2~26^2~31 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=13f0b70a6346c9cfe04e5c494d3f34aa92e0db8b samd21: Wire up pin interrupts Uses the external interrupt controller. Careful about pin mapping. Signed-off-by: Keith Packard --- diff --git a/src/samd21/ao_exti.h b/src/samd21/ao_exti.h index 43cfcb2d..1bd14a03 100644 --- a/src/samd21/ao_exti.h +++ b/src/samd21/ao_exti.h @@ -19,8 +19,8 @@ #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 diff --git a/src/samd21/ao_exti_samd21.c b/src/samd21/ao_exti_samd21.c index aa865cc2..96219783 100644 --- a/src/samd21/ao_exti_samd21.c +++ b/src/samd21/ao_exti_samd21.c @@ -19,145 +19,151 @@ #include #include -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); } diff --git a/src/samd21/samd21.h b/src/samd21/samd21.h index 331fb723..4a18e757 100644 --- a/src/samd21/samd21.h +++ b/src/samd21/samd21.h @@ -567,6 +567,55 @@ struct samd21_dmac_desc { #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; @@ -1395,6 +1444,97 @@ extern struct samd21_evsys samd21_evsys; #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 {