899 lines
25 KiB
C
Executable File
899 lines
25 KiB
C
Executable File
/*
|
|
Copyright (c) 2014-2018 NicoHood
|
|
See the readme for credit to other people.
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
*/
|
|
|
|
// Include Guard
|
|
#pragma once
|
|
|
|
// Software Version
|
|
#define PCINT_VERSION 126
|
|
|
|
#include <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
|
|
#ifdef ARDUINO
|
|
#include "Arduino.h"
|
|
|
|
#ifndef ARDUINO_ARCH_AVR
|
|
#error This library can only be used with AVR
|
|
#endif
|
|
|
|
#else
|
|
|
|
#ifndef LOW
|
|
#define LOW 0x0
|
|
#endif
|
|
#ifndef CHANGE
|
|
#define CHANGE 0x1
|
|
#endif
|
|
#ifndef FALLING
|
|
#define FALLING 0x2
|
|
#endif
|
|
#ifndef RISING
|
|
#define RISING 0x3
|
|
#endif
|
|
|
|
#endif
|
|
|
|
//================================================================================
|
|
// General Helper Definitions and Mappings
|
|
//================================================================================
|
|
|
|
// Settings and Board definitions are seperated to get an better overview.
|
|
// The order and position of the inclusion is important!
|
|
#include "PinChangeInterruptSettings.h"
|
|
#include "PinChangeInterruptBoards.h"
|
|
#include "PinChangeInterruptPins.h"
|
|
|
|
#if !PCINT_NUM_USED_PORTS
|
|
#error Please enable at least one PCINT port and pin!
|
|
#endif
|
|
|
|
// manually include cpp files to save flash if only 1 ISR is present
|
|
// it includes all ISR files but only the 1 available ISR will/can be compiled
|
|
#if (PCINT_NUM_USED_PORTS == 1)
|
|
#ifndef PCINT_COMPILE_ENABLED_ISR
|
|
#define PCINT_COMPILE_ENABLED_ISR
|
|
#endif
|
|
#endif
|
|
|
|
//================================================================================
|
|
// Makro Definitions
|
|
//================================================================================
|
|
|
|
// generates the callback for easier reordering in Settings
|
|
#define PCINT_MACRO_BRACKETS ()
|
|
#define PCINT_MACRO_TRUE == true)
|
|
#define PCINT_CALLBACK(bit, pcint) \
|
|
if (PCINT_USE_PCINT ## pcint PCINT_MACRO_TRUE \
|
|
if (trigger & (1 << bit)) \
|
|
PinChangeInterruptEventPCINT ## pcint PCINT_MACRO_BRACKETS
|
|
|
|
// definition used by the user to create custom LowLevel PCINT Events
|
|
#define PinChangeInterruptEvent_Wrapper(n) PinChangeInterruptEventPCINT ## n
|
|
#define PinChangeInterruptEvent(n) PinChangeInterruptEvent_Wrapper(n)
|
|
|
|
// missing 1.0.6 definition workaround
|
|
#ifndef NOT_AN_INTERRUPT
|
|
#define NOT_AN_INTERRUPT -1
|
|
#endif
|
|
|
|
// convert a normal pin to its PCINT number (0 - max 23), used by the user
|
|
// calculates the pin by the Arduino definitions
|
|
#if defined(PCIE0)
|
|
#define digitalPinToPinChangeInterrupt(p) (digitalPinToPCICR(p) ? ((8 * (digitalPinToPCICRbit(p) - PCIE0)) + digitalPinToPCMSKbit(p)) : NOT_AN_INTERRUPT)
|
|
#elif defined(PCIE)
|
|
#define digitalPinToPinChangeInterrupt(p) (digitalPinToPCICR(p) ? ((8 * (digitalPinToPCICRbit(p) - PCIE)) + digitalPinToPCMSKbit(p)) : NOT_AN_INTERRUPT)
|
|
#else
|
|
#error MCU has no such a register
|
|
#endif
|
|
|
|
// alias for shorter writing
|
|
#define PCINTEvent(n) PinChangeInterruptEvent_Wrapper(n)
|
|
#define digitalPinToPCINT digitalPinToPinChangeInterrupt
|
|
#define attachPCINT attachPinChangeInterrupt
|
|
#define enablePCINT enablePinChangeInterrupt
|
|
#define detachPCINT detachPinChangeInterrupt
|
|
#define disablePCINT disablePinChangeInterrupt
|
|
#define getPCINTTrigger getPinChangeInterruptTrigger
|
|
|
|
//================================================================================
|
|
// Function Prototypes + Variables
|
|
//================================================================================
|
|
|
|
// typedef for our callback function pointers
|
|
typedef void(*callback)(void);
|
|
|
|
// useless function for weak implemented/not used functions, extern c needed for the alias
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
void pcint_null_callback(void);
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
void PinChangeInterruptEventPCINT0(void);
|
|
void PinChangeInterruptEventPCINT1(void);
|
|
void PinChangeInterruptEventPCINT2(void);
|
|
void PinChangeInterruptEventPCINT3(void);
|
|
void PinChangeInterruptEventPCINT4(void);
|
|
void PinChangeInterruptEventPCINT5(void);
|
|
void PinChangeInterruptEventPCINT6(void);
|
|
void PinChangeInterruptEventPCINT7(void);
|
|
void PinChangeInterruptEventPCINT8(void);
|
|
void PinChangeInterruptEventPCINT9(void);
|
|
void PinChangeInterruptEventPCINT10(void);
|
|
void PinChangeInterruptEventPCINT11(void);
|
|
void PinChangeInterruptEventPCINT12(void);
|
|
void PinChangeInterruptEventPCINT13(void);
|
|
void PinChangeInterruptEventPCINT14(void);
|
|
void PinChangeInterruptEventPCINT15(void);
|
|
void PinChangeInterruptEventPCINT16(void);
|
|
void PinChangeInterruptEventPCINT17(void);
|
|
void PinChangeInterruptEventPCINT18(void);
|
|
void PinChangeInterruptEventPCINT19(void);
|
|
void PinChangeInterruptEventPCINT20(void);
|
|
void PinChangeInterruptEventPCINT21(void);
|
|
void PinChangeInterruptEventPCINT22(void);
|
|
void PinChangeInterruptEventPCINT23(void);
|
|
void PinChangeInterruptEventPCINT24(void);
|
|
void PinChangeInterruptEventPCINT25(void);
|
|
void PinChangeInterruptEventPCINT26(void);
|
|
void PinChangeInterruptEventPCINT27(void);
|
|
void PinChangeInterruptEventPCINT28(void);
|
|
void PinChangeInterruptEventPCINT29(void);
|
|
void PinChangeInterruptEventPCINT30(void);
|
|
void PinChangeInterruptEventPCINT31(void);
|
|
|
|
extern uint8_t oldPorts[PCINT_NUM_USED_PORTS];
|
|
extern uint8_t fallingPorts[PCINT_NUM_USED_PORTS];
|
|
extern uint8_t risingPorts[PCINT_NUM_USED_PORTS];
|
|
|
|
|
|
static inline uint8_t getArrayPosPCINT(uint8_t pcintPort) __attribute__((always_inline));
|
|
uint8_t getArrayPosPCINT(uint8_t pcintPort) {
|
|
/*
|
|
Maps the port to the array.
|
|
This is needed since you can deactivate ports
|
|
and the array will dynamically resize to save ram.
|
|
|
|
The function does not need that much flash since the if and else
|
|
are known at compile time, so the compiler removes all the complex logic.
|
|
The return is is the input if all pins are activated for example.
|
|
That's why the function is inline.
|
|
*/
|
|
|
|
if (PCINT_NUM_USED_PORTS == 1) {
|
|
// only the first element is used for a single port
|
|
return 0;
|
|
}
|
|
else if (PCINT_NUM_USED_PORTS == PCINT_NUM_PORTS) {
|
|
// use all ports and down remap the array position.
|
|
return pcintPort;
|
|
}
|
|
else if (PCINT_NUM_PORTS - PCINT_NUM_USED_PORTS == 1) {
|
|
// one port is not used
|
|
if (PCINT_USE_PORT0 == 0) {
|
|
// first port is not used, decrease all port numbers
|
|
return (pcintPort - 1);
|
|
}
|
|
else if (PCINT_HAS_PORT3 == 0) {
|
|
// 3 ports (standard)
|
|
if (PCINT_USE_PORT2 == 0) {
|
|
// last port not used, no mapping needed
|
|
return pcintPort;
|
|
}
|
|
else {
|
|
// worst case, port in the middle not used, remap
|
|
return ((pcintPort >> 1) & 0x01);
|
|
//if (pcintPort == 0) return 0;
|
|
//else return 1;
|
|
}
|
|
}
|
|
else {
|
|
// 4 ports (special case for a few AVRs)
|
|
if (PCINT_USE_PORT3 == 0) {
|
|
// last port not used, no mapping needed
|
|
return pcintPort;
|
|
}
|
|
else {
|
|
// worst case, one of two ports in the middle not used, remap
|
|
if (PCINT_USE_PORT1 == 0) {
|
|
// port1 not used, mapping needed
|
|
if (pcintPort == 0)
|
|
return 0;
|
|
else
|
|
return pcintPort - 1;
|
|
}
|
|
else if (PCINT_USE_PORT2 == 0) {
|
|
// port2 not used, mapping needed
|
|
if (pcintPort == 3)
|
|
return 2;
|
|
else
|
|
return pcintPort;
|
|
}
|
|
}
|
|
}
|
|
|
|
// use all ports and down remap the array position.
|
|
return pcintPort;
|
|
}
|
|
else if (PCINT_NUM_PORTS - PCINT_NUM_USED_PORTS == 2) {
|
|
if (PCINT_USE_PORT2 == 0 && PCINT_USE_PORT3 == 0) {
|
|
// no need for mapping
|
|
return pcintPort;
|
|
}
|
|
else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT3 == 0) {
|
|
// 1 offset
|
|
return (pcintPort - 1);
|
|
}
|
|
else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT1 == 0) {
|
|
// 2 offset
|
|
return (pcintPort - 2);
|
|
}
|
|
else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT2 == 0) {
|
|
// 2 -> 1
|
|
return (pcintPort >> 1);
|
|
}
|
|
else if (PCINT_USE_PORT1 == 0 && PCINT_USE_PORT2 == 0) {
|
|
// 3 -> 1
|
|
return (pcintPort >> 1);
|
|
}
|
|
else if (PCINT_USE_PORT1 == 0 && PCINT_USE_PORT3 == 0) {
|
|
// 3 -> 1, 1 -> 0
|
|
return (pcintPort >> 1);
|
|
}
|
|
}
|
|
|
|
// error
|
|
return 0;
|
|
}
|
|
|
|
//================================================================================
|
|
// Attach Function (partly inlined)
|
|
//================================================================================
|
|
|
|
void enablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask, const uint8_t arrayPos);
|
|
void attachPinChangeInterrupt0(void);
|
|
void attachPinChangeInterrupt1(void);
|
|
void attachPinChangeInterrupt2(void);
|
|
void attachPinChangeInterrupt3(void);
|
|
|
|
#if defined(PCINT_API)
|
|
|
|
/*
|
|
for (int i = 0; i < 32; i++) {
|
|
Serial.print("#if (PCINT_USE_PCINT");
|
|
Serial.print(i);
|
|
Serial.println(" == true)");
|
|
Serial.print("extern volatile callback callbackPCINT");
|
|
Serial.print(i);
|
|
Serial.println(";");
|
|
Serial.println("#endif");
|
|
}
|
|
*/
|
|
#if (PCINT_USE_PCINT0 == true)
|
|
extern volatile callback callbackPCINT0;
|
|
#endif
|
|
#if (PCINT_USE_PCINT1 == true)
|
|
extern volatile callback callbackPCINT1;
|
|
#endif
|
|
#if (PCINT_USE_PCINT2 == true)
|
|
extern volatile callback callbackPCINT2;
|
|
#endif
|
|
#if (PCINT_USE_PCINT3 == true)
|
|
extern volatile callback callbackPCINT3;
|
|
#endif
|
|
#if (PCINT_USE_PCINT4 == true)
|
|
extern volatile callback callbackPCINT4;
|
|
#endif
|
|
#if (PCINT_USE_PCINT5 == true)
|
|
extern volatile callback callbackPCINT5;
|
|
#endif
|
|
#if (PCINT_USE_PCINT6 == true)
|
|
extern volatile callback callbackPCINT6;
|
|
#endif
|
|
#if (PCINT_USE_PCINT7 == true)
|
|
extern volatile callback callbackPCINT7;
|
|
#endif
|
|
#if (PCINT_USE_PCINT8 == true)
|
|
extern volatile callback callbackPCINT8;
|
|
#endif
|
|
#if (PCINT_USE_PCINT9 == true)
|
|
extern volatile callback callbackPCINT9;
|
|
#endif
|
|
#if (PCINT_USE_PCINT10 == true)
|
|
extern volatile callback callbackPCINT10;
|
|
#endif
|
|
#if (PCINT_USE_PCINT11 == true)
|
|
extern volatile callback callbackPCINT11;
|
|
#endif
|
|
#if (PCINT_USE_PCINT12 == true)
|
|
extern volatile callback callbackPCINT12;
|
|
#endif
|
|
#if (PCINT_USE_PCINT13 == true)
|
|
extern volatile callback callbackPCINT13;
|
|
#endif
|
|
#if (PCINT_USE_PCINT14 == true)
|
|
extern volatile callback callbackPCINT14;
|
|
#endif
|
|
#if (PCINT_USE_PCINT15 == true)
|
|
extern volatile callback callbackPCINT15;
|
|
#endif
|
|
#if (PCINT_USE_PCINT16 == true)
|
|
extern volatile callback callbackPCINT16;
|
|
#endif
|
|
#if (PCINT_USE_PCINT17 == true)
|
|
extern volatile callback callbackPCINT17;
|
|
#endif
|
|
#if (PCINT_USE_PCINT18 == true)
|
|
extern volatile callback callbackPCINT18;
|
|
#endif
|
|
#if (PCINT_USE_PCINT19 == true)
|
|
extern volatile callback callbackPCINT19;
|
|
#endif
|
|
#if (PCINT_USE_PCINT20 == true)
|
|
extern volatile callback callbackPCINT20;
|
|
#endif
|
|
#if (PCINT_USE_PCINT21 == true)
|
|
extern volatile callback callbackPCINT21;
|
|
#endif
|
|
#if (PCINT_USE_PCINT22 == true)
|
|
extern volatile callback callbackPCINT22;
|
|
#endif
|
|
#if (PCINT_USE_PCINT23 == true)
|
|
extern volatile callback callbackPCINT23;
|
|
#endif
|
|
#if (PCINT_USE_PCINT24 == true)
|
|
extern volatile callback callbackPCINT24;
|
|
#endif
|
|
#if (PCINT_USE_PCINT25 == true)
|
|
extern volatile callback callbackPCINT25;
|
|
#endif
|
|
#if (PCINT_USE_PCINT26 == true)
|
|
extern volatile callback callbackPCINT26;
|
|
#endif
|
|
#if (PCINT_USE_PCINT27 == true)
|
|
extern volatile callback callbackPCINT27;
|
|
#endif
|
|
#if (PCINT_USE_PCINT28 == true)
|
|
extern volatile callback callbackPCINT28;
|
|
#endif
|
|
#if (PCINT_USE_PCINT29 == true)
|
|
extern volatile callback callbackPCINT29;
|
|
#endif
|
|
#if (PCINT_USE_PCINT30 == true)
|
|
extern volatile callback callbackPCINT30;
|
|
#endif
|
|
#if (PCINT_USE_PCINT31 == true)
|
|
extern volatile callback callbackPCINT31;
|
|
#endif
|
|
|
|
/*
|
|
for (int i = 0; i < 32; i++) {
|
|
Serial.print("#if (PCINT_USE_PCINT");
|
|
Serial.print(i);
|
|
Serial.println(" == true)");
|
|
Serial.print("if (pcintNum == ");
|
|
Serial.print(i);
|
|
Serial.println(")");
|
|
Serial.print("callbackPCINT");
|
|
Serial.print(i);
|
|
Serial.println(" = userFunc;");
|
|
Serial.println("#endif");
|
|
}
|
|
*/
|
|
|
|
// API attach function
|
|
static inline void attachPinChangeInterrupt(const uint8_t pcintNum, void(*userFunc)(void), const uint8_t mode) __attribute__((always_inline));
|
|
void attachPinChangeInterrupt(const uint8_t pcintNum, void(*userFunc)(void), const uint8_t mode) {
|
|
#else // no API attach function
|
|
static inline void attachPinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) __attribute__((always_inline));
|
|
void attachPinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) {
|
|
#endif // PCINT_API
|
|
|
|
// check if pcint is a valid pcint, exclude deactivated ports
|
|
uint8_t pcintPort = pcintNum / 8;
|
|
uint8_t pcintBit = pcintNum % 8;
|
|
|
|
// port 0
|
|
if (pcintPort == 0 && PCINT_USE_PORT0 == true) {
|
|
// use fake functions to make the ISRs compile with .a linkage
|
|
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
|
|
attachPinChangeInterrupt0();
|
|
#endif
|
|
|
|
// attache the function pointers for the API
|
|
#if defined(PCINT_API)
|
|
#if (PCINT_USE_PCINT0 == true)
|
|
if (pcintNum == 0)
|
|
callbackPCINT0 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT1 == true)
|
|
if (pcintNum == 1)
|
|
callbackPCINT1 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT2 == true)
|
|
if (pcintNum == 2)
|
|
callbackPCINT2 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT3 == true)
|
|
if (pcintNum == 3)
|
|
callbackPCINT3 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT4 == true)
|
|
if (pcintNum == 4)
|
|
callbackPCINT4 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT5 == true)
|
|
if (pcintNum == 5)
|
|
callbackPCINT5 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT6 == true)
|
|
if (pcintNum == 6)
|
|
callbackPCINT6 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT7 == true)
|
|
if (pcintNum == 7)
|
|
callbackPCINT7 = userFunc;
|
|
#endif
|
|
#endif // PCINT_API
|
|
}
|
|
|
|
// port 1
|
|
else if (pcintPort == 1 && PCINT_USE_PORT1 == true) {
|
|
// use fake functions to make the ISRs compile with .a linkage
|
|
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
|
|
attachPinChangeInterrupt1();
|
|
#endif
|
|
|
|
// attache the function pointers for the API
|
|
#if defined(PCINT_API)
|
|
#if (PCINT_USE_PCINT8 == true)
|
|
if (pcintNum == 8)
|
|
callbackPCINT8 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT9 == true)
|
|
if (pcintNum == 9)
|
|
callbackPCINT9 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT10 == true)
|
|
if (pcintNum == 10)
|
|
callbackPCINT10 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT11 == true)
|
|
if (pcintNum == 11)
|
|
callbackPCINT11 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT12 == true)
|
|
if (pcintNum == 12)
|
|
callbackPCINT12 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT13 == true)
|
|
if (pcintNum == 13)
|
|
callbackPCINT13 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT14 == true)
|
|
if (pcintNum == 14)
|
|
callbackPCINT14 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT15 == true)
|
|
if (pcintNum == 15)
|
|
callbackPCINT15 = userFunc;
|
|
#endif
|
|
#endif // PCINT_API
|
|
}
|
|
|
|
// port 2
|
|
else if (pcintPort == 2 && PCINT_USE_PORT2 == true) {
|
|
// use fake functions to make the ISRs compile with .a linkage
|
|
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
|
|
attachPinChangeInterrupt2();
|
|
#endif
|
|
// attache the function pointers for the API
|
|
#if defined(PCINT_API)
|
|
#if (PCINT_USE_PCINT16 == true)
|
|
if (pcintNum == 16)
|
|
callbackPCINT16 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT17 == true)
|
|
if (pcintNum == 17)
|
|
callbackPCINT17 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT18 == true)
|
|
if (pcintNum == 18)
|
|
callbackPCINT18 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT19 == true)
|
|
if (pcintNum == 19)
|
|
callbackPCINT19 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT20 == true)
|
|
if (pcintNum == 20)
|
|
callbackPCINT20 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT21 == true)
|
|
if (pcintNum == 21)
|
|
callbackPCINT21 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT22 == true)
|
|
if (pcintNum == 22)
|
|
callbackPCINT22 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT23 == true)
|
|
if (pcintNum == 23)
|
|
callbackPCINT23 = userFunc;
|
|
#endif
|
|
#endif // PCINT_API
|
|
}
|
|
|
|
// port 3
|
|
else if (pcintPort == 3 && PCINT_USE_PORT3 == true) {
|
|
// use fake functions to make the ISRs compile with .a linkage
|
|
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
|
|
attachPinChangeInterrupt3();
|
|
#endif
|
|
// attache the function pointers for the API
|
|
#if defined(PCINT_API)
|
|
#if (PCINT_USE_PCINT24 == true)
|
|
if (pcintNum == 24)
|
|
callbackPCINT24 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT25 == true)
|
|
if (pcintNum == 25)
|
|
callbackPCINT25 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT26 == true)
|
|
if (pcintNum == 26)
|
|
callbackPCINT26 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT27 == true)
|
|
if (pcintNum == 27)
|
|
callbackPCINT27 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT28 == true)
|
|
if (pcintNum == 28)
|
|
callbackPCINT28 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT29 == true)
|
|
if (pcintNum == 29)
|
|
callbackPCINT29 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT30 == true)
|
|
if (pcintNum == 30)
|
|
callbackPCINT30 = userFunc;
|
|
#endif
|
|
#if (PCINT_USE_PCINT31 == true)
|
|
if (pcintNum == 31)
|
|
callbackPCINT31 = userFunc;
|
|
#endif
|
|
#endif // PCINT_API
|
|
}
|
|
else return;
|
|
|
|
// get bitmask and array position
|
|
uint8_t pcintMask = (1 << pcintBit);
|
|
uint8_t arrayPos = getArrayPosPCINT(pcintPort);
|
|
|
|
// save settings related to mode and registers
|
|
if (mode == CHANGE || mode == RISING)
|
|
risingPorts[arrayPos] |= pcintMask;
|
|
if (mode == CHANGE || mode == FALLING)
|
|
fallingPorts[arrayPos] |= pcintMask;
|
|
|
|
// call the actual hardware attach function
|
|
enablePinChangeInterruptHelper(pcintPort, pcintMask, arrayPos);
|
|
}
|
|
|
|
// enable interrupt again if temporary disabled
|
|
static inline void enablePinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline));
|
|
void enablePinChangeInterrupt(const uint8_t pcintNum) {
|
|
// get PCINT registers
|
|
uint8_t pcintPort = pcintNum / 8;
|
|
uint8_t pcintBit = pcintNum % 8;
|
|
|
|
// check if pcint is a valid pcint, exclude deactivated ports
|
|
if (pcintPort == 0) {
|
|
if (PCINT_USE_PORT0 == false)
|
|
return;
|
|
}
|
|
else if (pcintPort == 1) {
|
|
if (PCINT_USE_PORT1 == false)
|
|
return;
|
|
}
|
|
else if (pcintPort == 2) {
|
|
if (PCINT_USE_PORT2 == false)
|
|
return;
|
|
}
|
|
else if (pcintPort == 3) {
|
|
if (PCINT_USE_PORT3 == false)
|
|
return;
|
|
}
|
|
else return;
|
|
|
|
// call the actual hardware attach function
|
|
uint8_t pcintMask = (1 << pcintBit);
|
|
uint8_t arrayPos = getArrayPosPCINT(pcintPort);
|
|
enablePinChangeInterruptHelper(pcintPort, pcintMask, arrayPos);
|
|
}
|
|
|
|
|
|
//================================================================================
|
|
// Detach Function (partly inlined)
|
|
//================================================================================
|
|
|
|
void disablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask);
|
|
static inline void detachPinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline));
|
|
|
|
void detachPinChangeInterrupt(const uint8_t pcintNum) {
|
|
// get PCINT registers
|
|
uint8_t pcintPort = pcintNum / 8;
|
|
uint8_t pcintBit = pcintNum % 8;
|
|
|
|
// check if pcint is a valid pcint, exclude deactivated ports
|
|
// port 0
|
|
if (pcintPort == 0 && PCINT_USE_PORT0 == true) {
|
|
// attache the function pointers for the API
|
|
#if defined(PCINT_API)
|
|
#if (PCINT_USE_PCINT0 == true)
|
|
if (pcintNum == 0)
|
|
callbackPCINT0 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT1 == true)
|
|
if (pcintNum == 1)
|
|
callbackPCINT1 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT2 == true)
|
|
if (pcintNum == 2)
|
|
callbackPCINT2 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT3 == true)
|
|
if (pcintNum == 3)
|
|
callbackPCINT3 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT4 == true)
|
|
if (pcintNum == 4)
|
|
callbackPCINT4 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT5 == true)
|
|
if (pcintNum == 5)
|
|
callbackPCINT5 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT6 == true)
|
|
if (pcintNum == 6)
|
|
callbackPCINT6 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT7 == true)
|
|
if (pcintNum == 7)
|
|
callbackPCINT7 = pcint_null_callback;
|
|
#endif
|
|
#endif // PCINT_API
|
|
}
|
|
|
|
// port 1
|
|
else if (pcintPort == 1 && PCINT_USE_PORT1 == true) {
|
|
// attache the function pointers for the API
|
|
#if defined(PCINT_API)
|
|
#if (PCINT_USE_PCINT8 == true)
|
|
if (pcintNum == 8)
|
|
callbackPCINT8 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT9 == true)
|
|
if (pcintNum == 9)
|
|
callbackPCINT9 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT10 == true)
|
|
if (pcintNum == 10)
|
|
callbackPCINT10 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT11 == true)
|
|
if (pcintNum == 11)
|
|
callbackPCINT11 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT12 == true)
|
|
if (pcintNum == 12)
|
|
callbackPCINT12 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT13 == true)
|
|
if (pcintNum == 13)
|
|
callbackPCINT13 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT14 == true)
|
|
if (pcintNum == 14)
|
|
callbackPCINT14 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT15 == true)
|
|
if (pcintNum == 15)
|
|
callbackPCINT15 = pcint_null_callback;
|
|
#endif
|
|
#endif // PCINT_API
|
|
}
|
|
|
|
// port 2
|
|
else if (pcintPort == 2 && PCINT_USE_PORT2 == true) {
|
|
// attache the function pointers for the API
|
|
#if defined(PCINT_API)
|
|
#if (PCINT_USE_PCINT16 == true)
|
|
if (pcintNum == 16)
|
|
callbackPCINT16 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT17 == true)
|
|
if (pcintNum == 17)
|
|
callbackPCINT17 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT18 == true)
|
|
if (pcintNum == 18)
|
|
callbackPCINT18 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT19 == true)
|
|
if (pcintNum == 19)
|
|
callbackPCINT19 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT20 == true)
|
|
if (pcintNum == 20)
|
|
callbackPCINT20 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT21 == true)
|
|
if (pcintNum == 21)
|
|
callbackPCINT21 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT22 == true)
|
|
if (pcintNum == 22)
|
|
callbackPCINT22 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT23 == true)
|
|
if (pcintNum == 23)
|
|
callbackPCINT23 = pcint_null_callback;
|
|
#endif
|
|
#endif // PCINT_API
|
|
}
|
|
|
|
// port 3
|
|
else if (pcintPort == 3 && PCINT_USE_PORT3 == true) {
|
|
// attache the function pointers for the API
|
|
#if defined(PCINT_API)
|
|
#if (PCINT_USE_PCINT24 == true)
|
|
if (pcintNum == 24)
|
|
callbackPCINT24 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT25 == true)
|
|
if (pcintNum == 25)
|
|
callbackPCINT25 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT26 == true)
|
|
if (pcintNum == 26)
|
|
callbackPCINT26 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT27 == true)
|
|
if (pcintNum == 27)
|
|
callbackPCINT27 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT28 == true)
|
|
if (pcintNum == 28)
|
|
callbackPCINT28 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT29 == true)
|
|
if (pcintNum == 29)
|
|
callbackPCINT29 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT30 == true)
|
|
if (pcintNum == 30)
|
|
callbackPCINT30 = pcint_null_callback;
|
|
#endif
|
|
#if (PCINT_USE_PCINT31 == true)
|
|
if (pcintNum == 31)
|
|
callbackPCINT31 = pcint_null_callback;
|
|
#endif
|
|
#endif // PCINT_API
|
|
}
|
|
else return;
|
|
|
|
// get bitmask and array position
|
|
uint8_t pcintMask = (1 << pcintBit);
|
|
uint8_t arrayPos = getArrayPosPCINT(pcintPort);
|
|
|
|
// delete setting
|
|
risingPorts[arrayPos] &= ~pcintMask;
|
|
fallingPorts[arrayPos] &= ~pcintMask;
|
|
|
|
// call the actual hardware disable function
|
|
disablePinChangeInterruptHelper(pcintPort, pcintMask);
|
|
}
|
|
|
|
static inline void disablePinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline));
|
|
void disablePinChangeInterrupt(const uint8_t pcintNum) {
|
|
// get PCINT registers
|
|
uint8_t pcintPort = pcintNum / 8;
|
|
uint8_t pcintBit = pcintNum % 8;
|
|
|
|
// check if pcint is a valid pcint, exclude deactivated ports
|
|
if (pcintPort == 0) {
|
|
if (PCINT_USE_PORT0 == false)
|
|
return;
|
|
}
|
|
else if (pcintPort == 1) {
|
|
if (PCINT_USE_PORT1 == false)
|
|
return;
|
|
}
|
|
else if (pcintPort == 2) {
|
|
if (PCINT_USE_PORT2 == false)
|
|
return;
|
|
}
|
|
else if (pcintPort == 3) {
|
|
if (PCINT_USE_PORT3 == false)
|
|
return;
|
|
}
|
|
else return;
|
|
|
|
// get bitmask
|
|
uint8_t pcintMask = (1 << pcintBit);
|
|
|
|
// Do not delete mode settings nor detach the user function
|
|
// Just turn off interrupts
|
|
|
|
// call the actual hardware disable function
|
|
disablePinChangeInterruptHelper(pcintPort, pcintMask);
|
|
}
|
|
|
|
//================================================================================
|
|
// getTrigger Function (inlined)
|
|
//================================================================================
|
|
|
|
static inline uint8_t getPinChangeInterruptTrigger(const uint8_t pcintNum) __attribute__((always_inline));
|
|
uint8_t getPinChangeInterruptTrigger(const uint8_t pcintNum) {
|
|
// get PCINT registers
|
|
uint8_t pcintPort = pcintNum / 8;
|
|
uint8_t pcintBit = pcintNum % 8;
|
|
|
|
// check if pcint is a valid pcint, exclude deactivated ports
|
|
if (pcintPort == 0) {
|
|
if (PCINT_USE_PORT0 == false)
|
|
return CHANGE;
|
|
}
|
|
else if (pcintPort == 1) {
|
|
if (PCINT_USE_PORT1 == false)
|
|
return CHANGE;
|
|
}
|
|
else if (pcintPort == 2) {
|
|
if (PCINT_USE_PORT2 == false)
|
|
return CHANGE;
|
|
}
|
|
else if (pcintPort == 3) {
|
|
if (PCINT_USE_PORT3 == false)
|
|
return CHANGE;
|
|
}
|
|
else return CHANGE;
|
|
|
|
uint8_t arrayPos = getArrayPosPCINT(pcintPort);
|
|
|
|
// Check if no mode was set, return an error
|
|
if(!(risingPorts[arrayPos] & (1 << pcintBit)) && !(fallingPorts[arrayPos] & (1 << pcintBit)))
|
|
return CHANGE;
|
|
|
|
// specify the CHANGE mode
|
|
if (oldPorts[arrayPos] & (1 << pcintBit))
|
|
return RISING;
|
|
else
|
|
return FALLING;
|
|
}
|