samd21: Wire up pin interrupts
authorKeith Packard <keithp@keithp.com>
Tue, 8 Nov 2022 06:22:26 +0000 (22:22 -0800)
committerKeith Packard <keithp@keithp.com>
Tue, 8 Nov 2022 06:22:26 +0000 (22:22 -0800)
Uses the external interrupt controller. Careful about pin mapping.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/samd21/ao_exti.h
src/samd21/ao_exti_samd21.c
src/samd21/samd21.h

index 43cfcb2d1d09bd12b9c3b537035554ebf5b40f68..1bd14a037d0a16e9433df7abf21907bdb45f6e7c 100644 (file)
@@ -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
index aa865cc2d2aef6103466ab3a019f54fb05a3ddac..962197837713975d0950d9e7db048fe0ae0f5050 100644 (file)
 #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);
 }
index 331fb7233ba4e17de39db6be7379f3dac904d174..4a18e757d986d73a2ee4c43891f2803448e3cb17 100644 (file)
@@ -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 {