1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-25 14:33:52 +01:00

Merge pull request #12933 from maribu/atmega_pcint_cleanup

cpu/atmega_common/periph/gpio: Clean up PCINT support
This commit is contained in:
benpicco 2020-02-06 18:29:15 +01:00 committed by GitHub
commit 24fb7a9aae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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)
{