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:
commit
24fb7a9aae
@ -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)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user