aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/ports/AVR
diff options
context:
space:
mode:
authorFabio Utzig <utzig@utzig.org>2017-04-02 22:27:45 +0000
committerFabio Utzig <utzig@utzig.org>2017-04-02 22:27:45 +0000
commitaca6f940196200789413a825e2157d4abf6d4676 (patch)
tree90edeb198453bec6b565f87d9d5de360dd310cfe /os/hal/ports/AVR
parent2000bff59bdde16770dd6d4274e44a2387de979e (diff)
downloadChibiOS-aca6f940196200789413a825e2157d4abf6d4676.tar.gz
ChibiOS-aca6f940196200789413a825e2157d4abf6d4676.tar.bz2
ChibiOS-aca6f940196200789413a825e2157d4abf6d4676.zip
[AVR] PCINTx support for EXT
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10138 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal/ports/AVR')
-rw-r--r--os/hal/ports/AVR/avr_pins.h65
-rw-r--r--os/hal/ports/AVR/hal_ext_lld.c684
-rw-r--r--os/hal/ports/AVR/hal_ext_lld.h457
3 files changed, 923 insertions, 283 deletions
diff --git a/os/hal/ports/AVR/avr_pins.h b/os/hal/ports/AVR/avr_pins.h
index b89325aff..bcd5a10e2 100644
--- a/os/hal/ports/AVR/avr_pins.h
+++ b/os/hal/ports/AVR/avr_pins.h
@@ -91,4 +91,69 @@
#endif /* AVR_ADC_USE_ADC1 */
+#if AVR_EXT_USE_PCINT0
+#if defined(__AVR_ATmega162__)
+ #define PCINT0_PIN PINA
+#elif defined(__AVR_ATmega328P__) || \
+ defined(__AVR_ATmega1280__) || \
+ defined(__AVR_ATmega2560__)
+ #define PCINT0_PIN PINB
+#else
+ #warning "Device not supported by EXT driver"
+#endif
+#endif /* AVR_EXT_USE_PCINT0 */
+
+#if AVR_EXT_USE_PCINT1
+#if defined(__AVR_ATmega162__) || \
+ defined(__AVR_ATmega328P__)
+ #define PCINT1_PIN PINC
+#elif defined(__AVR_ATmega1280__) || \
+ defined(__AVR_ATmega2560__)
+ #define PCINT1_PIN PINE
+#else
+ #warning "Device not supported by EXT driver"
+#endif
+#endif /* AVR_EXT_USE_PCINT1 */
+
+#if AVR_EXT_USE_PCINT2
+#if defined(__AVR_ATmega1280__) || \
+ defined(__AVR_ATmega2560__)
+ #define PCINT2_PIN PINK
+#else
+ #warning "Device not supported by EXT driver"
+#endif
+#endif /* AVR_EXT_USE_PCINT2 */
+
+#if AVR_EXT_USE_PCINT3
+#warning "Device not supported by EXT driver"
+#endif /* AVR_EXT_USE_PCINT3 */
+
+#if AVR_EXT_USE_PCINT4
+#warning "Device not supported by EXT driver"
+#endif /* AVR_EXT_USE_PCINT4 */
+
+#if AVR_EXT_USE_PCINT5
+#warning "Device not supported by EXT driver"
+#endif /* AVR_EXT_USE_PCINT5 */
+
+#if AVR_EXT_USE_PCINT6
+#warning "Device not supported by EXT driver"
+#endif /* AVR_EXT_USE_PCINT6 */
+
+#if AVR_EXT_USE_PCINT7
+#warning "Device not supported by EXT driver"
+#endif /* AVR_EXT_USE_PCINT7 */
+
+#if AVR_EXT_USE_PCINT8
+#warning "Device not supported by EXT driver"
+#endif /* AVR_EXT_USE_PCINT8 */
+
+#if AVR_EXT_USE_PCINT9
+#warning "Device not supported by EXT driver"
+#endif /* AVR_EXT_USE_PCINT9 */
+
+#if AVR_EXT_USE_PCINT10
+#warning "Device not supported by EXT driver"
+#endif /* AVR_EXT_USE_PCINT10 */
+
#endif /* _AVR_PINS_H_ */
diff --git a/os/hal/ports/AVR/hal_ext_lld.c b/os/hal/ports/AVR/hal_ext_lld.c
index 225bd7e15..6eccf924a 100644
--- a/os/hal/ports/AVR/hal_ext_lld.c
+++ b/os/hal/ports/AVR/hal_ext_lld.c
@@ -1,5 +1,7 @@
/*
- ChibiOS - Copyright (C) 2016 Theodore Ateba
+ EXT Low Level Driver for ChibiOS
+ Copyright (C) 2015 Igor Stoppa <igor.stoppa@gmail.com>
+ Copyright (C) 2016 Theodore Ateba
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,8 +17,8 @@
*/
/**
- * @file hal_ext_lld.c
- * @brief AVR EXT subsystem low level driver source.
+ * @file AVR/hal_ext_lld.c
+ * @brief AVR EXT subsystem low level driver source.
*
* @addtogroup EXT
* @{
@@ -30,12 +32,69 @@
/* Driver local definitions. */
/*===========================================================================*/
+#define EXT_EICRA_LOW_LEVEL 0
+#define EXT_EICRA_BOTH_EDGES 1
+#define EXT_EICRA_FALLING_EDGE 2
+#define EXT_EICRA_RISING_EDGE 3
+
+/**
+ * @brief Declares the isr for the ext channel specified
+ *
+ * @param[in] channel number of the channel
+ *
+ * @notapi
+ */
+#define declare_extint_isr(channel) \
+OSAL_IRQ_HANDLER(INT##channel##_vect) \
+{ \
+ OSAL_IRQ_PROLOGUE(); \
+ EXTD1.config->channels[EXT_INT##channel##_CHANNEL]. \
+ cb(&EXTD1, EXT_INT##channel##_CHANNEL); \
+ OSAL_IRQ_EPILOGUE(); \
+}
+
+/**
+ * @brief Declares the isr for the pc channel specified
+ *
+ * @param[in] port number of the port
+ *
+ * @notapi
+ */
+#define declare_pcint_isr(index) \
+OSAL_IRQ_HANDLER(PCINT##index##_vect) { \
+ uint8_t changed_pins; \
+ uint8_t i; \
+ \
+ OSAL_IRQ_PROLOGUE(); \
+ EXTD1.pc_current_values[index] = (*(PINS[index])) & (*(PCMSK[index])); \
+ \
+ /* XOR to find the changed pin(s) */ \
+ changed_pins = EXTD1.pc_current_values[index] ^ EXTD1.pc_old_values[index];\
+ \
+ for (i = 0; i < 8; i++) { \
+ if (changed_pins & (1 << i)) { \
+ const EXTChannelConfig *chn = \
+ &EXTD1.config->channels[EXT_PCINT##index##_INDEX + i]; \
+ \
+ if (((chn->mode & EXT_CH_MODE_RISING_EDGE) && \
+ ((EXTD1.pc_current_values[index] & (1 << i)) > 0)) || \
+ ((chn->mode & EXT_CH_MODE_FALLING_EDGE) && \
+ ((EXTD1.pc_current_values[index] & (1 << i)) == 0))) { \
+ chn->cb(&EXTD1, EXT_PCINT##index##_INDEX + i - EXT_PCINT_MIN_INDEX); \
+ } \
+ } \
+ } \
+ \
+ EXTD1.pc_old_values[index] = EXTD1.pc_current_values[index]; \
+ OSAL_IRQ_EPILOGUE(); \
+}
+
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
- * @brief EXTD1 driver identifier.
+ * @brief EXT1 driver identifier.
*/
EXTDriver EXTD1;
@@ -43,305 +102,313 @@ EXTDriver EXTD1;
/* Driver local variables and types. */
/*===========================================================================*/
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
+#if EXT_PC_NUM_PORTS > 0
+/**
+ * @brief Vector with addresses of Ports available.
+ */
+volatile uint8_t * const PINS[EXT_PC_NUM_PORTS] = {
+#if AVR_EXT_USE_PCINT0
+ (volatile uint8_t *const)&PCINT0_PIN,
+#endif
+#if AVR_EXT_USE_PCINT1
+ (volatile uint8_t *const)&PCINT1_PIN,
+#endif
+#if AVR_EXT_USE_PCINT2
+(volatile uint8_t *const)&PCINT2_PIN,
+#endif
+#if AVR_EXT_USE_PCINT3
+(volatile uint8_t *const)&PCINT3_PIN,
+#endif
+#if AVR_EXT_USE_PCINT4
+(volatile uint8_t *const)&PCINT4_PIN,
+#endif
+#if AVR_EXT_USE_PCINT5
+(volatile uint8_t *const)&PCINT5_PIN,
+#endif
+#if AVR_EXT_USE_PCINT6
+(volatile uint8_t *const)&PCINT6_PIN,
+#endif
+#if AVR_EXT_USE_PCINT7
+(volatile uint8_t *const)&PCINT7_PIN,
+#endif
+#if AVR_EXT_USE_PCINT8
+(volatile uint8_t *const)&PCINT8_PIN,
+#endif
+#if AVR_EXT_USE_PCINT9
+(volatile uint8_t *const)&PCINT9_PIN,
+#endif
+#if AVR_EXT_USE_PCINT10
+(volatile uint8_t *const)&PCINT10_PIN,
+#endif
+};
/**
- * @brief Set the INTx interrupt trigger front or state.
- *
- * @param[in] channel the channel to configure
- * @param[in] edge the front or state to configure
+ * @brief Vector with addresses of Port Masks available.
*/
-void ext_lld_set_intx_edges(expchannel_t channel, uint8_t edge) {
-#if AVR_EXT_USE_INT0 || defined(__DOXYGEN__)
- if (channel == INT0) {
- if (edge == EXT_CH_MODE_RISING_EDGE) {
- EICRA |= (1 << 0);
- EICRA |= (1 << 1);
- }
- else if (edge == EXT_CH_MODE_FALLING_EDGE) {
- EICRA &= ~(1 << 0);
- EICRA |= (1 << 1);
- }
- else if (edge == EXT_CH_MODE_BOTH_EDGES) {
- EICRA |= (1 << 0);
- EICRA &= ~(1 << 1);
- }
- else if (edge == EXT_CH_MODE_LOW_LEVEL) {
- EICRA &= ~(1 << 0);
- EICRA &= ~(1 << 1);
- }
- }
+volatile uint8_t * const PCMSK[EXT_PC_NUM_PORTS] = {
+#if AVR_EXT_USE_PCINT0
+ (volatile uint8_t *const)&PCMSK0,
#endif
-#if AVR_EXT_USE_INT1 || defined(__DOXYGEN__)
- if (channel == INT1) {
- if (edge == EXT_CH_MODE_RISING_EDGE) {
- EICRA |= (1 << 2);
- EICRA |= (1 << 3);
- }
- else if (edge == EXT_CH_MODE_FALLING_EDGE) {
- EICRA &= ~(1 << 2);
- EICRA |= (1 << 3);
- }
- else if (edge == EXT_CH_MODE_BOTH_EDGES) {
- EICRA |= (1 << 2);
- EICRA &= ~(1 << 3);
- }
- else if (edge == EXT_CH_MODE_LOW_LEVEL) {
- EICRA &= ~(1 << 2);
- EICRA &= ~(1 << 3);
- }
- }
+#if AVR_EXT_USE_PCINT1
+ (volatile uint8_t *const)&PCMSK1,
#endif
-#if AVR_EXT_USE_INT2 || defined(__DOXYGEN__)
- if (channel == INT2) {
- if (edge == EXT_CH_MODE_RISING_EDGE) {
- EICRA |= (1 << 4);
- EICRA |= (1 << 5);
- }
- else if (edge == EXT_CH_MODE_FALLING_EDGE) {
- EICRA &= ~(1 << 4);
- EICRA |= (1 << 5);
- }
- else if (edge == EXT_CH_MODE_BOTH_EDGES) {
- EICRA |= (1 << 4);
- EICRA &= ~(1 << 5);
- }
- else if (edge == EXT_CH_MODE_LOW_LEVEL) {
- EICRA &= ~(1 << 4);
- EICRA &= ~(1 << 5);
- }
- }
+#if AVR_EXT_USE_PCINT2
+ (volatile uint8_t *const)&PCMSK2,
#endif
-#if AVR_EXT_USE_INT3 || defined(__DOXYGEN__)
- if (channel == INT3) {
- if (edge == EXT_CH_MODE_RISING_EDGE) {
- EICRA |= (1 << 6);
- EICRA |= (1 << 7);
- }
- else if (edge == EXT_CH_MODE_FALLING_EDGE) {
- EICRA &= ~(1 << 6);
- EICRA |= (1 << 7);
- }
- else if (edge == EXT_CH_MODE_BOTH_EDGES) {
- EICRA |= (1 << 6);
- EICRA &= ~(1 << 7);
- }
- else if (edge == EXT_CH_MODE_LOW_LEVEL) {
- EICRA &= ~(1 << 6);
- EICRA &= ~(1 << 7);
- }
- }
+#if AVR_EXT_USE_PCINT3
+ (volatile uint8_t *const)&PCMSK3,
#endif
-#if AVR_EXT_USE_INT4 || defined(__DOXYGEN__)
- if (channel == INT4) {
- if (edge == EXT_CH_MODE_RISING_EDGE) {
- EICRB |= (1 << 0);
- EICRB |= (1 << 1);
- }
- else if (edge == EXT_CH_MODE_FALLING_EDGE) {
- EICRB &= ~(1 << 0);
- EICRB |= (1 << 1);
- }
- else if (edge == EXT_CH_MODE_BOTH_EDGES) {
- EICRB |= (1 << 0);
- EICRB &= ~(1 << 1);
- }
- else if (edge == EXT_CH_MODE_LOW_LEVEL) {
- EICRB &= ~(1 << 0);
- EICRB &= ~(1 << 1);
- }
- }
+#if AVR_EXT_USE_PCINT4
+ (volatile uint8_t *const)&PCMSK4,
#endif
-#if AVR_EXT_USE_INT5 || defined(__DOXYGEN__)
- if (channel == INT5) {
- if (edge == EXT_CH_MODE_RISING_EDGE) {
- EICRB |= (1 << 2);
- EICRB |= (1 << 3);
- }
- else if (edge == EXT_CH_MODE_FALLING_EDGE) {
- EICRB &= ~(1 << 2);
- EICRB |= (1 << 3);
- }
- else if (edge == EXT_CH_MODE_BOTH_EDGES) {
- EICRB |= (1 << 2);
- EICRB &= ~(1 << 3);
- }
- else if (edge == EXT_CH_MODE_LOW_LEVEL) {
- EICRB &= ~(1 << 2);
- EICRB &= ~(1 << 3);
- }
- }
+#if AVR_EXT_USE_PCINT5
+ (volatile uint8_t *const)&PCMSK5,
+#endif
+#if AVR_EXT_USE_PCINT6
+ (volatile uint8_t *const)&PCMSK6,
+#endif
+#if AVR_EXT_USE_PCINT7
+ (volatile uint8_t *const)&PCMSK7,
+#endif
+#if AVR_EXT_USE_PCINT8
+ (volatile uint8_t *const)&PCMSK8,
+#endif
+#if AVR_EXT_USE_PCINT9
+ (volatile uint8_t *const)&PCMSK9,
+#endif
+#if AVR_EXT_USE_PCINT10
+ (volatile uint8_t *const)&PCMSK10,
+#endif
+};
#endif
-}
/*===========================================================================*/
-/* Driver interrupt handlers. */
+/* Driver local functions. */
/*===========================================================================*/
-#if AVR_EXT_USE_INT0 || defined(__DOXYGEN__)
+#if EXT_PC_NUM_PORTS > 0
/**
- * @brief EXTI[INT0] interrupt handler.
+ * @brief Configures and activates the Pin Change inputs.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
*
- * @isr
+ * @notapi
*/
-OSAL_IRQ_HANDLER(INT0_vect) {
- OSAL_IRQ_PROLOGUE();
- EXTD1.config->channels[INT0].cb(&EXTD1, INT0);
- OSAL_IRQ_EPILOGUE();
-}
+static void start_pc(EXTDriver *extp) {
+ uint8_t icr = 0;
+ uint8_t i;
+
+ /* For every pin */
+ for (i = 0; i < EXT_PC_NUM_CHANNELS; i++) {
+ uint8_t mode = extp->config->channels[i + EXT_PC_MIN_CHANNEL].mode;
+
+ /* Only start if autostart and not disabled */
+ if ((mode & EXT_CH_MODE_AUTOSTART) && ((mode & EXT_CH_MODE_EDGES_MASK) != EXT_CH_MODE_DISABLED)) {
+ (*(PCMSK[i/8])) |= _BV(i & 0x07);
+ }
+ }
+
+ /* For every port */
+ for (i = 0; i < EXT_PC_NUM_PORTS; i++) {
+ /* Only enable interrupt if at least 1 bit in the mask is set */
+ if ((*(PCMSK[i])) != 0) {
+ /* Enable interrupt */
+ icr |= (_BV(i));
+ }
+ }
+
+ /* Enables/disables the peripheral, as requested. */
+#if defined(__AVR_ATmega162__)
+ GICR &= ~(0x03 << 3);
+ GICR |= (icr << 3);
+#else
+ PCICR = icr;
#endif
+}
-#if AVR_EXT_USE_INT1 || defined(__DOXYGEN__)
/**
- * @brief EXTI[INT1] interrupt handler.
- *
- * @isr
+ * @brief Deactivates the PC interrupts.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
*/
-OSAL_IRQ_HANDLER(INT1_vect) {
- OSAL_IRQ_PROLOGUE();
- EXTD1.config->channels[INT1].cb(&EXTD1, INT1);
- OSAL_IRQ_EPILOGUE();
-}
+static void stop_pc(EXTDriver *extp) {
+ uint8_t i;
+ (void)extp;
+
+ /* Disable pin change interrupts */
+#if defined(__AVR_ATmega162__)
+ GICR &= ~(0x03 << 3);
+#else
+ PCICR = 0;
#endif
-#if AVR_EXT_USE_INT2 || defined(__DOXYGEN__)
-/**
- * @brief EXTI[INT2] interrupt handler.
- *
- * @isr
- */
-OSAL_IRQ_HANDLER(INT2_vect) {
- OSAL_IRQ_PROLOGUE();
- EXTD1.config->channels[INT2].cb(&EXTD1, INT2);
- OSAL_IRQ_EPILOGUE();
+ /* Clear masks */
+ for (i = 0; i < EXT_PC_NUM_PORTS; i++) {
+ (*(PCMSK[i])) = 0;
+ }
}
#endif
-#if AVR_EXT_USE_INT3 || defined(__DOXYGEN__)
+#if EXT_INT_NUM_CHANNELS > 0
/**
- * @brief EXTI[INT3] interrupt handler.
+ * @brief Configures and activates the INT inputs.
*
- * @isr
+ * @param[in] extp pointer to the @p EXTDriver object
+ *
+ * @notapi
*/
-OSAL_IRQ_HANDLER(INT3_vect) {
- OSAL_IRQ_PROLOGUE();
- EXTD1.config->channels[INT3].cb(&EXTD1, INT3);
- OSAL_IRQ_EPILOGUE();
-}
+static void start_ext(EXTDriver *extp) {
+#if EXT_INT_NUM_CHANNELS < 4
+ uint8_t icr = 0;
+#else
+ uint16_t icr = 0;
#endif
+ uint8_t msk = 0;
+ for (expchannel_t channel = EXT_INT_MIN_CHANNEL;
+ channel <= EXT_INT_MAX_CHANNEL; channel++) {
+ /* Determines the triggering condition for each channel. */
+ switch(extp->config->channels[channel].mode &
+ ~(EXT_CH_MODE_AUTOSTART | EXT_CH_MODE_INTERNAL_PULLUP)) {
+ case EXT_CH_MODE_LOW_LEVEL:
+ icr |= (EXT_EICRA_LOW_LEVEL << (2 * (channel - EXT_INT_MIN_CHANNEL)));
+ break;
+ case EXT_CH_MODE_BOTH_EDGES:
+ icr |= (EXT_EICRA_BOTH_EDGES << (2 * (channel - EXT_INT_MIN_CHANNEL)));
+ break;
+ case EXT_CH_MODE_RISING_EDGE:
+ icr |= (EXT_EICRA_RISING_EDGE << (2 * (channel - EXT_INT_MIN_CHANNEL)));
+ break;
+ case EXT_CH_MODE_FALLING_EDGE:
+ icr |= (EXT_EICRA_FALLING_EDGE << (2 * (channel - EXT_INT_MIN_CHANNEL)));
+ break;
+ default: osalDbgAssert(FALSE, "unsupported mode");
+ }
-#if AVR_EXT_USE_INT4 || defined(__DOXYGEN__)
-/**
- * @brief EXTI[INT4] interrupt handler.
- *
- * @isr
- */
-OSAL_IRQ_HANDLER(INT4_vect) {
- OSAL_IRQ_PROLOGUE();
- EXTD1.config->channels[INT4].cb(&EXTD1, INT4);
- OSAL_IRQ_EPILOGUE();
-}
+ /* Determines which channel must be started right away. */
+ if (extp->config->channels[channel].mode & EXT_CH_MODE_AUTOSTART) {
+ msk |= (1 << (channel - EXT_INT_MIN_CHANNEL));
+ }
+ }
+ /* Configures the peripheral. */
+#if defined(__AVR_ATmega162__)
+ MCUCR |= (icr & 0x0f);
+
+ icr >>= 4;
+ osalDbgAssert(((icr & 0x02) == EXT_EICRA_RISING_EDGE) || ((icr & 0x02) == EXT_EICRA_FALLING_EDGE), "INT2 only supports rising or falling edge, not both.");
+ EMCUCR |= icr & 0x01;
+
+ GICR |= ((msk & 0x03) << 6);
+ if (icr & 0x01) {
+ /* Enable INT2 */
+ GICR |= (1 << 5);
+ }
+#else
+ EICRA = icr & 0xff;
+#if EXT_INT_NUM_CHANNELS > 4
+ EICRB = icr >> 8;
#endif
-#if AVR_EXT_USE_INT5 || defined(__DOXYGEN__)
+ /* Enables/disables the peripheral, as requested. */
+ EIMSK = msk;
+#endif
+}
+
/**
- * @brief EXTI[INT5] interrupt handler.
- *
- * @isr
+ * @brief Deactivates the INT interrupts.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
*/
-OSAL_IRQ_HANDLER(INT5_vect) {
- OSAL_IRQ_PROLOGUE();
- EXTD1.config->channels[INT5].cb(&EXTD1, INT5);
- OSAL_IRQ_EPILOGUE();
+static void stop_ext(EXTDriver *extp) {
+ (void)extp;
+#if defined(__AVR_ATmega162__)
+ MCUCR &= ~(0x0f);
+ EMCUCR &= ~(0x01);
+ GICR |= ~(0x07 << 5);
+#else
+ EICRA = 0;
+#if EXT_INT_NUM_CHANNELS > 4
+ EICRB = 0;
+#endif
+ /* Enables/disables the peripheral, as requested. */
+ EIMSK = 0;
+#endif
}
#endif
/*===========================================================================*/
-/* Driver functions. */
+/* Driver interrupt handlers. */
/*===========================================================================*/
-/**
- * @brief Enables an EXT channel.
- *
- * @param[in] extp pointer to the @p EXTDriver object
- * @param[in] channel channel to be enabled
- *
- * @notapi
+/*
+ * Interrupt handlers for PC-type interrupts.
*/
-void ext_lld_channel_enable(EXTDriver *extp, expchannel_t channel) {
-#if AVR_EXT_USE_INT0 || defined(__DOXYGEN__)
- if (channel == INT0) {
- EIMSK |= 1 << INT0;
- ext_lld_set_intx_edges(channel, extp->config->channels[channel].mode);
- }
+#define EXT_PCINT_MIN_INDEX EXT_PC_MIN_PORT
+
+#if 0 < EXT_PC_NUM_PORTS
+#define EXT_PCINT0_INDEX EXT_PCINT_MIN_INDEX
+declare_pcint_isr(0);
#endif
-#if AVR_EXT_USE_INT1 || defined(__DOXYGEN__)
- if (channel == INT1) {
- EIMSK |= 1 << INT1;
- ext_lld_set_intx_edges(channel, extp->config->channels[channel].mode);
- }
+#if 1 < EXT_PC_NUM_PORTS
+#define EXT_PCINT1_INDEX (EXT_PCINT0_INDEX + 1)
+declare_pcint_isr(1);
#endif
-#if AVR_EXT_USE_INT2 || defined(__DOXYGEN__)
- if (channel == INT2) {
- EIMSK |= 1 << INT2;
- ext_lld_set_intx_edges(channel, extp->config->channels[channel].mode);
- }
+#if 2 < EXT_PC_NUM_PORTS
+#define EXT_PCINT2_INDEX (EXT_PCINT1_INDEX + 1)
+declare_pcint_isr(2);
#endif
-#if AVR_EXT_USE_INT3 || defined(__DOXYGEN__)
- if (channel == INT3) {
- EIMSK |= 1 << INT3;
- ext_lld_set_intx_edges(channel, extp->config->channels[channel].mode);
- }
+#if 3 < EXT_PC_NUM_PORTS
+#define EXT_PCINT3_INDEX (EXT_PCINT2_INDEX + 1)
+declare_pcint_isr(3);
#endif
-#if AVR_EXT_USE_INT4 || defined(__DOXYGEN__)
- if (channel == INT4) {
- EIMSK |= 1 << INT4;
- ext_lld_set_intx_edges(channel, extp->config->channels[channel].mode);
- }
+#if 4 < EXT_PC_NUM_PORTS
+#define EXT_PCINT4_INDEX (EXT_PCINT3_INDEX + 1)
+declare_pcint_isr(4);
#endif
-#if AVR_EXT_USE_INT5 || defined(__DOXYGEN__)
- if (channel == INT5) {
- EIMSK |= 1 << INT5;
- ext_lld_set_intx_edges(channel, extp->config->channels[channel].mode);
- }
+#if 5 < EXT_PC_NUM_PORTS
+#define EXT_PCINT5_INDEX (EXT_PCINT4_INDEX + 1)
+declare_pcint_isr(5);
+#endif
+#if 6 < EXT_PC_NUM_PORTS
+#define EXT_PCINT6_INDEX (EXT_PCINT5_INDEX + 1)
+declare_pcint_isr(6);
+#endif
+#if 7 < EXT_PC_NUM_PORTS
+#define EXT_PCINT7_INDEX (EXT_PCINT6_INDEX + 1)
+declare_pcint_isr(7);
+#endif
+#if 8 < EXT_PC_NUM_PORTS
+#define EXT_PCINT8_INDEX (EXT_PCINT7_INDEX + 1)
+declare_pcint_isr(8);
+#endif
+#if 9 < EXT_PC_NUM_PORTS
+#define EXT_PCINT9_INDEX (EXT_PCINT8_INDEX + 1)
+declare_pcint_isr(9);
#endif
-}
-/**
- * @brief Disables an EXT channel.
- *
- * @param[in] extp pinter to the @p EXTDriver object
- * @param[in] channel channel to be disabled
- *
- * @notapi
+/*
+ * Interrupt handlers for INT-type interrupts.
*/
-void ext_lld_channel_disable(EXTDriver *extp, expchannel_t channel) {
-#if AVR_EXT_USE_INT0 || defined(__DOXYGEN__)
- if (channel == INT0)
- EIMSK &= ~(1 << INT0);
+#if 0 < EXT_INT_NUM_CHANNELS
+declare_extint_isr(0);
#endif
-#if AVR_EXT_USE_INT1 || defined(__DOXYGEN__)
- if (channel == INT1)
- EIMSK &= ~(1 << INT1);
+#if 1 < EXT_INT_NUM_CHANNELS
+declare_extint_isr(1);
#endif
-#if AVR_EXT_USE_INT2 || defined(__DOXYGEN__)
- if (channel == INT2)
- EIMSK &= ~(1 << INT2);
+#if 2 < EXT_INT_NUM_CHANNELS
+declare_extint_isr(2);
#endif
-#if AVR_EXT_USE_INT3 || defined(__DOXYGEN__)
- if (channel == INT3)
- EIMSK &= ~(1 << INT3);
+#if 3 < EXT_INT_NUM_CHANNELS
+declare_extint_isr(3);
#endif
-#if AVR_EXT_USE_INT4 || defined(__DOXYGEN__)
- if (channel == INT4)
- EIMSK &= ~(1 << INT4);
+#if 4 < EXT_INT_NUM_CHANNELS
+declare_extint_isr(4);
#endif
-#if AVR_EXT_USE_INT5 || defined(__DOXYGEN__)
- if (channel == INT5)
- EIMSK &= ~(1 << INT5);
+#if 5 < EXT_INT_NUM_CHANNELS
+declare_extint_isr(5);
#endif
-}
+
+/*===========================================================================*/
+/* Driver functions. */
+/*===========================================================================*/
/**
* @brief Low level EXT driver initialization.
@@ -351,40 +418,129 @@ void ext_lld_channel_disable(EXTDriver *extp, expchannel_t channel) {
void ext_lld_init(void) {
/* Driver initialization.*/
extObjectInit(&EXTD1);
+#if EXT_PC_NUM_PORTS > 0
+ for (int i = 0; i < EXT_PC_NUM_PORTS; i++) {
+ EXTD1.pc_old_values[i] = 0;
+ }
+#endif
}
/**
* @brief Configures and activates the EXT peripheral.
*
- * @param[in] extp pointer to the @p EXTDriver object
+ * @param[in] extp pointer to the @p EXTDriver object
*
* @notapi
*/
void ext_lld_start(EXTDriver *extp) {
- expchannel_t line;
+#if EXT_INT_NUM_CHANNELS > 0
+ start_ext(extp);
+#endif
+#if EXT_PC_NUM_PORTS > 0
+ start_pc(extp);
+#endif
+}
- if (extp->state == EXT_STOP)
- osalSysUnlock();
+/**
+ * @brief Deactivates the EXT peripheral.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
+ *
+ * @notapi
+ */
+void ext_lld_stop(EXTDriver *extp) {
- /* Configuration of automatic channels. */
- for (line = 0; line < EXT_MAX_CHANNELS; line++) {
- if (extp->config->channels[line].mode & EXT_CH_MODE_AUTOSTART)
- ext_lld_channel_enable(extp, line);
- else
- ext_lld_channel_disable(extp, line);
+ if (extp->state == EXT_ACTIVE) {
+ /* Disables the peripheral.*/
+#if EXT_INT_NUM_CHANNELS > 0
+ stop_ext(extp);
+#endif
+#if EXT_PC_NUM_PORTS > 0
+ stop_pc(extp);
+#endif
}
}
/**
- * @brief Deactivates the EXT peripheral.
+ * @brief Enables an EXT channel.
*
- * @param[in] extp pointer to the @p EXTDriver object
+ * @param[in] extp pointer to the @p EXTDriver object
+ * @param[in] channel channel to be enabled
*
* @notapi
*/
-void ext_lld_stop(EXTDriver *extp) {
- if (extp->state == EXT_ACTIVE)
- osalSysLock();
+void ext_lld_channel_enable(EXTDriver *extp, expchannel_t channel) {
+ (void)extp;
+#if EXT_PC_NUM_CHANNELS > 0
+ if (EXT_PC_MIN_CHANNEL <= channel && channel <= EXT_PC_MAX_CHANNEL) {
+ uint8_t port = (channel - EXT_PC_MIN_CHANNEL) / 8;
+
+ /* Enable bit in mask */
+ (*(PCMSK[port])) |= _BV((channel - EXT_PC_MIN_CHANNEL) % 8);
+
+ /* Always enable interrupt */
+#if defined(__AVR_ATmega162__)
+ GICR |= (_BV(port) << 3);
+#else
+ PCICR |= _BV(port);
+#endif
+ }
+#endif
+#if EXT_PC_NUM_CHANNELS > 0 && EXT_INT_NUM_CHANNELS > 0
+ else
+#endif
+#if EXT_INT_NUM_CHANNELS > 0
+ if (channel <= EXT_INT_MAX_CHANNEL) {
+#if defined(__AVR_ATmega162__)
+ GICR |= ((1 << channel) << 5);
+#else
+ /* Enables/disables the peripheral, as requested. */
+ EIMSK |= (1 << channel);
+#endif
+ }
+#endif
+}
+
+/**
+ * @brief Disables an EXT channel.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
+ * @param[in] channel channel to be disabled
+ *
+ * @notapi
+ */
+void ext_lld_channel_disable(EXTDriver *extp, expchannel_t channel) {
+ (void)extp;
+#if EXT_PC_NUM_CHANNELS > 0
+ if (EXT_PC_MIN_CHANNEL <= channel && channel <= EXT_PC_MAX_CHANNEL) {
+ uint8_t port = (channel - EXT_PC_MIN_CHANNEL) / 8;
+
+ /* Clear bit in mask */
+ (*(PCMSK[port])) &= ~(_BV((channel - EXT_PC_MIN_CHANNEL) % 8));
+
+ /* Disable interrupt if no bits are set */
+ if ((*(PCMSK[port])) == 0) {
+#if defined(__AVR_ATmega162__)
+ GICR &= ~(_BV(port) << 3);
+#else
+ PCICR |= ~(_BV(port));
+#endif
+ }
+ }
+#endif
+#if EXT_PC_NUM_CHANNELS > 0 && EXT_INT_NUM_CHANNELS > 0
+ else
+#endif
+#if EXT_INT_NUM_CHANNELS > 0
+ if (channel <= EXT_INT_MAX_CHANNEL) {
+#if defined(__AVR_ATmega162__)
+ GICR &= ~((1 << channel) << 5);
+#else
+ /* Enables/disables the peripheral, as requested. */
+ EIMSK &= ~(1 << channel);
+#endif
+ }
+#endif
}
#endif /* HAL_USE_EXT */
diff --git a/os/hal/ports/AVR/hal_ext_lld.h b/os/hal/ports/AVR/hal_ext_lld.h
index 883972419..c20c553b0 100644
--- a/os/hal/ports/AVR/hal_ext_lld.h
+++ b/os/hal/ports/AVR/hal_ext_lld.h
@@ -1,5 +1,7 @@
/*
- ChibiOS - Copyright (C) 2016 Theodore Ateba
+ EXT Low Level Driver for ChibiOS
+ Copyright (C) 2015 Igor Stoppa <igor.stoppa@gmail.com>
+ Copyright (C) 2016 Theodore Ateba
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,8 +17,8 @@
*/
/**
- * @file hal_ext_lld.h
- * @brief EXT Driver subsystem low level driver source.
+ * @file AVR/hal_ext_lld.h
+ * @brief EXT Driver subsystem low level driver source.
*
* @addtogroup EXT
* @{
@@ -32,48 +34,451 @@
/*===========================================================================*/
/**
- * @brief Maximum number of EXT channels.
+ * @brief Level-driven irq generation.
*/
-#define AVR_INT_NUM_LINES 6 /**< INT0 to INT5 */
-
-/**
- * @brief Available number of EXT channels.
- */
-#define EXT_MAX_CHANNELS AVR_INT_NUM_LINES
+#define EXT_CH_MODE_LEVELS_MASK 8U /**< @brief Mask of levels field. */
+#undef EXT_CH_MODE_LOW_LEVEL
+#define EXT_CH_MODE_LOW_LEVEL 8U /**< @brief Trigger on Low level. */
+#define EXT_CH_MODE_INTERNAL_PULLUP 16U /**< @brief Use internal pullup. */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
+/**
+ * @name AVR configuration options
+ * @{
+ */
+/**
+ * @brief INT0 support enable switch.
+ * @details If set to @p TRUE the support for INT0 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_INT0) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_INT0 FALSE
+#endif
+
+/**
+ * @brief INT1 support enable switch.
+ * @details If set to @p TRUE the support for INT1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_INT1) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_INT1 FALSE
+#endif
+
+/**
+ * @brief INT2 support enable switch.
+ * @details If set to @p TRUE the support for INT2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_INT2) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_INT2 FALSE
+#endif
+
+/**
+ * @brief INT3 support enable switch.
+ * @details If set to @p TRUE the support for INT3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_INT3) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_INT3 FALSE
+#endif
+
+/**
+ * @brief INT4 support enable switch.
+ * @details If set to @p TRUE the support for INT4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_INT4) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_INT4 FALSE
+#endif
+
+/**
+ * @brief INT5 support enable switch.
+ * @details If set to @p TRUE the support for INT5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_INT5) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_INT5 FALSE
+#endif
+
+/**
+ * @brief PCINT0 support enable switch.
+ * @details If set to @p TRUE the support for PCINT0 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT0) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT0 FALSE
+#endif
+
+/**
+ * @brief PCINT1 support enable switch.
+ * @details If set to @p TRUE the support for PCINT1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT1) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT1 FALSE
+#endif
+
+/**
+ * @brief PCINT2 support enable switch.
+ * @details If set to @p TRUE the support for PCINT2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT2) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT2 FALSE
+#endif
+
+/**
+ * @brief PCINT3 support enable switch.
+ * @details If set to @p TRUE the support for PCINT3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT3) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT3 FALSE
+#endif
+
+/**
+ * @brief PCINT4 support enable switch.
+ * @details If set to @p TRUE the support for PCINT4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT4) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT4 FALSE
+#endif
+
+/**
+ * @brief PCINT5 support enable switch.
+ * @details If set to @p TRUE the support for PCINT5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT5) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT5 FALSE
+#endif
+
+/**
+ * @brief PCINT6 support enable switch.
+ * @details If set to @p TRUE the support for PCINT6 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT6) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT6 FALSE
+#endif
+
+/**
+ * @brief PCINT7 support enable switch.
+ * @details If set to @p TRUE the support for PCINT7 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT7) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT7 FALSE
+#endif
+
+/**
+ * @brief PCINT8 support enable switch.
+ * @details If set to @p TRUE the support for PCINT8 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT8) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT8 FALSE
+#endif
+
+/**
+ * @brief PCINT9 support enable switch.
+ * @details If set to @p TRUE the support for PCINT9 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT9) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT9 FALSE
+#endif
+
+/**
+ * @brief PCINT10 support enable switch.
+ * @details If set to @p TRUE the support for PCINT10 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(AVR_EXT_USE_PCINT10) || defined(__DOXYGEN__)
+#define AVR_EXT_USE_PCINT10 FALSE
+#endif
+/** @} */
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
+#if !defined(INT0_vect) && AVR_EXT_USE_INT0
+#error "INT0 is not present in the selected device"
+#endif
+
+#if !defined(INT1_vect) && AVR_EXT_USE_INT1
+#error "INT1 is not present in the selected device"
+#endif
+
+#if !defined(INT2_vect) && AVR_EXT_USE_INT2
+#error "INT2 is not present in the selected device"
+#endif
+
+#if !defined(INT3_vect) && AVR_EXT_USE_INT3
+#error "INT3 is not present in the selected device"
+#endif
+
+#if !defined(INT4_vect) && AVR_EXT_USE_INT4
+#error "INT4 is not present in the selected device"
+#endif
+
+#if !defined(INT5_vect) && AVR_EXT_USE_INT5
+#error "INT5 is not present in the selected device"
+#endif
+
+#if !defined(PCINT0_PIN) && AVR_EXT_USE_PCINT0
+#error "PCINT0 is not present in the selected device"
+#endif
+
+#if !defined(PCINT1_PIN) && AVR_EXT_USE_PCINT1
+#error "PCINT1 is not present in the selected device"
+#endif
+
+#if !defined(PCINT2_PIN) && AVR_EXT_USE_PCINT2
+#error "PCINT2 is not present in the selected device"
+#endif
+
+#if !defined(PCINT3_PIN) && AVR_EXT_USE_PCINT3
+#error "PCINT3 is not present in the selected device"
+#endif
+
+#if !defined(PCINT4_PIN) && AVR_EXT_USE_PCINT4
+#error "PCINT4 is not present in the selected device"
+#endif
+
+#if !defined(PCINT5_PIN) && AVR_EXT_USE_PCINT5
+#error "PCINT5 is not present in the selected device"
+#endif
+
+#if !defined(PCINT6_PIN) && AVR_EXT_USE_PCINT6
+#error "PCINT6 is not present in the selected device"
+#endif
+
+#if !defined(PCINT7_PIN) && AVR_EXT_USE_PCINT7
+#error "PCINT7 is not present in the selected device"
+#endif
+
+#if !defined(PCINT8_PIN) && AVR_EXT_USE_PCINT8
+#error "PCINT8 is not present in the selected device"
+#endif
+
+#if !defined(PCINT9_PIN) && AVR_EXT_USE_PCINT9
+#error "PCINT9 is not present in the selected device"
+#endif
+
+#if !defined(PCINT10_PIN) && AVR_EXT_USE_PCINT10
+#error "PCINT10 is not present in the selected device"
+#endif
+
+/**
+ * @brief Indexes of INT channels.
+ */
+#define EXT_INT_MIN_CHANNEL 0
+
+#if AVR_EXT_USE_INT0
+#define EXT_INT0_PRESENT 1
+#define EXT_INT0_CHANNEL EXT_INT_MIN_CHANNEL
+#else
+#define EXT_INT0_PRESENT 0
+#define EXT_INT0_CHANNEL (EXT_INT_MIN_CHANNEL - 1)
+#endif
+
+#if AVR_EXT_USE_INT1
+#define EXT_INT1_PRESENT 1
+#define EXT_INT1_CHANNEL (EXT_INT0_CHANNEL + 1)
+#else
+#define EXT_INT1_PRESENT 0
+#define EXT_INT1_CHANNEL EXT_INT0_CHANNEL
+#endif
+
+#if AVR_EXT_USE_INT2
+#define EXT_INT2_PRESENT 1
+#define EXT_INT2_CHANNEL (EXT_INT1_CHANNEL + 1)
+#else
+#define EXT_INT2_PRESENT 0
+#define EXT_INT2_CHANNEL EXT_INT1_CHANNEL
+#endif
+
+#if AVR_EXT_USE_INT3
+#define EXT_INT3_PRESENT 1
+#define EXT_INT3_CHANNEL (EXT_INT2_CHANNEL + 1)
+#else
+#define EXT_INT3_PRESENT 0
+#define EXT_INT3_CHANNEL EXT_INT2_CHANNEL
+#endif
+
+#if AVR_EXT_USE_INT4
+#define EXT_INT4_PRESENT 1
+#define EXT_INT4_CHANNEL (EXT_INT3_CHANNEL + 1)
+#else
+#define EXT_INT4_PRESENT 0
+#define EXT_INT4_CHANNEL EXT_INT3_CHANNEL
+#endif
+
+#if AVR_EXT_USE_INT5
+#define EXT_INT5_PRESENT 1
+#define EXT_INT5_CHANNEL (EXT_INT4_CHANNEL + 1)
+#else
+#define EXT_INT5_PRESENT 0
+#define EXT_INT5_CHANNEL EXT_INT4_CHANNEL
+#endif
+
+#define EXT_INT_NUM_CHANNELS \
+ (EXT_INT0_PRESENT + EXT_INT1_PRESENT + EXT_INT2_PRESENT + \
+ EXT_INT3_PRESENT + EXT_INT4_PRESENT + EXT_INT5_PRESENT)
+
+#if EXT_INT_NUM_CHANNELS > 0
+#define EXT_INT_MAX_CHANNEL (EXT_INT_MIN_CHANNEL + EXT_INT_NUM_CHANNELS - 1)
+#else
+#define EXT_INT_MAX_CHANNEL 0
+#endif
+
+/**
+ * @brief Indexes of PC channels.
+ */
+#define EXT_PC_MIN_PORT EXT_INT_NUM_CHANNELS
+
+#if AVR_EXT_USE_PCINT0
+#define PORTA_PRESENT 1
+#define PORTA_INDEX EXT_PC_MIN_PORT
+#else
+#define PORTA_PRESENT 0
+#define PORTA_INDEX (EXT_PC_MIN_PORT - 1)
+#endif
+
+#if AVR_EXT_USE_PCINT1
+#define PORTB_PRESENT 1
+#define PORTB_INDEX (PORTA_INDEX + 1)
+#else
+#define PORTB_PRESENT 0
+#define PORTB_INDEX PORTA_INDEX
+#endif
+
+#if AVR_EXT_USE_PCINT2
+#define PORTC_PRESENT 1
+#define PORTC_INDEX (PORTB_INDEX + 1)
+#else
+#define PORTC_PRESENT 0
+#define PORTC_INDEX PORTB_INDEX
+#endif
+
+#if AVR_EXT_USE_PCINT3
+#define PORTD_PRESENT 1
+#define PORTD_INDEX (PORTC_INDEX + 1)
+#else
+#define PORTD_PRESENT 0
+#define PORTD_INDEX PORTC_INDEX
+#endif
+
+#if AVR_EXT_USE_PCINT4
+#define PORTE_PRESENT 1
+#define PORTE_INDEX (PORTD_INDEX + 1)
+#else
+#define PORTE_PRESENT 0
+#define PORTE_INDEX PORTD_INDEX
+#endif
+
+#if AVR_EXT_USE_PCINT5
+#define PORTF_PRESENT 1
+#define PORTF_INDEX (PORTE_INDEX + 1)
+#else
+#define PORTF_PRESENT 0
+#define PORTF_INDEX PORTE_INDEX
+#endif
+
+#if AVR_EXT_USE_PCINT6
+#define PORTG_PRESENT 1
+#define PORTG_INDEX (PORTF_INDEX + 1)
+#else
+#define PORTG_PRESENT 0
+#define PORTG_INDEX PORTF_INDEX
+#endif
+
+#if AVR_EXT_USE_PCINT7
+#define PORTH_PRESENT 1
+#define PORTH_INDEX (PORTG_INDEX + 1)
+#else
+#define PORTH_PRESENT 0
+#define PORTH_INDEX PORTG_INDEX
+#endif
+
+#if AVR_EXT_USE_PCINT8
+#define PORTI_PRESENT 1
+#define PORTI_INDEX (PORTH_INDEX + 1)
+#else
+#define PORTI_PRESENT 0
+#define PORTI_INDEX PORTH_INDEX
+#endif
+
+#if AVR_EXT_USE_PCINT9
+#define PORTJ_PRESENT 1
+#define PORTJ_INDEX (PORTI_INDEX + 1)
+#else
+#define PORTJ_PRESENT 0
+#define PORTJ_INDEX PORTI_INDEX
+#endif
+
+#if AVR_EXT_USE_PCINT10
+#define PORTK_PRESENT 1
+#define PORTK_INDEX (PORTJ_INDEX + 1)
+#else
+#define PORTK_PRESENT 0
+#define PORTK_INDEX PORTJ_INDEX
+#endif
+
+/**
+ * @brief Available number of PC ports.
+ */
+
+#define EXT_PC_NUM_PORTS \
+ (PORTA_PRESENT + PORTB_PRESENT + PORTC_PRESENT + PORTD_PRESENT + \
+ PORTE_PRESENT + PORTF_PRESENT + PORTG_PRESENT + PORTH_PRESENT + \
+ PORTI_PRESENT + PORTJ_PRESENT + PORTK_PRESENT)
+
+#if EXT_PC_NUM_PORTS > 0
+#define EXT_PC_MAX_PORT (EXT_PC_MIN_PORT + EXT_PC_NUM_PORTS - 1)
+#else
+#define EXT_PC_MAX_PORT 0
+#endif
+
+#define EXT_PC_NUM_CHANNELS (EXT_PC_NUM_PORTS * 8)
+
+#define EXT_TOTAL_CHANNELS (EXT_INT_NUM_CHANNELS + EXT_PC_NUM_CHANNELS)
+#define EXT_MAX_CHANNELS EXT_TOTAL_CHANNELS
+#define EXT_PC_MIN_CHANNEL EXT_INT_NUM_CHANNELS
+#define EXT_PC_MAX_CHANNEL (EXT_PC_MIN_CHANNEL + EXT_PC_NUM_CHANNELS - 1)
+
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
- * @brief EXT channel identifier.
+ * @brief EXT channel identifier.
*/
typedef uint16_t expchannel_t;
/**
- * @brief Type of an EXT generic notification callback.
+ * @brief Type of an EXT generic notification callback.
*
* @param[in] extp pointer to the @p EXPDriver object triggering the
* callback
+ * @param[in] channel channel being triggered.
*/
typedef void (*extcallback_t)(EXTDriver *extp, expchannel_t channel);
/**
- * @brief Channel configuration structure.
+ * @brief Channel configuration structure.
*/
typedef struct {
/**
- * @brief Channel mode.
+ * @brief Channel mode from HAL.
*/
- uint32_t mode;
+ uint8_t mode;
/**
* @brief Channel callback.
*/
@@ -81,19 +486,19 @@ typedef struct {
} EXTChannelConfig;
/**
- * @brief Driver configuration structure.
- * @note It could be empty on some architectures.
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
*/
typedef struct {
/**
* @brief Channel configurations.
*/
- EXTChannelConfig channels[EXT_MAX_CHANNELS];
+ EXTChannelConfig channels[EXT_TOTAL_CHANNELS];
/* End of the mandatory fields.*/
} EXTConfig;
/**
- * @brief Structure representing an EXT driver.
+ * @brief Structure representing an EXT driver.
*/
struct EXTDriver {
/**
@@ -106,15 +511,29 @@ struct EXTDriver {
*/
const EXTConfig *config;
/* End of the mandatory fields.*/
+#if EXT_PC_NUM_PORTS > 0
+ /**
+ * @brief Current pin values. Only valid for PCINT.
+ */
+ uint8_t pc_current_values[EXT_PC_NUM_PORTS];
+ /**
+ * @brief Previous pin states. Only valid for PCINT.
+ */
+ uint8_t pc_old_values[EXT_PC_NUM_PORTS];
+#endif
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
+#define ext_port_to_channel(port, bit) \
+ ((PORT##port##_INDEX - EXT_PC_MIN_PORT) * 8 + bit)
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
+
extern EXTDriver EXTD1;
#ifdef __cplusplus