Looking for some feedback on my work in progress implementation of pad events on AVR ATmega MCUs (not the new Tiny-0/1/2 or Mega-0 parts). Needs cleanup for sure, but I am able to use pad events with this patch! (both callbacks and wait)
Theory of operation:
Pin Change Interrupts on the AVR have a single interrupt vector per supported port. (PCINT0,1,2,etc.) There is a mask register per supported port where you can define which pins for which changes will trigger the interrupt. The hardware DOES NOT keep track of which bits changed, only that some bit on the port changed, so we have to do that ourselves if we care, which also means that if the pin state only lasts a couple of clock cycles we don't actually know what event happened. Either way, I keep a pin state register per port and inside the ISR this is XOR'd with the current sampled pin state to figure out which bits have changed. This is and-ed with the mask register to get the set of changes on enabled pads. The ISR then determines if any of the events should call the corresponding ISR (all the rising/falling edge stuff).
The mcuconf.h defines allow defining which pin change banks are enabled. For every enabled bank, storage for 8 padevent_t structures are needed, and a byte is needed each for pin state, rising edge enables, and falling edge enables (total of 3 bytes).
Most parts only have at most 3 pin change banks (24 events total) but the ATmega644PA and friends have 4, and the ATmega324PB has 5 (40 events total).
Unfortunately neither the PCINTn numbers nor addresses correspond with the locations of the PORTx registers. Different parts have different numbers of pin change interrupts and the mapping of pin change interrupt ids to port letter is not uniform either. I had to add a bunch of part checks to map the PCINTx registers to the IOPORTx registers in ChibiOS. Quite a mess.
I will also be extending this to support the INTx interrupts but the mapping work there is even worse XD.
Add defines such as the following to mcuconf.h:
Code: Select all
#define AVR_GPIO_USE_PCINT0 FALSE
#define AVR_GPIO_USE_PCINT1 FALSE
#define AVR_GPIO_USE_PCINT2 TRUE
#define AVR_GPIO_USE_PCINT3 FALSE
#define AVR_GPIO_USE_PCINT4 FALSE
LLD changes:
Code: Select all
Index: os/hal/ports/AVR/MEGA/LLD/GPIOv1/hal_pal_lld.c
===================================================================
--- os/hal/ports/AVR/MEGA/LLD/GPIOv1/hal_pal_lld.c (revision 17201)
+++ os/hal/ports/AVR/MEGA/LLD/GPIOv1/hal_pal_lld.c (working copy)
@@ -30,11 +30,11 @@
/* Driver exported variables. */
/*==========================================================================*/
-#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE)
+#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__)
/**
- * @brief Event records for the 16 GPIO EXTI channels.
+ * @brief Event records for the GPIO pin change channels.
*/
-palevent_t _pal_events[16];
+palevent_t _pal_events[_pal_event_count()];
#endif
/*==========================================================================*/
@@ -41,14 +41,168 @@
/* Driver local variables and types. */
/*==========================================================================*/
+typedef struct {
+ uint8_t rising_edges;
+ uint8_t falling_edges;
+} avr_gpio_event_config_t;
+
+#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE)
+
+#if defined(IOPORT1_PCMSK) || defined(__DOXYGEN__)
+avr_gpio_event_config_t _event_config_ioport1;
+volatile uint8_t _pin_state_ioport1;
+#endif
+
+#if defined(IOPORT2_PCMSK) || defined(__DOXYGEN__)
+avr_gpio_event_config_t _event_config_ioport2;
+volatile uint8_t _pin_state_ioport2;
+#endif
+
+#if defined(IOPORT3_PCMSK) || defined(__DOXYGEN__)
+avr_gpio_event_config_t _event_config_ioport3;
+volatile uint8_t _pin_state_ioport3;
+#endif
+
+#if defined(IOPORT4_PCMSK) || defined(__DOXYGEN__)
+avr_gpio_event_config_t _event_config_ioport4;
+volatile uint8_t _pin_state_ioport4;
+#endif
+
+#if defined(IOPORT5_PCMSK) || defined(__DOXYGEN__)
+avr_gpio_event_config_t _event_config_ioport5;
+volatile uint8_t _pin_state_ioport5;
+#endif
+
+#if defined(IOPORT10_PCMSK) || defined(__DOXYGEN__)
+avr_gpio_event_config_t _event_config_ioport10;
+volatile uint8_t _pin_state_ioport10;
+#endif
+
+#if defined(IOPORT11_PCMSK) || defined(__DOXYGEN__)
+avr_gpio_event_config_t _event_config_ioport11;
+volatile uint8_t _pin_state_ioport11;
+#endif
+
+#endif /* PAL_USE_WAIT || PAL_USE_CALLBACKS */
+
/*==========================================================================*/
/* Driver local functions. */
/*==========================================================================*/
+volatile uint8_t* _port_pcmsk(ioportid_t port) {
+#if defined(IOPORT1_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT1) {
+ return &IOPORT1_PCMSK;
+ }
+#endif
+#if defined(IOPORT2_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT2) {
+ return &IOPORT2_PCMSK;
+ }
+#endif
+#if defined(IOPORT3_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT3) {
+ return &IOPORT3_PCMSK;
+ }
+#endif
+#if defined(IOPORT4_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT4) {
+ return &IOPORT4_PCMSK;
+ }
+#endif
+#if defined(IOPORT5_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT5) {
+ return &IOPORT5_PCMSK;
+ }
+#endif
+#if defined(IOPORT10_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT10) {
+ return &IOPORT10_PCMSK;
+ }
+#endif
+#if defined(IOPORT11_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT11) {
+ return &IOPORT11_PCMSK;
+ }
+#endif
+ return NULL;
+}
+
/*==========================================================================*/
/* Driver interrupt handlers. */
/*==========================================================================*/
+#define _pcint_isr_code(n) \
+ do { \
+ const uint8_t pins = palReadPort(IOPORT##n); \
+ const uint8_t changed = IOPORT##n##_PCMSK & (pins ^ _pin_state_ioport##n); \
+ const uint8_t rising = _event_config_ioport##n.rising_edges & changed & pins; \
+ const uint8_t falling = _event_config_ioport##n.falling_edges & changed & ~pins; \
+ uint8_t events = rising | falling; \
+ for (uint8_t i = 0; events != 0; i++, events >>= 1) { \
+ if (events & 1) { \
+ _pal_isr_code(_IOPORT##n##_EVENT_OFFSET + i); \
+ } \
+ } \
+ _pin_state_ioport##n = pins; \
+ } while (0)
+
+#if defined(IOPORT1_PCMSK) || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(IOPORT1_PCINT_vect) {
+ OSAL_IRQ_PROLOGUE();
+ _pcint_isr_code(1);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(IOPORT2_PCMSK) || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(IOPORT2_PCINT_vect) {
+ OSAL_IRQ_PROLOGUE();
+ _pcint_isr_code(2);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(IOPORT3_PCMSK) || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(IOPORT3_PCINT_vect) {
+ OSAL_IRQ_PROLOGUE();
+ _pcint_isr_code(3);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(IOPORT4_PCMSK) || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(IOPORT4_PCINT_vect) {
+ OSAL_IRQ_PROLOGUE();
+ _pcint_isr_code(4);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(IOPORT5_PCMSK) || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(IOPORT5_PCINT_vect) {
+ OSAL_IRQ_PROLOGUE();
+ _pcint_isr_code(5);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(IOPORT10_PCMSK) || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(IOPORT10_PCINT_vect) {
+ OSAL_IRQ_PROLOGUE();
+ _pcint_isr_code(10);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(IOPORT11_PCMSK) || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(IOPORT11_PCINT_vect) {
+ OSAL_IRQ_PROLOGUE();
+ _pcint_isr_code(11);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
/*==========================================================================*/
/* Driver exported functions. */
/*==========================================================================*/
@@ -63,6 +217,14 @@
*/
void _pal_lld_init(const PALConfig *config) {
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
+ unsigned i;
+
+ for (i = 0; i < _pal_event_count(); i++) {
+ _pal_init_event(i);
+ }
+#endif
+
#if defined(PORTA) || defined(__DOXYGEN__)
PORTA = config->porta.out;
DDRA = config->porta.dir;
@@ -117,6 +279,57 @@
PORTL = config->portl.out;
DDRL = config->portl.dir;
#endif
+
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
+ #if defined(IOPORT1_PCMSK) || defined(__DOXYGEN__)
+ _event_config_ioport1.rising_edges = 0;
+ _event_config_ioport1.falling_edges = 0;
+ _pin_state_ioport1 = IOPORT1->in;
+ PCICR |= (1U << IOPORT1_PCIE);
+ #endif
+
+ #if defined(IOPORT2_PCMSK) || defined(__DOXYGEN__)
+ _event_config_ioport2.rising_edges = 0;
+ _event_config_ioport2.falling_edges = 0;
+ _pin_state_ioport2 = IOPORT2->in;
+ PCICR |= (1U << IOPORT2_PCIE);
+ #endif
+
+ #if defined(IOPORT3_PCMSK) || defined(__DOXYGEN__)
+ _event_config_ioport3.rising_edges = 0;
+ _event_config_ioport3.falling_edges = 0;
+ _pin_state_ioport3 = IOPORT3->in;
+ PCICR |= (1U << IOPORT3_PCIE);
+ #endif
+
+ #if defined(IOPORT4_PCMSK) || defined(__DOXYGEN__)
+ _event_config_ioport4.rising_edges = 0;
+ _event_config_ioport4.falling_edges = 0;
+ _pin_state_ioport4 = IOPORT4->in;
+ PCICR |= (1U << IOPORT4_PCIE);
+ #endif
+
+ #if defined(IOPORT5_PCMSK) || defined(__DOXYGEN__)
+ _event_config_ioport5.rising_edges = 0;
+ _event_config_ioport5.falling_edges = 0;
+ _pin_state_ioport5 = IOPORT5->in;
+ PCICR |= (1U << IOPORT5_PCIE);
+ #endif
+
+ #if defined(IOPORT10_PCMSK) || defined(__DOXYGEN__)
+ _event_config_ioport10.rising_edges = 0;
+ _event_config_ioport10.falling_edges = 0;
+ _pin_state_ioport10 = IOPORT10->in;
+ PCICR |= (1U << IOPORT10_PCIE);
+ #endif
+
+ #if defined(IOPORT11_PCMSK) || defined(__DOXYGEN__)
+ _event_config_ioport11.rising_edges = 0;
+ _event_config_ioport11.falling_edges = 0;
+ _pin_state_ioport11 = IOPORT11->in;
+ PCICR |= (1U << IOPORT11_PCIE);
+ #endif
+#endif
}
/**
@@ -158,6 +371,7 @@
}
}
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Pad event enable.
* @details This function programs an event callback in the specified mode.
@@ -173,19 +387,134 @@
*/
void _pal_lld_enablepadevent(ioportid_t port,
iopadid_t pad,
- ioeventmode_t mode,
- palcallback_t callback,
- void *arg) {
- (void)port;
- (void)pad;
- (void)mode;
- (void)callback;
- (void)arg;
+ ioeventmode_t mode) {
+ const uint8_t padmask = (1U << pad);
+ const uint8_t rising_edges = (mode & PAL_EVENT_MODE_RISING_EDGE) ? padmask : 0;
+ const uint8_t falling_edges = (mode & PAL_EVENT_MODE_FALLING_EDGE) ? padmask : 0;
- /* TODO: Implement the interruption here. */
+ #define _enablepadevent_code(n) \
+ do { \
+ _event_config_ioport##n.rising_edges = \
+ (_event_config_ioport##n.rising_edges & padmask) | rising_edges; \
+ _event_config_ioport##n.falling_edges = \
+ (_event_config_ioport##n.falling_edges & padmask) | falling_edges; \
+ _pin_state_ioport##n = (_pin_state_ioport##n & padmask) | (IOPORT##n->in & padmask); \
+ IOPORT##n##_PCMSK |= padmask; \
+ } while (0)
+
+#if defined(IOPORT1_PCMSK) || defined(__DOXYGEN__)
+ _enablepadevent_code(1);
+#endif
+
+ #if defined(IOPORT2_PCMSK) || defined(__DOXYGEN__)
+ _enablepadevent_code(2);
+ #endif
+
+ #if defined(IOPORT3_PCMSK) || defined(__DOXYGEN__)
+ _enablepadevent_code(3);
+ #endif
+
+ #if defined(IOPORT4_PCMSK) || defined(__DOXYGEN__)
+ _enablepadevent_code(4);
+ #endif
+
+ #if defined(IOPORT5_PCMSK) || defined(__DOXYGEN__)
+ _enablepadevent_code(5);
+ #endif
+
+ #if defined(IOPORT10_PCMSK) || defined(__DOXYGEN__)
+ _enablepadevent_code(10);
+ #endif
+
+ #if defined(IOPORT11_PCMSK) || defined(__DOXYGEN__)
+ _enablepadevent_code(11);
+ #endif
}
/**
+ * @brief Pad event disable.
+ * @details This function disables previously programmed event callbacks.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad) {
+ volatile uint8_t* pcmsk = _port_pcmsk(port);
+ if (pcmsk) {
+ *pcmsk &= ~(1U << pad);
+ }
+}
+
+/**
+ * @brief Returns a PAL event structure associated to a pad.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+palevent_t* _pal_lld_get_pad_event(ioportid_t port, iopadid_t pad) {
+#if defined(IOPORT1_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT1) {
+ return &_pal_events[_IOPORT1_EVENT_OFFSET + pad];
+ }
+#endif
+#if defined(IOPORT2_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT2) {
+ return &_pal_events[_IOPORT2_EVENT_OFFSET + pad];
+ }
+#endif
+#if defined(IOPORT3_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT3) {
+ return &_pal_events[_IOPORT3_EVENT_OFFSET + pad];
+ }
+#endif
+#if defined(IOPORT4_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT4) {
+ return &_pal_events[_IOPORT4_EVENT_OFFSET + pad];
+ }
+#endif
+#if defined(IOPORT5_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT5) {
+ return &_pal_events[_IOPORT5_EVENT_OFFSET + pad];
+ }
+#endif
+#if defined(IOPORT10_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT10) {
+ return &_pal_events[_IOPORT10_EVENT_OFFSET + pad];
+ }
+#endif
+#if defined(IOPORT11_PCMSK) || defined(__DOXYGEN__)
+ if (port == IOPORT11) {
+ return &_pal_events[_IOPORT11_EVENT_OFFSET + pad];
+ }
+#endif
+ return NULL;
+}
+
+/**
+ * @brief Pad event enable check.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @return Pad event status.
+ * @retval false if the pad event is disabled.
+ * @retval true if the pad event is enabled.
+ *
+ * @notapi
+ */
+bool pal_lld_ispadeventenabled(ioportid_t port, iopadid_t pad) {
+ volatile uint8_t* pcmsk = _port_pcmsk(port);
+ if (pcmsk) {
+ return (*pcmsk & (1U << pad)) != 0U;
+ }
+ return false;
+}
+#endif /* PAL_USE_CALLBACKS || PAL_USE_WAIT */
+
+/**
* @brief Make a line identifier with a given port and pad identifiers.
*
* @param[in] port the port identifier
Code: Select all
Index: os/hal/ports/AVR/MEGA/LLD/GPIOv1/hal_pal_lld.h
===================================================================
--- os/hal/ports/AVR/MEGA/LLD/GPIOv1/hal_pal_lld.h (revision 17201)
+++ os/hal/ports/AVR/MEGA/LLD/GPIOv1/hal_pal_lld.h (working copy)
@@ -274,6 +274,212 @@
#define IOPORTSPI1 ((volatile avr_gpio_registers_t *)&PIN_SPI1)
#endif
+
+/* PCMSK0 mappings */
+#if AVR_GPIO_USE_PCINT0
+
+ /* PCMSK0 -> PORTA (IOPORT1) */
+ #if defined(__AVR_ATmega164__) || defined(__AVR_ATmega164P__) || defined(__AVR_ATmega164A__) || defined(__AVR_ATmega164PA__) || \
+ defined(__AVR_ATmega324__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__) || \
+ defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644PA__) || \
+ defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || \
+ defined(__AVR_ATmega162__)
+
+ #define IOPORT1_PCMSK PCMSK0 /* PCMSK0 -> PORTA */
+ #define IOPORT1_PCIE 0 /* PCIE0 */
+ #define IOPORT1_PCINT_vect PCINT0_vect /* Interrupt vector */
+
+ /* PCMSK0 -> PORTB (IOPORT2) */
+ #elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || \
+ defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || \
+ defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || \
+ defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || \
+ defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || \
+ defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || \
+ defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) || \
+ defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)
+
+ #define IOPORT2_PCMSK PCMSK0 /* PCMSK0 -> PORTB */
+ #define IOPORT2_PCIE 0 /* PCIE0 */
+ #define IOPORT2_PCINT_vect PCINT0_vect /* Interrupt vector */
+
+ /* PCMSK0 -> PORTE (IOPORT5) */
+ #elif defined(__AVR_ATmega169__) || defined(__AVR_ATmega169P__) || \
+ defined(__AVR_ATmega329__) || defined(__AVR_ATmega329P__) || \
+ defined(__AVR_ATmega649__) || defined(__AVR_ATmega649P__) || \
+ defined(__AVR_ATmega3290__) || defined(__AVR_ATmega3290P__) || \
+ defined(__AVR_ATmega6490__) || defined(__AVR_ATmega6490P__)
+
+ #define IOPORT5_PCMSK PCMSK0 /* PCMSK0 -> PORTE */
+ #define IOPORT5_PCIE 0 /* PCIE0 */
+ #define IOPORT5_PCINT_vect PCINT0_vect /* Interrupt vector */
+
+ #else
+ #error "PCMSK0 (AVR_GPIO_USE_PCINT0) is not supported on this ATmega device"
+ #endif
+#endif /* AVR_GPIO_USE_PCINT0 */
+
+/* PCMSK1 mappings */
+#if AVR_GPIO_USE_PCINT1
+
+ /* PCMSK1 -> PORTB (IOPORT2) */
+ #if defined(__AVR_ATmega164__) || defined(__AVR_ATmega164P__) || defined(__AVR_ATmega164A__) || defined(__AVR_ATmega164PA__) || \
+ defined(__AVR_ATmega324__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__) || \
+ defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644PA__) || \
+ defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || \
+ defined(__AVR_ATmega162__) || \
+ defined(__AVR_ATmega169__) || defined(__AVR_ATmega169P__) || \
+ defined(__AVR_ATmega329__) || defined(__AVR_ATmega329P__) || \
+ defined(__AVR_ATmega649__) || defined(__AVR_ATmega649P__) || \
+ defined(__AVR_ATmega3290__) || defined(__AVR_ATmega3290P__) || \
+ defined(__AVR_ATmega6490__) || defined(__AVR_ATmega6490P__)
+
+ #define IOPORT2_PCMSK PCMSK1 /* PCMSK1 -> PORTB */
+ #define IOPORT2_PCIE 1 /* PCIE1 */
+ #define IOPORT2_PCINT_vect PCINT1_vect /* Interrupt vector */
+
+ /* PCMSK1 -> PORTC (IOPORT3) */
+ #elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || \
+ defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || \
+ defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || \
+ defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || \
+ defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)
+
+ #define IOPORT3_PCMSK PCMSK1 /* PCMSK1 -> PORTC */
+ #define IOPORT3_PCIE 1 /* PCIE1 */
+ #define IOPORT3_PCINT_vect PCINT1_vect /* Interrupt vector */
+
+ /* PCMSK1 -> PORTJ (IOPORT10) */
+ #elif defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+
+ #define IOPORT10_PCMSK PCMSK1 /* PCMSK1 -> PORTJ */
+ #define IOPORT10_PCIE 1 /* PCIE1 */
+ #define IOPORT10_PCINT_vect PCINT1_vect /* Interrupt vector */
+
+ #else
+ #error "PCMSK1 (AVR_GPIO_USE_PCINT1) is not supported on this ATmega device"
+ #endif
+#endif /* AVR_GPIO_USE_PCINT1 */
+
+/* PCMSK2 mappings */
+#if AVR_GPIO_USE_PCINT2
+
+ /* PCMSK2 -> PORTC (IOPORT3) */
+ #if defined(__AVR_ATmega324__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__) || \
+ defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644PA__) || \
+ defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
+
+ #define IOPORT3_PCMSK PCMSK2 /* PCMSK2 -> PORTC */
+ #define IOPORT3_PCIE 2 /* PCIE2 */
+ #define IOPORT3_PCINT_vect PCINT2_vect /* Interrupt vector */
+
+ /* PCMSK2 -> PORTD (IOPORT4) */
+ #elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || \
+ defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || \
+ defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || \
+ defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__)
+
+ #define IOPORT4_PCMSK PCMSK2 /* PCMSK2 -> PORTD */
+ #define IOPORT4_PCIE 2 /* PCIE2 */
+ #define IOPORT4_PCINT_vect PCINT2_vect /* Interrupt vector */
+
+ /* PCMSK2 -> PORTK (IOPORT11) */
+ #elif defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+
+ #define IOPORT11_PCMSK PCMSK2 /* PCMSK2 -> PORTK */
+ #define IOPORT11_PCIE 2 /* PCIE2 */
+ #define IOPORT11_PCINT_vect PCINT2_vect /* Interrupt vector */
+
+ #else
+ #error "PCMSK2 (AVR_GPIO_USE_PCINT2) is not supported on this ATmega device"
+ #endif
+
+#endif /* AVR_GPIO_USE_PCINT2 */
+
+/* PCMSK3 mappings */
+#if AVR_GPIO_USE_PCINT3
+
+ /* PCMSK3 -> PORTD (IOPORT4) */
+ #if defined(__AVR_ATmega164__) || defined(__AVR_ATmega164P__) || defined(__AVR_ATmega164A__) || defined(__AVR_ATmega164PA__) || \
+ defined(__AVR_ATmega324__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__) || \
+ defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644PA__) || \
+ defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
+
+ #define IOPORT4_PCMSK PCMSK3 /* PCMSK3 -> PORTD */
+ #define IOPORT4_PCIE 3 /* PCIE3 */
+ #define IOPORT4_PCINT_vect PCINT3_vect /* Interrupt vector */
+
+ #else
+ #error "PCMSK3 (AVR_GPIO_USE_PCINT3) is not supported on this ATmega device"
+ #endif
+#endif /* AVR_GPIO_USE_PCINT3 */
+
+/* PCMSK4 mappings */
+#if AVR_GPIO_USE_PCINT4
+
+ /* PCMSK4 -> PORTE (IOPORT5) - ATmega324PB only */
+ #if defined(__AVR_ATmega324PB__)
+
+ #define IOPORT5_PCMSK PCMSK4 /* PCMSK4 -> PORTE */
+ #define IOPORT5_PCIE 4 /* PCIE4 */
+ #define IOPORT5_PCINT_vect PCINT4_vect /* Interrupt vector */
+
+ #else
+ #error "PCMSK4 (AVR_GPIO_USE_PCINT4) is only supported on ATmega324PB"
+ #endif
+#endif /* AVR_GPIO_USE_PCINT4 */
+
+#if defined(IOPORT1_PCMSK) || defined(__DOXYGEN__)
+ #define _IOPORT1_EVENT_COUNT (8)
+#else
+ #define _IOPORT1_EVENT_COUNT (0)
+#endif
+#define _IOPORT1_EVENT_OFFSET (0)
+
+#if defined(IOPORT2_PCMSK) || defined(__DOXYGEN__)
+ #define _IOPORT2_EVENT_COUNT (8)
+#else
+ #define _IOPORT2_EVENT_COUNT (0)
+#endif
+#define _IOPORT2_EVENT_OFFSET (_IOPORT1_EVENT_OFFSET + _IOPORT1_EVENT_COUNT)
+
+#if defined(IOPORT3_PCMSK) || defined(__DOXYGEN__)
+ #define _IOPORT3_EVENT_COUNT (8)
+#else
+ #define _IOPORT3_EVENT_COUNT (0)
+#endif
+#define _IOPORT3_EVENT_OFFSET (_IOPORT2_EVENT_OFFSET + _IOPORT2_EVENT_COUNT)
+
+#if defined(IOPORT4_PCMSK) || defined(__DOXYGEN__)
+ #define _IOPORT4_EVENT_COUNT (8)
+#else
+ #define _IOPORT4_EVENT_COUNT (0)
+#endif
+#define _IOPORT4_EVENT_OFFSET (_IOPORT3_EVENT_OFFSET + _IOPORT3_EVENT_COUNT)
+
+#if defined(IOPORT5_PCMSK) || defined(__DOXYGEN__)
+ #define _IOPORT5_EVENT_COUNT (8)
+#else
+ #define _IOPORT5_EVENT_COUNT (0)
+#endif
+#define _IOPORT5_EVENT_OFFSET (_IOPORT4_EVENT_OFFSET + _IOPORT4_EVENT_COUNT)
+
+#if defined(IOPORT10_PCMSK) || defined(__DOXYGEN__)
+ #define _IOPORT10_EVENT_COUNT (8)
+#else
+ #define _IOPORT10_EVENT_COUNT (0)
+#endif
+#define _IOPORT10_EVENT_OFFSET (_IOPORT5_EVENT_OFFSET + _IOPORT5_EVENT_COUNT)
+
+#if defined(IOPORT11_PCMSK) || defined(__DOXYGEN__)
+ #define _IOPORT11_EVENT_COUNT (8)
+#else
+ #define _IOPORT11_EVENT_COUNT (0)
+#endif
+#define _IOPORT11_EVENT_OFFSET (_IOPORT10_EVENT_OFFSET + _IOPORT10_EVENT_COUNT)
+
+#define _pal_event_count() (_IOPORT11_EVENT_OFFSET + _IOPORT11_EVENT_COUNT)
+
/*==========================================================================*/
/* Implementation, some of the following macros could be implemented as */
/* Functions, if so please put them in hal_pal_lld.c. */
@@ -360,19 +566,16 @@
/**
* @brief Pad event enable.
- * @details This function programs an event callback in the specified mode.
* @note Programming an unknown or unsupported mode is silently ignored.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @param[in] mode pad event mode
- * @param[in] callback event callback function
- * @param[in] arg callback argument
*
* @notapi
*/
-#define pal_lld_enablepadevent(port, pad, mode, callback, arg) \
- _pal_lld_enablepadevent(port, pad, mode, callback, arg)
+#define pal_lld_enablepadevent(port, pad, mode) \
+ _pal_lld_enablepadevent(port, pad, mode)
/**
* @brief Pad event disable.
@@ -395,7 +598,7 @@
* @notapi
*/
#define pal_lld_get_pad_event(port, pad) \
- &_pal_events[pad]; (void)(port)
+ _pal_lld_get_pad_event(port, pad)
/**
* @brief Returns a PAL event structure associated to a line.
@@ -405,12 +608,25 @@
* @notapi
*/
#define pal_lld_get_line_event(line) \
- &_pal_events[PAL_PAD(line)]
+ _pal_lld_get_pad_event(PAL_PORT(line), PAL_PAD(line))
+/**
+ * @brief Pad event enable check.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @return Pad event status.
+ * @retval false if the pad event is disabled.
+ * @retval true if the pad event is enabled.
+ *
+ * @notapi
+ */
+#define pal_lld_ispadeventenabled(port, pad) \
+ _pal_lld_ispadeventenabled(port, pad)
+
#if !defined(__DOXYGEN__)
-extern const PALConfig pal_default_config;
#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE)
-extern palevent_t _pal_events[16];
+extern palevent_t _pal_events[_pal_event_count()];
#endif
#endif
@@ -423,13 +639,12 @@
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode);
-
void _pal_lld_enablepadevent(ioportid_t port,
iopadid_t pad,
- ioeventmode_t mode,
- palcallback_t callback,
- void *arg);
+ ioeventmode_t mode);
void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad);
+ palevent_t* _pal_lld_get_pad_event(ioportid_t port, iopadid_t line);
+ bool _pal_lld_ispadeventenabled(ioportid_t port, iopadid_t line);
ioline_t _pal_lld_setlineid(ioportid_t port, uint8_t pad);
ioportid_t _pal_lld_getportfromline(ioline_t line);
Wait test app:
Code: Select all
#include "ch.h"
#include "hal.h"
#define LINE_EXT_BUTTON PAL_LINE(IOPORT4, 2U)
int main(void) {
halInit();
chSysInit();
palSetLineMode(LINE_LED1, PAL_MODE_OUTPUT_PUSHPULL);
palClearLine(LINE_LED1);
palSetLineMode(LINE_EXT_BUTTON, PAL_MODE_INPUT_PULLUP);
palEnableLineEvent(LINE_EXT_BUTTON, PAL_EVENT_MODE_FALLING_EDGE);
/* main() thread loop. */
while (true) {
palWaitLineTimeout(LINE_EXT_BUTTON, TIME_INFINITE);
palToggleLine(LINE_LED1);
chThdSleepMilliseconds(250);
}
}
