diff --git a/boards/arduino-mega2560/doc.txt b/boards/arduino-mega2560/doc.txt index 992ae89475..fcdf4c4a88 100644 --- a/boards/arduino-mega2560/doc.txt +++ b/boards/arduino-mega2560/doc.txt @@ -46,6 +46,11 @@ This should take care of everything! We use the open `avrdude` tool to write the new code into the ATmega2560's flash +## Pin Change Interrupts + +More pins can be used for hardware interrupts using the Pin Change +Interrupt feature. See @ref boards_common_atmega for details. + ## State While there is basic support in RIOT, there are still some parts missing: * Timer implementation needs love (ideally simulate a 32bit timer by adding diff --git a/boards/arduino-mega2560/include/atmega_pcint.h b/boards/arduino-mega2560/include/atmega_pcint.h new file mode 100644 index 0000000000..47dcbafdbd --- /dev/null +++ b/boards/arduino-mega2560/include/atmega_pcint.h @@ -0,0 +1,16 @@ +#ifndef ATMEGA_PCINT_H +#define ATMEGA_PCINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ATMEGA_PCINT_MAP_PCINT0 GPIO_PIN(PORT_B, 0), GPIO_PIN(PORT_B, 1), GPIO_PIN(PORT_B, 2), GPIO_PIN(PORT_B, 3), GPIO_PIN(PORT_B, 4), GPIO_PIN(PORT_B, 5), GPIO_PIN(PORT_B, 6), GPIO_PIN(PORT_B, 7) +#define ATMEGA_PCINT_MAP_PCINT1 GPIO_PIN(PORT_E, 0), GPIO_PIN(PORT_J, 0), GPIO_PIN(PORT_J, 1), GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF +#define ATMEGA_PCINT_MAP_PCINT2 GPIO_PIN(PORT_K, 0), GPIO_PIN(PORT_K, 1), GPIO_PIN(PORT_K, 2), GPIO_PIN(PORT_K, 3), GPIO_PIN(PORT_K, 4), GPIO_PIN(PORT_K, 5), GPIO_PIN(PORT_K, 6), GPIO_PIN(PORT_K, 7) + +#ifdef __cplusplus +} +#endif + +#endif /* ATMEGA_PCINT_H */ diff --git a/boards/arduino-uno/doc.txt b/boards/arduino-uno/doc.txt index 0ef7b9bb5c..00d4ff6436 100644 --- a/boards/arduino-uno/doc.txt +++ b/boards/arduino-uno/doc.txt @@ -37,6 +37,11 @@ This should take care of everything! We use the open `avrdude` tool to write the new code into the ATmega328p's flash +## Pin Change Interrupts + +More pins can be used for hardware interrupts using the Pin Change +Interrupt feature. See @ref boards_common_atmega for details. + ##Caution Don't expect having a working network stack due to very limited resources. */ diff --git a/boards/common/atmega/doc.txt b/boards/common/atmega/doc.txt new file mode 100644 index 0000000000..81e9a07db1 --- /dev/null +++ b/boards/common/atmega/doc.txt @@ -0,0 +1,17 @@ +/** +@defgroup boards_common_atmega ATmega common +@ingroup boards +@brief Shared files and configuration for ATmega-based boards + +### Pin Change Interrupts + +Pin Change Interrupts (PCINTs) can be enabled using pseudo modules. To provide +a low-memory overhead implementation, the PCINTs are grouped into **banks**. +Each banks corresponds to one PCINT on the ATmega (PCINT0, ..., PCINT3). + +To enable only a specific bank, simply add `USEMODULE += atmega_pcintN` to your +Makefile. To enable all interrupts you can use `USEMODULE += atmega_pcint`. + +In case you want to add a new CPU, simply provide an `atmega_pcint.h` with your +CPU and adapt your Makefile.dep and Makefile.featues files. + */ \ No newline at end of file diff --git a/boards/jiminy-mega256rfr2/doc.txt b/boards/jiminy-mega256rfr2/doc.txt index 9a09ed9e0b..6b0d0f3323 100644 --- a/boards/jiminy-mega256rfr2/doc.txt +++ b/boards/jiminy-mega256rfr2/doc.txt @@ -173,4 +173,9 @@ the clocks for all peripherals are enabled and set to the smallest divider (high power consumption. When the device should be put into deep sleep it is recommended to use the internal RC oscillator as system clock source. +## Pin Change Interrupts + +More pins can be used for hardware interrupts using the Pin Change +Interrupt feature. See @ref boards_common_atmega for details. + */ diff --git a/boards/mega-xplained/doc.txt b/boards/mega-xplained/doc.txt index 1aa39ac1c8..2c59bd442a 100644 --- a/boards/mega-xplained/doc.txt +++ b/boards/mega-xplained/doc.txt @@ -34,4 +34,10 @@ It will be used automatically with `make term`: ``` make BOARD=mega-xplained -C examples/hello-world term ``` + +### Pin Change Interrupts + +More pins can be used for hardware interrupts using the Pin Change +Interrupt feature. See @ref boards_common_atmega for details. + */ diff --git a/boards/waspmote-pro/doc.txt b/boards/waspmote-pro/doc.txt index 67f180aefb..82c85b3ce9 100644 --- a/boards/waspmote-pro/doc.txt +++ b/boards/waspmote-pro/doc.txt @@ -2,4 +2,10 @@ @defgroup boards_waspmote-pro Waspmote PRO v1.2 @ingroup boards @brief Support for the Waspmote PRO v1.2 board. + +## Pin Change Interrupts + +More pins can be used for hardware interrupts using the Pin Change +Interrupt feature. See @ref boards_common_atmega for details. + */ diff --git a/cpu/atmega1281/Makefile.features b/cpu/atmega1281/Makefile.features index 008260685b..39270920c7 100644 --- a/cpu/atmega1281/Makefile.features +++ b/cpu/atmega1281/Makefile.features @@ -1 +1,3 @@ --include $(RIOTCPU)/atmega_common/Makefile.features +FEATURES_PROVIDED += atmega_pcint1 atmega_pcint2 + +include $(RIOTCPU)/atmega_common/Makefile.features diff --git a/cpu/atmega1281/Makefile.include b/cpu/atmega1281/Makefile.include index 66add33aaa..3c826aa587 100644 --- a/cpu/atmega1281/Makefile.include +++ b/cpu/atmega1281/Makefile.include @@ -4,5 +4,10 @@ USEMODULE += atmega_common RAM_LEN = 8K ROM_LEN = 128K +# expand atmega_pcint for additional PCINTs of atmega1281 +ifneq (,$(filter atmega_pcint,$(USEMODULE))) + USEMODULE += atmega_pcint1 atmega_pcint2 +endif + # CPU depends on the atmega common module, so include it include $(RIOTCPU)/atmega_common/Makefile.include diff --git a/cpu/atmega1281/include/atmega_pcint.h b/cpu/atmega1281/include/atmega_pcint.h new file mode 100644 index 0000000000..c0f6d6d28c --- /dev/null +++ b/cpu/atmega1281/include/atmega_pcint.h @@ -0,0 +1,16 @@ +#ifndef ATMEGA_PCINT_H +#define ATMEGA_PCINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ATMEGA_PCINT_MAP_PCINT0 GPIO_PIN(PORT_B, 0), GPIO_PIN(PORT_B, 1), GPIO_PIN(PORT_B, 2), GPIO_PIN(PORT_B, 3), GPIO_PIN(PORT_B, 4), GPIO_PIN(PORT_B, 5), GPIO_PIN(PORT_B, 6), GPIO_PIN(PORT_B, 7) +#define ATMEGA_PCINT_MAP_PCINT1 GPIO_PIN(PORT_E, 0), GPIO_PIN(PORT_J, 0), GPIO_PIN(PORT_J, 1), GPIO_PIN(PORT_J, 2), GPIO_PIN(PORT_J, 3), GPIO_PIN(PORT_J, 4), GPIO_PIN(PORT_J, 5), GPIO_PIN(PORT_J, 6) +#define ATMEGA_PCINT_MAP_PCINT2 GPIO_PIN(PORT_K, 0), GPIO_PIN(PORT_K, 1), GPIO_PIN(PORT_K, 2), GPIO_PIN(PORT_K, 3), GPIO_PIN(PORT_K, 4), GPIO_PIN(PORT_K, 5), GPIO_PIN(PORT_K, 6), GPIO_PIN(PORT_K, 7) + +#ifdef __cplusplus +} +#endif + +#endif /* ATMEGA_PCINT_H */ diff --git a/cpu/atmega1284p/Makefile.dep b/cpu/atmega1284p/Makefile.dep new file mode 100644 index 0000000000..41c8200b07 --- /dev/null +++ b/cpu/atmega1284p/Makefile.dep @@ -0,0 +1,6 @@ +# additional PCINTs for atmega1284p +ifneq (,$(filter atmega_pcint,$(USEMODULE))) + USEMODULE += atmega_pcint1 atmega_pcint2 atmega_pcint3 +endif + +include $(RIOTCPU)/atmega_common/Makefile.dep diff --git a/cpu/atmega1284p/Makefile.features b/cpu/atmega1284p/Makefile.features index 008260685b..caffb80aa2 100644 --- a/cpu/atmega1284p/Makefile.features +++ b/cpu/atmega1284p/Makefile.features @@ -1 +1,4 @@ --include $(RIOTCPU)/atmega_common/Makefile.features +# additional PCINTs for atmega1284p +FEATURES_PROVIDED += atmega_pcint1 atmega_pcint2 atmega_pcint3 + +include $(RIOTCPU)/atmega_common/Makefile.features diff --git a/cpu/atmega1284p/Makefile.include b/cpu/atmega1284p/Makefile.include index 985d14cf9e..6bd27a9343 100644 --- a/cpu/atmega1284p/Makefile.include +++ b/cpu/atmega1284p/Makefile.include @@ -4,5 +4,10 @@ USEMODULE += atmega_common RAM_LEN = 16K ROM_LEN = 128K +# expand atmega_pcint for atmega1284p +ifneq (,$(filter atmega_pcint,$(USEMODULE))) + USEMODULE += atmega_pcint1 atmega_pcint2 atmega_pcint3 +endif + # CPU depends on the atmega common module, so include it include $(RIOTCPU)/atmega_common/Makefile.include diff --git a/cpu/atmega1284p/include/atmega_pcint.h b/cpu/atmega1284p/include/atmega_pcint.h new file mode 100644 index 0000000000..36f30beb12 --- /dev/null +++ b/cpu/atmega1284p/include/atmega_pcint.h @@ -0,0 +1,17 @@ +#ifndef ATMEGA_PCINT_H +#define ATMEGA_PCINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ATMEGA_PCINT_MAP_PCINT0 GPIO_PIN(PORT_A, 0), GPIO_PIN(PORT_A, 1), GPIO_PIN(PORT_A, 2), GPIO_PIN(PORT_A, 3), GPIO_PIN(PORT_A, 4), GPIO_PIN(PORT_A, 5), GPIO_PIN(PORT_A, 6), GPIO_PIN(PORT_A, 7) +#define ATMEGA_PCINT_MAP_PCINT1 GPIO_PIN(PORT_B, 0), GPIO_PIN(PORT_B, 1), GPIO_PIN(PORT_B, 2), GPIO_PIN(PORT_B, 3), GPIO_PIN(PORT_B, 4), GPIO_PIN(PORT_B, 5), GPIO_PIN(PORT_B, 6), GPIO_PIN(PORT_B, 7) +#define ATMEGA_PCINT_MAP_PCINT2 GPIO_PIN(PORT_C, 0), GPIO_PIN(PORT_C, 1), GPIO_PIN(PORT_C, 2), GPIO_PIN(PORT_C, 3), GPIO_PIN(PORT_C, 4), GPIO_PIN(PORT_C, 5), GPIO_PIN(PORT_C, 6), GPIO_PIN(PORT_C, 7) +#define ATMEGA_PCINT_MAP_PCINT3 GPIO_PIN(PORT_D, 0), GPIO_PIN(PORT_D, 1), GPIO_PIN(PORT_D, 2), GPIO_PIN(PORT_D, 3), GPIO_PIN(PORT_D, 4), GPIO_PIN(PORT_D, 5), GPIO_PIN(PORT_D, 6), GPIO_PIN(PORT_D, 7) + +#ifdef __cplusplus +} +#endif + +#endif /* ATMEGA_PCINT_H */ diff --git a/cpu/atmega2560/Makefile.dep b/cpu/atmega2560/Makefile.dep new file mode 100644 index 0000000000..8a5262d271 --- /dev/null +++ b/cpu/atmega2560/Makefile.dep @@ -0,0 +1,6 @@ +# additional PCINTs for atmega2560 +ifneq (,$(filter atmega_pcint,$(USEMODULE))) + USEMODULE += atmega_pcint1 atmega_pcint2 +endif + +include $(RIOTCPU)/atmega_common/Makefile.dep diff --git a/cpu/atmega2560/Makefile.features b/cpu/atmega2560/Makefile.features index 008260685b..39270920c7 100644 --- a/cpu/atmega2560/Makefile.features +++ b/cpu/atmega2560/Makefile.features @@ -1 +1,3 @@ --include $(RIOTCPU)/atmega_common/Makefile.features +FEATURES_PROVIDED += atmega_pcint1 atmega_pcint2 + +include $(RIOTCPU)/atmega_common/Makefile.features diff --git a/cpu/atmega2560/Makefile.include b/cpu/atmega2560/Makefile.include index 16c500d37c..07c5448328 100644 --- a/cpu/atmega2560/Makefile.include +++ b/cpu/atmega2560/Makefile.include @@ -4,5 +4,10 @@ USEMODULE += atmega_common RAM_LEN = 8K ROM_LEN = 256K +# expand atmega_pcint with additional PCINTs for atmega2560 +ifneq (,$(filter atmega_pcint,$(USEMODULE))) + USEMODULE += atmega_pcint1 atmega_pcint2 +endif + # CPU depends on the atmega common module, so include it include $(RIOTCPU)/atmega_common/Makefile.include diff --git a/cpu/atmega2560/include/atmega_pcint.h b/cpu/atmega2560/include/atmega_pcint.h new file mode 100644 index 0000000000..c0f6d6d28c --- /dev/null +++ b/cpu/atmega2560/include/atmega_pcint.h @@ -0,0 +1,16 @@ +#ifndef ATMEGA_PCINT_H +#define ATMEGA_PCINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ATMEGA_PCINT_MAP_PCINT0 GPIO_PIN(PORT_B, 0), GPIO_PIN(PORT_B, 1), GPIO_PIN(PORT_B, 2), GPIO_PIN(PORT_B, 3), GPIO_PIN(PORT_B, 4), GPIO_PIN(PORT_B, 5), GPIO_PIN(PORT_B, 6), GPIO_PIN(PORT_B, 7) +#define ATMEGA_PCINT_MAP_PCINT1 GPIO_PIN(PORT_E, 0), GPIO_PIN(PORT_J, 0), GPIO_PIN(PORT_J, 1), GPIO_PIN(PORT_J, 2), GPIO_PIN(PORT_J, 3), GPIO_PIN(PORT_J, 4), GPIO_PIN(PORT_J, 5), GPIO_PIN(PORT_J, 6) +#define ATMEGA_PCINT_MAP_PCINT2 GPIO_PIN(PORT_K, 0), GPIO_PIN(PORT_K, 1), GPIO_PIN(PORT_K, 2), GPIO_PIN(PORT_K, 3), GPIO_PIN(PORT_K, 4), GPIO_PIN(PORT_K, 5), GPIO_PIN(PORT_K, 6), GPIO_PIN(PORT_K, 7) + +#ifdef __cplusplus +} +#endif + +#endif /* ATMEGA_PCINT_H */ diff --git a/cpu/atmega256rfr2/Makefile.dep b/cpu/atmega256rfr2/Makefile.dep new file mode 100644 index 0000000000..cc821137d3 --- /dev/null +++ b/cpu/atmega256rfr2/Makefile.dep @@ -0,0 +1,6 @@ +# additional PCINTs for atmega256rfr2 +ifneq (,$(filter atmega_pcint,$(USEMODULE))) + USEMODULE += atmega_pcint1 +endif + +include $(RIOTCPU)/atmega_common/Makefile.dep diff --git a/cpu/atmega256rfr2/Makefile.features b/cpu/atmega256rfr2/Makefile.features index f5ad466ab1..9e21413689 100644 --- a/cpu/atmega256rfr2/Makefile.features +++ b/cpu/atmega256rfr2/Makefile.features @@ -1,7 +1,9 @@ include $(RIOTCPU)/atmega_common/Makefile.features - # common feature are defined in atmega_common/Makefile.features # Only add Additional features +# additional PCINT for atmega256rfr2 +FEATURES_PROVIDED += atmega_pcint1 + # Various other features (if any) FEATURES_PROVIDED += periph_cpuid diff --git a/cpu/atmega256rfr2/Makefile.include b/cpu/atmega256rfr2/Makefile.include index c7e4d680ea..d573da94db 100644 --- a/cpu/atmega256rfr2/Makefile.include +++ b/cpu/atmega256rfr2/Makefile.include @@ -7,5 +7,10 @@ USEMODULE += periph RAM_LEN = 32K ROM_LEN = 256K +# expand atmega_pcint for atmega256rfr2 +ifneq (,$(filter atmega_pcint,$(USEMODULE))) + USEMODULE += atmega_pcint1 +endif + # CPU depends on the atmega common module, so include it include $(RIOTCPU)/atmega_common/Makefile.include diff --git a/cpu/atmega256rfr2/include/atmega_pcint.h b/cpu/atmega256rfr2/include/atmega_pcint.h new file mode 100644 index 0000000000..c25d43c169 --- /dev/null +++ b/cpu/atmega256rfr2/include/atmega_pcint.h @@ -0,0 +1,15 @@ +#ifndef ATMEGA_PCINT_H +#define ATMEGA_PCINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ATMEGA_PCINT_MAP_PCINT0 GPIO_PIN(PORT_B, 0), GPIO_PIN(PORT_B, 1), GPIO_PIN(PORT_B, 2), GPIO_PIN(PORT_B, 3), GPIO_PIN(PORT_B, 4), GPIO_PIN(PORT_B, 5), GPIO_PIN(PORT_B, 6), GPIO_PIN(PORT_B, 7) +#define ATMEGA_PCINT_MAP_PCINT1 GPIO_PIN(PORT_E, 0), GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF + +#ifdef __cplusplus +} +#endif + +#endif /* ATMEGA_PCINT_H */ diff --git a/cpu/atmega328p/Makefile.features b/cpu/atmega328p/Makefile.features index 008260685b..39270920c7 100644 --- a/cpu/atmega328p/Makefile.features +++ b/cpu/atmega328p/Makefile.features @@ -1 +1,3 @@ --include $(RIOTCPU)/atmega_common/Makefile.features +FEATURES_PROVIDED += atmega_pcint1 atmega_pcint2 + +include $(RIOTCPU)/atmega_common/Makefile.features diff --git a/cpu/atmega328p/Makefile.include b/cpu/atmega328p/Makefile.include index 20119203dd..6c2b1845b9 100644 --- a/cpu/atmega328p/Makefile.include +++ b/cpu/atmega328p/Makefile.include @@ -4,5 +4,10 @@ USEMODULE += atmega_common RAM_LEN = 2K ROM_LEN = 32K +# additional PCINTs for atmega328p +ifneq (,$(filter atmega_pcint,$(USEMODULE))) + USEMODULE += atmega_pcint1 atmega_pcint2 +endif + # CPU depends on the atmega common module, so include it include $(RIOTCPU)/atmega_common/Makefile.include diff --git a/cpu/atmega328p/include/atmega_pcint.h b/cpu/atmega328p/include/atmega_pcint.h new file mode 100644 index 0000000000..69b1d32ef8 --- /dev/null +++ b/cpu/atmega328p/include/atmega_pcint.h @@ -0,0 +1,16 @@ +#ifndef ATMEGA_PCINT_H +#define ATMEGA_PCINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ATMEGA_PCINT_MAP_PCINT0 GPIO_PIN(PORT_B, 0), GPIO_PIN(PORT_B, 1), GPIO_PIN(PORT_B, 2), GPIO_PIN(PORT_B, 3), GPIO_PIN(PORT_B, 4), GPIO_PIN(PORT_B, 5), GPIO_PIN(PORT_B, 6), GPIO_PIN(PORT_B, 7) +#define ATMEGA_PCINT_MAP_PCINT1 GPIO_PIN(PORT_C, 0), GPIO_PIN(PORT_C, 1), GPIO_PIN(PORT_C, 2), GPIO_PIN(PORT_C, 3), GPIO_PIN(PORT_C, 4), GPIO_PIN(PORT_C, 5), GPIO_PIN(PORT_C, 6), GPIO_UNDEF +#define ATMEGA_PCINT_MAP_PCINT2 GPIO_PIN(PORT_D, 0), GPIO_PIN(PORT_D, 1), GPIO_PIN(PORT_D, 2), GPIO_PIN(PORT_D, 3), GPIO_PIN(PORT_D, 4), GPIO_PIN(PORT_D, 5), GPIO_PIN(PORT_D, 6), GPIO_PIN(PORT_D, 7) + +#ifdef __cplusplus +} +#endif + +#endif /* ATMEGA_PCINT_H */ diff --git a/cpu/atmega32u4/Makefile.dep b/cpu/atmega32u4/Makefile.dep new file mode 100644 index 0000000000..ee10d78b29 --- /dev/null +++ b/cpu/atmega32u4/Makefile.dep @@ -0,0 +1,2 @@ +# common Makefile.dep expand the atmega_pcint pseudo module +include $(RIOTCPU)/atmega_common/Makefile.dep diff --git a/cpu/atmega32u4/Makefile.features b/cpu/atmega32u4/Makefile.features index 008260685b..e7319ab5c6 100644 --- a/cpu/atmega32u4/Makefile.features +++ b/cpu/atmega32u4/Makefile.features @@ -1 +1,2 @@ --include $(RIOTCPU)/atmega_common/Makefile.features +# atmega_common provides atmega_pcint0 +include $(RIOTCPU)/atmega_common/Makefile.features diff --git a/cpu/atmega32u4/include/atmega_pcint.h b/cpu/atmega32u4/include/atmega_pcint.h new file mode 100644 index 0000000000..0595cc4614 --- /dev/null +++ b/cpu/atmega32u4/include/atmega_pcint.h @@ -0,0 +1,14 @@ +#ifndef ATMEGA_PCINT_H +#define ATMEGA_PCINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ATMEGA_PCINT_MAP_PCINT0 GPIO_PIN(PORT_B, 0), GPIO_PIN(PORT_B, 1), GPIO_PIN(PORT_B, 2), GPIO_PIN(PORT_B, 3), GPIO_PIN(PORT_B, 4), GPIO_PIN(PORT_B, 5), GPIO_PIN(PORT_B, 6), GPIO_PIN(PORT_B, 7) + +#ifdef __cplusplus +} +#endif + +#endif /* ATMEGA_PCINT_H */ diff --git a/cpu/atmega_common/Makefile.dep b/cpu/atmega_common/Makefile.dep new file mode 100644 index 0000000000..efee68f6f9 --- /dev/null +++ b/cpu/atmega_common/Makefile.dep @@ -0,0 +1,24 @@ +# expand atmega_pcint module +ifneq (,$(filter atmega_pcint,$(USEMODULE))) + USEMODULE += atmega_pcint0 +endif + +# feature for atmega_pcint0 module +ifneq (,$(filter atmega_pcint0,$(USEMODULE))) + FEATURES_REQUIRED += atmega_pcint0 +endif + +# feature for atmega_pcint1 module +ifneq (,$(filter atmega_pcint1,$(USEMODULE))) + FEATURES_REQUIRED += atmega_pcint1 +endif + +# feature for atmega_pcint2 module +ifneq (,$(filter atmega_pcint2,$(USEMODULE))) + FEATURES_REQUIRED += atmega_pcint2 +endif + +# feature for atmega_pcint3 module +ifneq (,$(filter atmega_pcint3,$(USEMODULE))) + FEATURES_REQUIRED += atmega_pcint3 +endif diff --git a/cpu/atmega_common/Makefile.features b/cpu/atmega_common/Makefile.features index 2adc58bc7b..18cbcf576a 100644 --- a/cpu/atmega_common/Makefile.features +++ b/cpu/atmega_common/Makefile.features @@ -1,2 +1,4 @@ FEATURES_PROVIDED += periph_eeprom FEATURES_PROVIDED += periph_pm + +FEATURES_PROVIDED += atmega_pcint0 diff --git a/cpu/atmega_common/Makefile.include b/cpu/atmega_common/Makefile.include index 5c02288d19..45ddb895dd 100644 --- a/cpu/atmega_common/Makefile.include +++ b/cpu/atmega_common/Makefile.include @@ -6,4 +6,34 @@ export INCLUDES += -I$(RIOTCPU)/atmega_common/include \ # avr libc needs some RIOT-specific support code USEMODULE += avr_libc_extra +PSEUDOMODULES += atmega_pcint +PSEUDOMODULES += atmega_pcint% + +# expand atmega_pcint module +# atmega16u4 only features atmega_pcint0, therefore additional pseudomodules +# are activated in each CPU's Makefile.include +ifneq (,$(filter atmega_pcint,$(USEMODULE))) + USEMODULE += atmega_pcint0 +endif + +# feature for atmega_pcint0 module +ifneq (,$(filter atmega_pcint0,$(USEMODULE))) + FEATURES_REQUIRED += atmega_pcint0 +endif + +# feature for atmega_pcint1 module +ifneq (,$(filter atmega_pcint1,$(USEMODULE))) + FEATURES_REQUIRED += atmega_pcint1 +endif + +# feature for atmega_pcint2 module +ifneq (,$(filter atmega_pcint2,$(USEMODULE))) + FEATURES_REQUIRED += atmega_pcint2 +endif + +# feature for atmega_pcint3 module +ifneq (,$(filter atmega_pcint3,$(USEMODULE))) + FEATURES_REQUIRED += atmega_pcint3 +endif + include $(RIOTMAKE)/arch/atmega.inc.mk diff --git a/cpu/atmega_common/periph/gpio.c b/cpu/atmega_common/periph/gpio.c index 08997c88ea..51c5286220 100644 --- a/cpu/atmega_common/periph/gpio.c +++ b/cpu/atmega_common/periph/gpio.c @@ -19,6 +19,9 @@ * @author René Herthel * @author Francisco Acosta * @author Laurent Navet + * @author Robert Hartung + * @author Torben Petersen + * @author Marian Buschsieweke * * @} */ @@ -28,10 +31,14 @@ #include #include "cpu.h" +#include "board.h" #include "periph/gpio.h" #include "periph_conf.h" #include "periph_cpu.h" +#define ENABLE_DEBUG (0) +#include "debug.h" + #define GPIO_BASE_PORT_A (0x20) #define GPIO_OFFSET_PORT_H (0xCB) #define GPIO_OFFSET_PIN_PORT (0x02) @@ -42,6 +49,7 @@ * @brief Define GPIO interruptions for an specific atmega CPU, by default * 2 (for small atmega CPUs) */ + #if defined(INT7_vect) #define GPIO_EXT_INT_NUMOF (8U) #elif defined(INT6_vect) @@ -59,7 +67,105 @@ #endif static gpio_isr_ctx_t config[GPIO_EXT_INT_NUMOF]; -#endif /* MODULE_PERIPH_GPIO_IRQ */ + +/** + * @brief detects ammount 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 +#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 */ + +#ifdef MODULE_ATMEGA_PCINT1 +#ifndef 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 */ + +#ifdef MODULE_ATMEGA_PCINT2 +#ifndef 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 */ + +#ifdef MODULE_ATMEGA_PCINT3 +#ifndef 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 */ + +#define PCINT_NUM_BANKS (_COUNTER3) + +/** + * @brief stores the last pcint state of each port + */ +static uint8_t pcint_state[PCINT_NUM_BANKS]; + +/** + * @brief stores all cb and args for all defined pcint. + */ +typedef struct { + gpio_flank_t flank; /**< type of interrupt the flank should be triggered on */ + gpio_cb_t cb; /**< interrupt callback */ + void *arg; /**< optional argument */ +} gpio_isr_ctx_pcint_t; + +/** + * @brief + */ +static const gpio_t pcint_mapping[] = { +#ifdef PCINT0_IDX + ATMEGA_PCINT_MAP_PCINT0, +#endif /* PCINT0_IDX */ +#ifdef PCINT1_IDX + ATMEGA_PCINT_MAP_PCINT1, +#endif /* PCINT1_IDX */ +#ifdef PCINT2_IDX + ATMEGA_PCINT_MAP_PCINT2, +#endif /* PCINT2_IDX */ +#ifdef PCINT3_IDX + ATMEGA_PCINT_MAP_PCINT3, +#endif /* PCINT3_IDX */ +}; +/** + * @brief + */ +static gpio_isr_ctx_pcint_t pcint_config[8 * PCINT_NUM_BANKS]; +#endif /* MODULE_ATMEGA_PCINTn */ + +#endif /* MODULE_PERIPH_GPIO_IRQ */ /** * @brief Extract the pin number of the given pin @@ -115,6 +221,7 @@ static inline uint16_t _pin_addr(gpio_t pin) int gpio_init(gpio_t pin, gpio_mode_t mode) { uint8_t pin_mask = (1 << _pin_num(pin)); + switch (mode) { case GPIO_OUT: _SFR_MEM8(_ddr_addr(pin)) |= pin_mask; @@ -195,8 +302,82 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, return -1; } - /* not a valid interrupt pin */ + /* not a valid interrupt pin. Set as pcint instead if pcints are enabled */ if (int_num < 0) { + /* If pin change interrupts are enabled, enable mask and interrupt */ + #ifdef PCINT_NUM_BANKS + int8_t offset = -1; + uint8_t pin_num = _pin_num(pin); + + for (unsigned i = 0; + i < sizeof(pcint_mapping) / sizeof(pcint_mapping[0]); 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(_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 -1; } @@ -219,12 +400,12 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, EICRA &= ~(0x3 << (int_num * 2)); EICRA |= (flank << (int_num * 2)); } -#if defined(EICRB) + #if defined(EICRB) else { EICRB &= ~(0x3 << ((int_num % 4) * 2)); EICRB |= (flank << ((int_num % 4) * 2)); } -#endif + #endif /* set callback */ config[int_num].cb = cb; @@ -254,6 +435,72 @@ static inline void irq_handler(uint8_t int_num) __exit_isr(); } +#ifdef PCINT_NUM_BANKS +/* inline function that is used by the PCINT ISR */ +static inline void pcint_handler(uint8_t bank, uint8_t enabled_pcints) +{ + __enter_isr(); + /* Find right item */ + uint8_t idx = 0; + + while (enabled_pcints > 0) { + /* check if this pin is enabled & has changed */ + if (enabled_pcints & 0x1) { + /* get pin from mapping (assumes 8 entries per bank!) */ + gpio_t pin = pcint_mapping[bank * 8 + idx]; + /* re-construct mask from pin */ + uint8_t pin_mask = (1 << (_pin_num(pin))); + uint8_t idx_mask = (1 << idx); + uint8_t port_value = (_SFR_MEM8(_pin_addr( pin ))); + uint8_t pin_value = ((port_value & pin_mask) != 0); + uint8_t old_state = ((pcint_state[bank] & idx_mask) != 0); + gpio_isr_ctx_pcint_t *conf = &pcint_config[bank * 8 + idx]; + if (old_state != pin_value) { + pcint_state[bank] ^= idx_mask; + if ((conf->flank == GPIO_BOTH || + (pin_value && conf->flank == GPIO_RISING) || + (!pin_value && conf->flank == GPIO_FALLING))) { + /* execute callback routine */ + conf->cb(conf->arg); + } + } + } + enabled_pcints = enabled_pcints >> 1; + idx++; + } + + __exit_isr(); +} +#if defined(PCINT0_IDX) +ISR(PCINT0_vect, ISR_BLOCK) +{ + pcint_handler(PCINT0_IDX, PCMSK0); +} +#endif /* PCINT0_IDX */ + +#if defined(PCINT1_IDX) +ISR(PCINT1_vect, ISR_BLOCK) +{ + pcint_handler(PCINT1_IDX, PCMSK1); +} +#endif /* PCINT1_IDX */ + +#if defined(PCINT2_IDX) +ISR(PCINT2_vect, ISR_BLOCK) +{ + pcint_handler(PCINT2_IDX, PCMSK2); +} +#endif /* PCINT2_IDX */ + +#if defined(PCINT3_IDX) +ISR(PCINT3_vect, ISR_BLOCK) +{ + pcint_handler(PCINT3_IDX, PCMSK3); +} +#endif /* PCINT3_IDX */ + +#endif /* GPIO_PC_INT_NUMOF */ + ISR(INT0_vect, ISR_BLOCK) { irq_handler(0); /**< predefined interrupt pin */