Merge pull request #11122 from ibr-cm/hartung/atmega-pin-change-interrupt-pseudomodules
cpu/atmega_common: pseudomodule-based pin change interrupt implementation
This commit is contained in:
commit
e612d3d71b
@ -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
|
||||
|
||||
16
boards/arduino-mega2560/include/atmega_pcint.h
Normal file
16
boards/arduino-mega2560/include/atmega_pcint.h
Normal file
@ -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 */
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
17
boards/common/atmega/doc.txt
Normal file
17
boards/common/atmega/doc.txt
Normal file
@ -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.
|
||||
*/
|
||||
@ -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.
|
||||
|
||||
*/
|
||||
|
||||
@ -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.
|
||||
|
||||
*/
|
||||
|
||||
@ -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.
|
||||
|
||||
*/
|
||||
|
||||
@ -1 +1,3 @@
|
||||
-include $(RIOTCPU)/atmega_common/Makefile.features
|
||||
FEATURES_PROVIDED += atmega_pcint1 atmega_pcint2
|
||||
|
||||
include $(RIOTCPU)/atmega_common/Makefile.features
|
||||
|
||||
@ -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
|
||||
|
||||
16
cpu/atmega1281/include/atmega_pcint.h
Normal file
16
cpu/atmega1281/include/atmega_pcint.h
Normal file
@ -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 */
|
||||
6
cpu/atmega1284p/Makefile.dep
Normal file
6
cpu/atmega1284p/Makefile.dep
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
17
cpu/atmega1284p/include/atmega_pcint.h
Normal file
17
cpu/atmega1284p/include/atmega_pcint.h
Normal file
@ -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 */
|
||||
6
cpu/atmega2560/Makefile.dep
Normal file
6
cpu/atmega2560/Makefile.dep
Normal file
@ -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
|
||||
@ -1 +1,3 @@
|
||||
-include $(RIOTCPU)/atmega_common/Makefile.features
|
||||
FEATURES_PROVIDED += atmega_pcint1 atmega_pcint2
|
||||
|
||||
include $(RIOTCPU)/atmega_common/Makefile.features
|
||||
|
||||
@ -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
|
||||
|
||||
16
cpu/atmega2560/include/atmega_pcint.h
Normal file
16
cpu/atmega2560/include/atmega_pcint.h
Normal file
@ -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 */
|
||||
6
cpu/atmega256rfr2/Makefile.dep
Normal file
6
cpu/atmega256rfr2/Makefile.dep
Normal file
@ -0,0 +1,6 @@
|
||||
# additional PCINTs for atmega256rfr2
|
||||
ifneq (,$(filter atmega_pcint,$(USEMODULE)))
|
||||
USEMODULE += atmega_pcint1
|
||||
endif
|
||||
|
||||
include $(RIOTCPU)/atmega_common/Makefile.dep
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
15
cpu/atmega256rfr2/include/atmega_pcint.h
Normal file
15
cpu/atmega256rfr2/include/atmega_pcint.h
Normal file
@ -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 */
|
||||
@ -1 +1,3 @@
|
||||
-include $(RIOTCPU)/atmega_common/Makefile.features
|
||||
FEATURES_PROVIDED += atmega_pcint1 atmega_pcint2
|
||||
|
||||
include $(RIOTCPU)/atmega_common/Makefile.features
|
||||
|
||||
@ -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
|
||||
|
||||
16
cpu/atmega328p/include/atmega_pcint.h
Normal file
16
cpu/atmega328p/include/atmega_pcint.h
Normal file
@ -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 */
|
||||
2
cpu/atmega32u4/Makefile.dep
Normal file
2
cpu/atmega32u4/Makefile.dep
Normal file
@ -0,0 +1,2 @@
|
||||
# common Makefile.dep expand the atmega_pcint pseudo module
|
||||
include $(RIOTCPU)/atmega_common/Makefile.dep
|
||||
@ -1 +1,2 @@
|
||||
-include $(RIOTCPU)/atmega_common/Makefile.features
|
||||
# atmega_common provides atmega_pcint0
|
||||
include $(RIOTCPU)/atmega_common/Makefile.features
|
||||
|
||||
14
cpu/atmega32u4/include/atmega_pcint.h
Normal file
14
cpu/atmega32u4/include/atmega_pcint.h
Normal file
@ -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 */
|
||||
24
cpu/atmega_common/Makefile.dep
Normal file
24
cpu/atmega_common/Makefile.dep
Normal file
@ -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
|
||||
@ -1,2 +1,4 @@
|
||||
FEATURES_PROVIDED += periph_eeprom
|
||||
FEATURES_PROVIDED += periph_pm
|
||||
|
||||
FEATURES_PROVIDED += atmega_pcint0
|
||||
|
||||
@ -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
|
||||
|
||||
@ -19,6 +19,9 @@
|
||||
* @author René Herthel <rene-herthel@outlook.de>
|
||||
* @author Francisco Acosta <francisco.acosta@inria.fr>
|
||||
* @author Laurent Navet <laurent.navet@gmail.com>
|
||||
* @author Robert Hartung <hartung@ibr.cs.tu-bs.de>
|
||||
* @author Torben Petersen <petersen@ibr.cs.tu-bs.de>
|
||||
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
@ -28,10 +31,14 @@
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#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,6 +67,104 @@
|
||||
#endif
|
||||
|
||||
static gpio_isr_ctx_t config[GPIO_EXT_INT_NUMOF];
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
|
||||
/**
|
||||
@ -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 */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user