diff --git a/cpu/atmega_common/periph/gpio.c b/cpu/atmega_common/periph/gpio.c index b629cac81d..ba7b462004 100644 --- a/cpu/atmega_common/periph/gpio.c +++ b/cpu/atmega_common/periph/gpio.c @@ -64,65 +64,52 @@ static gpio_isr_ctx_t config[GPIO_EXT_INT_NUMOF]; -/** - * @brief detects amount of possible PCINTs - */ +/* Detects amount of possible PCINTs */ #if defined(MODULE_ATMEGA_PCINT0) || defined(MODULE_ATMEGA_PCINT1) || \ defined(MODULE_ATMEGA_PCINT2) || defined(MODULE_ATMEGA_PCINT3) #include "atmega_pcint.h" -/** - * @brief check which pcints should be enabled! - */ -#ifdef MODULE_ATMEGA_PCINT0 -#ifndef ATMEGA_PCINT_MAP_PCINT0 +#define ENABLE_PCINT + +/* Check which pcints should be enabled */ +#if defined(MODULE_ATMEGA_PCINT0) && !defined(ATMEGA_PCINT_MAP_PCINT0) #error \ Either mapping for pin change interrupt bank 0 is missing or not supported by the MCU -#else -#define PCINT0_IDX (0) -#define _COUNTER0 (1) -#endif /* ATMEGA_PCINT_MAP_PCINT0 */ -#else -#define _COUNTER0 (0) -#endif /* MODULE_ATMEGA_PCINT0 */ +#endif -#ifdef MODULE_ATMEGA_PCINT1 -#ifndef ATMEGA_PCINT_MAP_PCINT1 +#if defined(MODULE_ATMEGA_PCINT1) && !defined(ATMEGA_PCINT_MAP_PCINT1) #error \ Either mapping for pin change interrupt bank 1 is missing or not supported by the MCU -#else -#define PCINT1_IDX _COUNTER0 -#define _COUNTER1 (_COUNTER0 + 1) -#endif /* ATMEGA_PCINT_MAP_PCINT1 */ -#else -#define _COUNTER1 _COUNTER0 -#endif /* MODULE_ATMEGA_PCINT1 */ +#endif -#ifdef MODULE_ATMEGA_PCINT2 -#ifndef ATMEGA_PCINT_MAP_PCINT2 +#if defined(MODULE_ATMEGA_PCINT2) && !defined(ATMEGA_PCINT_MAP_PCINT2) #error \ Either mapping for pin change interrupt bank 2 is missing or not supported by the MCU -#else -#define PCINT2_IDX _COUNTER1 -#define _COUNTER2 (_COUNTER1 + 1) -#endif /* ATMEGA_PCINT_MAP_PCINT2 */ -#else -#define _COUNTER2 _COUNTER1 -#endif /* MODULE_ATMEGA_PCINT2 */ +#endif -#ifdef MODULE_ATMEGA_PCINT3 -#ifndef ATMEGA_PCINT_MAP_PCINT3 +#if defined(MODULE_ATMEGA_PCINT3) && !defined(ATMEGA_PCINT_MAP_PCINT3) #error \ Either mapping for pin change interrupt bank 3 is missing or not supported by the MCU -#else -#define PCINT3_IDX _COUNTER2 -#define _COUNTER3 (_COUNTER2 + 1) -#endif /* ATMEGA_PCINT_MAP_PCINT3 */ -#else -#define _COUNTER3 _COUNTER2 -#endif /* MODULE_ATMEGA_PCINT3 */ +#endif -#define PCINT_NUM_BANKS (_COUNTER3) +/** + * @brief Use anonymous enum as for addressing the @ref pcint_state + */ +enum { +#ifdef MODULE_ATMEGA_PCINT0 + PCINT0_IDX, /**< Index of PCINT0, if used */ +#endif /* MODULE_ATMEGA_PCINT0 */ +#ifdef MODULE_ATMEGA_PCINT1 + PCINT1_IDX, /**< Index of PCINT1, if used */ +#endif /* MODULE_ATMEGA_PCINT1 */ +#ifdef MODULE_ATMEGA_PCINT2 + PCINT2_IDX, /**< Index of PCINT2, if used */ +#endif /* MODULE_ATMEGA_PCINT2 */ +#ifdef MODULE_ATMEGA_PCINT3 + PCINT3_IDX, /**< Index of PCINT3, if used */ +#endif /* MODULE_ATMEGA_PCINT3 */ + PCINT_NUM_BANKS /**< Number of PCINT banks used */ +}; /** * @brief stores the last pcint state of each port @@ -142,16 +129,16 @@ typedef struct { * @brief */ static const gpio_t pcint_mapping[] = { -#ifdef PCINT0_IDX +#ifdef MODULE_ATMEGA_PCINT0 ATMEGA_PCINT_MAP_PCINT0, #endif /* PCINT0_IDX */ -#ifdef PCINT1_IDX +#ifdef MODULE_ATMEGA_PCINT1 ATMEGA_PCINT_MAP_PCINT1, #endif /* PCINT1_IDX */ -#ifdef PCINT2_IDX +#ifdef MODULE_ATMEGA_PCINT2 ATMEGA_PCINT_MAP_PCINT2, #endif /* PCINT2_IDX */ -#ifdef PCINT3_IDX +#ifdef MODULE_ATMEGA_PCINT3 ATMEGA_PCINT_MAP_PCINT3, #endif /* PCINT3_IDX */ }; @@ -237,6 +224,84 @@ static inline int8_t _int_num(gpio_t pin) return -1; } +#ifdef ENABLE_PCINT +static inline int pcint_init_int(gpio_t pin, gpio_mode_t mode, + gpio_flank_t flank, + gpio_cb_t cb, void *arg) +{ + int8_t offset = -1; + uint8_t pin_num = atmega_pin_num(pin); + + for (unsigned i = 0; i < ARRAY_SIZE(pcint_mapping); i++) { + if (pin != GPIO_UNDEF && pin == pcint_mapping[i]) { + offset = i; + break; + } + } + + /* if pcint was not found: return -1 */ + if (offset < 0) { + return offset; + } + + uint8_t bank = offset / 8; + uint8_t bank_idx = offset % 8; + DEBUG("PCINT enabled for bank %u offset %u\n", + (unsigned)bank, (unsigned)offset); + + /* save configuration for pin change interrupt */ + pcint_config[offset].flank = flank; + pcint_config[offset].arg = arg; + pcint_config[offset].cb = cb; + + /* init gpio */ + gpio_init(pin, mode); + /* configure pcint */ + cli(); + switch (bank) { +#ifdef MODULE_ATMEGA_PCINT0 + case PCINT0_IDX: + PCMSK0 |= (1 << bank_idx); + PCICR |= (1 << PCIE0); + break; +#endif /* MODULE_ATMEGA_PCINT0 */ +#ifdef MODULE_ATMEGA_PCINT1 + case PCINT1_IDX: + PCMSK1 |= (1 << bank_idx); + PCICR |= (1 << PCIE1); + break; +#endif /* MODULE_ATMEGA_PCINT1 */ +#ifdef MODULE_ATMEGA_PCINT2 + case PCINT2_IDX: + PCMSK2 |= (1 << bank_idx); + PCICR |= (1 << PCIE2); + break; +#endif /* MODULE_ATMEGA_PCINT2 */ +#ifdef MODULE_ATMEGA_PCINT3 + case PCINT3_IDX: + PCMSK3 |= (1 << bank_idx); + PCICR |= (1 << PCIE3); + break; +#endif /* MODULE_ATMEGA_PCINT3 */ + default: + return -1; + break; + } + /* As ports are mixed in a bank (e.g. PCINT0), we can only save a single bit here! */ + uint8_t port_value = (_SFR_MEM8(atmega_pin_addr( pin ))); + uint8_t pin_mask = (1 << pin_num); + uint8_t pin_value = ((port_value & pin_mask) != 0); + if (pin_value) { + pcint_state[bank] |= pin_mask; + } + else { + pcint_state[bank] &= ~pin_mask; + } + sei(); + return 0; +} +#endif /* ENABLE_PCINT */ + int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, gpio_cb_t cb, void *arg) { @@ -249,80 +314,12 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, /* not a valid interrupt pin. Set as pcint instead if pcints are enabled */ if (int_num < 0) { +#ifdef ENABLE_PCINT /* If pin change interrupts are enabled, enable mask and interrupt */ - #ifdef PCINT_NUM_BANKS - int8_t offset = -1; - uint8_t pin_num = atmega_pin_num(pin); - - for (unsigned i = 0; i < ARRAY_SIZE(pcint_mapping); i++) { - if (pin != GPIO_UNDEF && pin == pcint_mapping[i]) { - offset = i; - break; - } - } - - /* if pcint was not found: return -1 */ - if (offset < 0) { - return offset; - } - - uint8_t bank = offset / 8; - uint8_t bank_idx = offset % 8; - DEBUG("PCINT enabled for bank %u offset %u\n", - (unsigned)bank, (unsigned)offset); - - /* save configuration for pin change interrupt */ - pcint_config[offset].flank = flank; - pcint_config[offset].arg = arg; - pcint_config[offset].cb = cb; - - /* init gpio */ - gpio_init(pin, mode); - /* configure pcint */ - cli(); - switch (bank) { -#ifdef PCINT0_IDX - case PCINT0_IDX: - PCMSK0 |= (1 << bank_idx); - PCICR |= (1 << PCIE0); - break; -#endif /* PCINT0_IDX */ -#ifdef PCINT1_IDX - case PCINT1_IDX: - PCMSK1 |= (1 << bank_idx); - PCICR |= (1 << PCIE1); - break; -#endif /* PCINT1_IDX */ -#ifdef PCINT2_IDX - case PCINT2_IDX: - PCMSK2 |= (1 << bank_idx); - PCICR |= (1 << PCIE2); - break; -#endif /* PCINT2_IDX */ -#ifdef PCINT3_IDX - case PCINT3_IDX: - PCMSK3 |= (1 << pin_num); - PCICR |= (1 << PCIE3); - break; -#endif /* PCINT3_IDX */ - default: - return -1; - break; - } - /* As ports are mixed in a bank (e.g. PCINT0), we can only save a single bit here! */ - uint8_t port_value = (_SFR_MEM8(atmega_pin_addr( pin ))); - uint8_t pin_mask = (1 << pin_num); - uint8_t pin_value = ((port_value & pin_mask) != 0); - if (pin_value) { - pcint_state[bank] |= pin_mask; - } - else { - pcint_state[bank] &= ~pin_mask; - } - sei(); - return 0; - #endif /* GPIO_PC_INT_NUMOF */ + return pcint_init_int(pin, mode, flank, cb, arg); +#else return -1; +#endif /* ENABLE_PCINT */ } /* flank not supported */ @@ -379,7 +376,7 @@ static inline void irq_handler(uint8_t int_num) atmega_exit_isr(); } -#ifdef PCINT_NUM_BANKS +#ifdef ENABLE_PCINT /* inline function that is used by the PCINT ISR */ static inline void pcint_handler(uint8_t bank, uint8_t enabled_pcints) { @@ -415,35 +412,35 @@ static inline void pcint_handler(uint8_t bank, uint8_t enabled_pcints) atmega_exit_isr(); } -#if defined(PCINT0_IDX) +#ifdef MODULE_ATMEGA_PCINT0 ISR(PCINT0_vect, ISR_BLOCK) { pcint_handler(PCINT0_IDX, PCMSK0); } -#endif /* PCINT0_IDX */ +#endif /* MODULE_ATMEGA_PCINT0 */ -#if defined(PCINT1_IDX) +#ifdef MODULE_ATMEGA_PCINT1 ISR(PCINT1_vect, ISR_BLOCK) { pcint_handler(PCINT1_IDX, PCMSK1); } -#endif /* PCINT1_IDX */ +#endif /* MODULE_ATMEGA_PCINT1 */ -#if defined(PCINT2_IDX) +#ifdef MODULE_ATMEGA_PCINT2 ISR(PCINT2_vect, ISR_BLOCK) { pcint_handler(PCINT2_IDX, PCMSK2); } -#endif /* PCINT2_IDX */ +#endif /* MODULE_ATMEGA_PCINT2 */ -#if defined(PCINT3_IDX) +#ifdef MODULE_ATMEGA_PCINT3 ISR(PCINT3_vect, ISR_BLOCK) { pcint_handler(PCINT3_IDX, PCMSK3); } -#endif /* PCINT3_IDX */ +#endif /* MODULE_ATMEGA_PCINT3 */ -#endif /* GPIO_PC_INT_NUMOF */ +#endif /* ENABLE_PCINT */ ISR(INT0_vect, ISR_BLOCK) {