diff --git a/libraries/Cytron_Motor_Drivers_Library/CytronMotorDriver.cpp b/libraries/Cytron_Motor_Drivers_Library/CytronMotorDriver.cpp new file mode 100644 index 0000000..450dec8 --- /dev/null +++ b/libraries/Cytron_Motor_Drivers_Library/CytronMotorDriver.cpp @@ -0,0 +1,47 @@ +#include "CytronMotorDriver.h" + +CytronMD::CytronMD(MODE mode, uint8_t pin1, uint8_t pin2) +{ + _mode = mode; + _pin1 = pin1; + _pin2 = pin2; + + pinMode(_pin1, OUTPUT); + pinMode(_pin2, OUTPUT); + + digitalWrite(_pin1, LOW); + digitalWrite(_pin2, LOW); +} + +void CytronMD::setSpeed(int16_t speed) +{ + // Make sure the speed is within the limit. + if (speed > 255) { + speed = 255; + } else if (speed < -255) { + speed = -255; + } + + // Set the speed and direction. + switch (_mode) { + case PWM_DIR: + if (speed >= 0) { + analogWrite(_pin1, speed); + digitalWrite(_pin2, LOW); + } else { + analogWrite(_pin1, -speed); + digitalWrite(_pin2, HIGH); + } + break; + + case PWM_PWM: + if (speed >= 0) { + analogWrite(_pin1, speed); + analogWrite(_pin2, 0); + } else { + analogWrite(_pin1, 0); + analogWrite(_pin2, -speed); + } + break; + } +} diff --git a/libraries/Cytron_Motor_Drivers_Library/CytronMotorDriver.h b/libraries/Cytron_Motor_Drivers_Library/CytronMotorDriver.h new file mode 100644 index 0000000..d297f7b --- /dev/null +++ b/libraries/Cytron_Motor_Drivers_Library/CytronMotorDriver.h @@ -0,0 +1,44 @@ +#ifndef CYTRON_MOTOR_DRIVER_H +#define CYTRON_MOTOR_DRIVER_H + +#include +#include + + + +enum MODE { + PWM_DIR, + PWM_PWM, +}; + + + +class CytronMD +{ + public: + CytronMD(MODE mode, uint8_t pin1, uint8_t pin2); + void setSpeed(int16_t speed); + + protected: + MODE _mode; + uint8_t _pin1; + uint8_t _pin2; +}; + + + +/* class CytronMD10C : public CytronMD +{ + public: + CytronMD10C(uint8_t pwmPin, uint8_t dirPin) : CytronMD(PWM_DIR, pwmPin, dirPin) {}; +}; + + + +class CytronMD13S : public CytronMD +{ + public: + CytronMD13S(uint8_t pwmPin, uint8_t dirPin) : CytronMD(PWM_DIR, pwmPin, dirPin) {}; +}; */ + +#endif diff --git a/libraries/Cytron_Motor_Drivers_Library/LICENSE b/libraries/Cytron_Motor_Drivers_Library/LICENSE new file mode 100644 index 0000000..1709a15 --- /dev/null +++ b/libraries/Cytron_Motor_Drivers_Library/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 CytronTechnologies + +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. diff --git a/libraries/Cytron_Motor_Drivers_Library/README.md b/libraries/Cytron_Motor_Drivers_Library/README.md new file mode 100644 index 0000000..e8d0489 --- /dev/null +++ b/libraries/Cytron_Motor_Drivers_Library/README.md @@ -0,0 +1,60 @@ +# Arduino Library for Cytron Motor Drivers +This library provides functions for Cytron Motor Drivers.
+Please refer to the examples on how to use the library.
+Connection to the motor driver is described in the comment section of the examples. + +## Installation +1. Open the Arduino IDE, select `Sketch` -> `Include Library` -> `Manage Libraries...`. +2. Search for `Cytron Motor Drivers Library`. +3. Click `Install` to install the library. +4. Restart the Arduino IDE. +5. Examples can be opened in Arduino IDE from `File` -> `Examples` -> `Cytron DC Motors Library`.
+Please refer to the example list below for all the compatible motor drivers. + + +## Examples +### 1. PWM_DIR +This example shows how to drive a motor using PWM and DIR pins.
+PWM pin is used to control the speed of the motor while DIR pin is used to control the direction.
+
+This example only show how to drive a single motor for simplicity.
+For multi channels motor driver, all channels work the same way.
+ +**Compatible Motor Drivers:** +* [MD10C](https://www.cytron.io/p-md10c) +* [MD10-POT](https://www.cytron.io/p-md10-pot) +* [MD13S](https://www.cytron.io/p-md13s) +* [MD20A](https://www.cytron.io/p-20amp-6v-30v-dc-motor-driver) +* [MD30C](https://www.cytron.io/p-md30c) +* [SHIELD-MD10](https://www.cytron.io/p-shield-md10) +* [MDS160A*](https://www.cytron.io/p-mds160a) +* [MDS40B*](https://www.cytron.io/p-mds40b) + +**Smart series motor driver needs to be configured as **Sign-Magnitude PWM Input** mode. Refer to user manual for more details.* + + + +### 2. PWM_DIR_DUAL +This example shows how to drive 2 motors using PWM and DIR pins .
+PWM pin is used to control the speed of the motor while DIR pin is used to control the direction.
+ +**Compatible Motor Drivers:** +* [SHIELD-2AMOTOR](https://www.cytron.io/p-shield-2amotor) +* [SHIELD-3AMOTOR](https://www.cytron.io/p-shield-3amotor) +* [MDD10A](https://www.cytron.io/p-mdd10a) +* [FD04A](https://www.cytron.io/p-fd04a) +* [MDDS10*](https://www.cytron.io/p-mdds10) +* [MDDS30*](https://www.cytron.io/p-mdds30) +* [MDDS60*](https://www.cytron.io/p-mdds60) + +**Smart series motor driver needs to be configured as **Sign-Magnitude PWM Input** mode. Refer to user manual for more details.* + + + +### 2. PWM_PWM_DUAL +This example shows how to drive 2 motors using 4 PWM input pins (2 for each motor).
+Input A controls the motor speed in forward direction and Input B controls the motor speed in backward direction.
+ +**Compatible Motor Drivers:** +* [MAKER-DRIVE](https://www.cytron.io/p-maker-drive) +* [MDD03A](https://www.cytron.io/p-mdd03a) diff --git a/libraries/Cytron_Motor_Drivers_Library/examples/PWM_DIR/PWM_DIR.ino b/libraries/Cytron_Motor_Drivers_Library/examples/PWM_DIR/PWM_DIR.ino new file mode 100644 index 0000000..0efb350 --- /dev/null +++ b/libraries/Cytron_Motor_Drivers_Library/examples/PWM_DIR/PWM_DIR.ino @@ -0,0 +1,60 @@ +/******************************************************************************* + * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTY AND SUPPORT + * IS APPLICABLE TO THIS SOFTWARE IN ANY FORM. CYTRON TECHNOLOGIES SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR CONSEQUENTIAL + * DAMAGES, FOR ANY REASON WHATSOEVER. + ******************************************************************************** + * DESCRIPTION: + * + * This example shows how to drive a motor using the PWM and DIR pins. + * This example only shows how to drive a single motor for simplicity. + * For dual channel motor driver, both channel work the same way. + * + * + * CONNECTIONS: + * + * Arduino D3 - Motor Driver PWM Input + * Arduino D4 - Motor Driver DIR Input + * Arduino GND - Motor Driver GND + * + * + * AUTHOR : Kong Wai Weng + * COMPANY : Cytron Technologies Sdn Bhd + * WEBSITE : www.cytron.io + * EMAIL : support@cytron.io + * + *******************************************************************************/ + + #include "CytronMotorDriver.h" + + +// Configure the motor driver. +CytronMD motor(PWM_DIR, 3, 4); // PWM = Pin 3, DIR = Pin 4. + + +// The setup routine runs once when you press reset. +void setup() { + +} + + +// The loop routine runs over and over again forever. +void loop() { + motor.setSpeed(128); // Run forward at 50% speed. + delay(1000); + + motor.setSpeed(255); // Run forward at full speed. + delay(1000); + + motor.setSpeed(0); // Stop. + delay(1000); + + motor.setSpeed(-128); // Run backward at 50% speed. + delay(1000); + + motor.setSpeed(-255); // Run backward at full speed. + delay(1000); + + motor.setSpeed(0); // Stop. + delay(1000); +} diff --git a/libraries/Cytron_Motor_Drivers_Library/examples/PWM_DIR_DUAL/PWM_DIR_DUAL.ino b/libraries/Cytron_Motor_Drivers_Library/examples/PWM_DIR_DUAL/PWM_DIR_DUAL.ino new file mode 100644 index 0000000..bc9cc84 --- /dev/null +++ b/libraries/Cytron_Motor_Drivers_Library/examples/PWM_DIR_DUAL/PWM_DIR_DUAL.ino @@ -0,0 +1,68 @@ +/******************************************************************************* + * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTY AND SUPPORT + * IS APPLICABLE TO THIS SOFTWARE IN ANY FORM. CYTRON TECHNOLOGIES SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR CONSEQUENTIAL + * DAMAGES, FOR ANY REASON WHATSOEVER. + ******************************************************************************** + * DESCRIPTION: + * + * This example shows how to drive 2 motors using the PWM and DIR pins with + * 2-channel motor driver. + * + * + * CONNECTIONS: + * + * Arduino D3 - Motor Driver PWM 1 Input + * Arduino D4 - Motor Driver DIR 1 Input + * Arduino D9 - Motor Driver PWM 2 Input + * Arduino D10 - Motor Driver DIR 2 Input + * Arduino GND - Motor Driver GND + * + * + * AUTHOR : Kong Wai Weng + * COMPANY : Cytron Technologies Sdn Bhd + * WEBSITE : www.cytron.io + * EMAIL : support@cytron.io + * + *******************************************************************************/ + + #include "CytronMotorDriver.h" + + +// Configure the motor driver. +CytronMD motor1(PWM_DIR, 3, 4); // PWM 1 = Pin 3, DIR 1 = Pin 4. +CytronMD motor2(PWM_DIR, 9, 10); // PWM 2 = Pin 9, DIR 2 = Pin 10. + + +// The setup routine runs once when you press reset. +void setup() { + +} + + +// The loop routine runs over and over again forever. +void loop() { + motor1.setSpeed(128); // Motor 1 runs forward at 50% speed. + motor2.setSpeed(-128); // Motor 2 runs backward at 50% speed. + delay(1000); + + motor1.setSpeed(255); // Motor 1 runs forward at full speed. + motor2.setSpeed(-255); // Motor 2 runs backward at full speed. + delay(1000); + + motor1.setSpeed(0); // Motor 1 stops. + motor2.setSpeed(0); // Motor 2 stops. + delay(1000); + + motor1.setSpeed(-128); // Motor 1 runs backward at 50% speed. + motor2.setSpeed(128); // Motor 2 runs forward at 50% speed. + delay(1000); + + motor1.setSpeed(-255); // Motor 1 runs backward at full speed. + motor2.setSpeed(255); // Motor 2 runs forward at full speed. + delay(1000); + + motor1.setSpeed(0); // Motor 1 stops. + motor2.setSpeed(0); // Motor 2 stops. + delay(1000); +} \ No newline at end of file diff --git a/libraries/Cytron_Motor_Drivers_Library/examples/PWM_PWM_DUAL/PWM_PWM_DUAL.ino b/libraries/Cytron_Motor_Drivers_Library/examples/PWM_PWM_DUAL/PWM_PWM_DUAL.ino new file mode 100644 index 0000000..f91e352 --- /dev/null +++ b/libraries/Cytron_Motor_Drivers_Library/examples/PWM_PWM_DUAL/PWM_PWM_DUAL.ino @@ -0,0 +1,68 @@ +/******************************************************************************* + * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTY AND SUPPORT + * IS APPLICABLE TO THIS SOFTWARE IN ANY FORM. CYTRON TECHNOLOGIES SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR CONSEQUENTIAL + * DAMAGES, FOR ANY REASON WHATSOEVER. + ******************************************************************************** + * DESCRIPTION: + * + * This example shows how to drive 2 motors using 4 PWM pins (2 for each motor) + * with 2-channel motor driver. + * + * + * CONNECTIONS: + * + * Arduino D3 - Motor Driver PWM 1A Input + * Arduino D9 - Motor Driver PWM 1B Input + * Arduino D10 - Motor Driver PWM 2A Input + * Arduino D11 - Motor Driver PWM 2B Input + * Arduino GND - Motor Driver GND + * + * + * AUTHOR : Kong Wai Weng + * COMPANY : Cytron Technologies Sdn Bhd + * WEBSITE : www.cytron.io + * EMAIL : support@cytron.io + * + *******************************************************************************/ + + #include "CytronMotorDriver.h" + + +// Configure the motor driver. +CytronMD motor1(PWM_PWM, 3, 9); // PWM 1A = Pin 3, PWM 1B = Pin 9. +CytronMD motor2(PWM_PWM, 10, 11); // PWM 2A = Pin 10, PWM 2B = Pin 11. + + +// The setup routine runs once when you press reset. +void setup() { + +} + + +// The loop routine runs over and over again forever. +void loop() { + motor1.setSpeed(128); // Motor 1 runs forward at 50% speed. + motor2.setSpeed(-128); // Motor 2 runs backward at 50% speed. + delay(1000); + + motor1.setSpeed(255); // Motor 1 runs forward at full speed. + motor2.setSpeed(-255); // Motor 2 runs backward at full speed. + delay(1000); + + motor1.setSpeed(0); // Motor 1 stops. + motor2.setSpeed(0); // Motor 2 stops. + delay(1000); + + motor1.setSpeed(-128); // Motor 1 runs backward at 50% speed. + motor2.setSpeed(128); // Motor 2 runs forward at 50% speed. + delay(1000); + + motor1.setSpeed(-255); // Motor 1 runs backward at full speed. + motor2.setSpeed(255); // Motor 2 runs forward at full speed. + delay(1000); + + motor1.setSpeed(0); // Motor 1 stops. + motor2.setSpeed(0); // Motor 2 stops. + delay(1000); +} \ No newline at end of file diff --git a/libraries/Cytron_Motor_Drivers_Library/keywords.txt b/libraries/Cytron_Motor_Drivers_Library/keywords.txt new file mode 100644 index 0000000..100b362 --- /dev/null +++ b/libraries/Cytron_Motor_Drivers_Library/keywords.txt @@ -0,0 +1,24 @@ +############################################# +# Syntax Coloring Map For Cytron Motor Driver +############################################# +# Class +############################################# + +CytronMD KEYWORD3 + + + +############################################# +# Methods and Functions +############################################# + +setSpeed KEYWORD2 + + + +############################################# +# Constants +############################################# + +PWM_DIR LITERAL1 +PWM_PWM LITERAL1 diff --git a/libraries/Cytron_Motor_Drivers_Library/library.properties b/libraries/Cytron_Motor_Drivers_Library/library.properties new file mode 100644 index 0000000..3b55c7f --- /dev/null +++ b/libraries/Cytron_Motor_Drivers_Library/library.properties @@ -0,0 +1,9 @@ +name=Cytron Motor Drivers Library +version=1.0.1 +author=Cytron Technologies Sdn Bhd +maintainer=Cytron Technologies Sdn Bhd +sentence=Library for Cytron Motor Drivers. +paragraph=Provide examples on how to use the motor drivers. +category=Device Control +url=https://github.com/CytronTechnologies/CytronMotorDriver.git +architectures=* \ No newline at end of file diff --git a/libraries/EnableInterrupt/EnableInterrupt.h b/libraries/EnableInterrupt/EnableInterrupt.h new file mode 100644 index 0000000..3da2258 --- /dev/null +++ b/libraries/EnableInterrupt/EnableInterrupt.h @@ -0,0 +1,2073 @@ +// in vim, :set ts=2 sts=2 sw=2 et fdm=marker + +// EnableInterrupt, a library by GreyGnome. Copyright 2014-2015 by Michael Anthony Schwager. + +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Many definitions in /usr/avr/include/avr/io.h + +#ifndef EnableInterrupt_h +#define EnableInterrupt_h +#include + +// Function Prototypes (comment) /*{{{*/ +/* ************************************************************************************* +// ************************************************************************************* +// Function Prototypes ***************************************************************** +// ************************************************************************************* +// ************************************************************************************* +// *** These are the only functions the end user (programmer) needs to consider. *** +// *** This means you! *** +// ************************************************************************************* +*//*}}}*/ + +// Arduino Due (not Duemilanove) and Zero macros. Easy-peasy. +// Zero uses the __SAMD21G18A__ processor macro (2015-10-13) but we will use this handy macro, to +// avoid breaking the library over tiny changes. +#if defined __SAM3U4E__ || defined __SAM3X8E__ || defined __SAM3X8H__ || defined ARDUINO_SAMD_ZERO || defined __SAMD21G18A__ || defined __SAMD21J18A__ /*{{{*/ +#ifdef NEEDFORSPEED +#error Due and Zero are already fast; the NEEDFORSPEED definition does not make sense on it. +#endif +#define enableInterrupt(pin,userFunc,mode) attachInterrupt(pin, userFunc,mode) +#define disableInterrupt(pin) detachInterrupt(pin)/*}}}*/ +#else + +// Usage: (comment) /*{{{*/ +/* enableInterrupt- Sets up an interrupt on a selected Arduino pin. + * or + * enableInterruptFast- When used with the NEEDFORSPEED macro, sets up an interrupt on a selected Arduino pin. + * + * Usage: + * enableInterrupt(uint8_t pinNumber, void (*userFunction)(void), uint8_t mode); + * or + * enableInterrupt(uint8_t interruptDesignator, void (*userFunction)(void), uint8_t mode); + * + * For HiSpeed mode, + * enableInterruptFast(uint8_t pinNumber, uint8_t mode); + * or + * enableInterruptFast(uint8_t interruptDesignator, uint8_t mode); + * + * --------------------------------------------------------------------------------------- + * + * disableInterrupt- Disables interrupt on a selected Arduino pin. + * + * Usage: + * + * disableInterrupt(uint8_t pinNumber); + * or + * disableInterrupt(uint8_t interruptDesignator); + * + * --------------------------------------------------------------------------------------- + * + * interruptDesignator: Essentially this is an Arduino pin, and if that's all you want to give + * the function, it will work just fine. Why is it called an "interruptDesignator", then? Because + * there's a twist: You can perform a bitwise "and" with the pin number and PINCHANGEINTERRUPT + * to specify that you want to use a Pin Change Interrupt type of interrupt on those pins that + * support both Pin Change and External Interrupts. Otherwise, the library will choose whatever + * interrupt type (External, or Pin Change) normally applies to that pin, with priority to + * External Interrupt. + * + * The interruptDesignator is required because on the ATmega328 processor pins 2 and 3 support + * ''either'' pin change or * external interrupts. On 644/1284-based systems, pin change interrupts + * are supported on all pins and external interrupts are supported on pins 2, 10, and 11. + * Otherwise, each pin only supports a single type of interrupt and the + * PINCHANGEINTERRUPT scheme changes nothing. This means you can ignore this whole discussion + * for ATmega2560- or ATmega32U4-based Arduinos. You can probably safely ignore it for + * ATmega328-based Arduinos, too. + *//*}}}*/ + +void enableInterrupt(uint8_t interruptDesignator, void (*userFunction)(void), uint8_t mode); +void disableInterrupt(uint8_t interruptDesignator); +void bogusFunctionPlaceholder(void); +#ifdef NEEDFORSPEED +#undef enableInterruptFast +// enableInterruptFast(uint8_t interruptDesignator, uint8_t mode); +#define enableInterruptFast(x, y) enableInterrupt(x, bogusFunctionPlaceholder, y) +#endif + +// ************************************************************************************* +// End Function Prototypes ************************************************************* +// ************************************************************************************* + +#undef PINCHANGEINTERRUPT +#define PINCHANGEINTERRUPT 0x80 + +#undef attachPinChangeInterrupt +#undef detachPinChangeInterrupt +#define detachPinChangeInterrupt(pin) disableInterrupt(pin) +#define attachPinChangeInterrupt(pin,userFunc,mode) enableInterrupt(pin, userFunc, mode) + +#ifdef LIBCALL_ENABLEINTERRUPT // LIBCALL_ENABLEINTERRUPT **************************************** + +#ifdef EI_ARDUINO_INTERRUPTED_PIN +extern volatile uint8_t arduinoInterruptedPin; +extern volatile uint8_t arduinoPinState; +#endif + +#else + +#ifdef EI_ARDUINO_INTERRUPTED_PIN +volatile uint8_t arduinoInterruptedPin=0; +volatile uint8_t arduinoPinState=0; +#endif + + +#ifdef NEEDFORSPEED +void bogusFunctionPlaceholder(void) { +} +#include "utility/ei_pindefs_speed.h" +#endif + +/* Arduino pin to ATmega port translaton is found doing digital_pin_to_port_PGM[] */ +/* Arduino pin to PCMSKx bitmask is found by doing digital_pin_to_bit_mask_PGM[] */ +/* ...except for PortJ, which is shifted left 1 bit in PCI1 */ +volatile uint8_t *pcmsk; + +// Arduino.h has these, but the block is surrounded by #ifdef ARDUINO_MAIN +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 + +typedef void (*interruptFunctionType)(void); + +// =========================================================================================== +// CHIP SPECIFIC DATA STRUCTURES ============================================================= +// =========================================================================================== + +/* UNO SERIES *************************************************************************/ +/* UNO SERIES *************************************************************************/ +/* UNO SERIES *************************************************************************/ +#if defined __AVR_ATmega168__ || defined __AVR_ATmega168A__ || defined __AVR_ATmega168P__ || \ + defined __AVR_ATmega168PA__ || defined __AVR_ATmega328__ || defined __AVR_ATmega328P__ +#define ARDUINO_328 /*{{{*/ +#define EI_NOTPORTA +#define EI_NOTPORTJ +#define EI_NOTPORTK /*}}}*/ + +#if defined EI_NOTPINCHANGE /*{{{*/ +#ifndef EI_NOTPORTB +#define EI_NOTPORTB +#endif +#ifndef EI_NOTPORTC +#define EI_NOTPORTC +#endif +#ifndef EI_NOTPORTD +#define EI_NOTPORTD +#endif +#endif // defined EI_NOTPINCHANGE + +#ifndef NEEDFORSPEED + +#define ARDUINO_PIN_B0 8 +#define ARDUINO_PIN_B1 9 +#define ARDUINO_PIN_B2 10 +#define ARDUINO_PIN_B3 11 +#define ARDUINO_PIN_B4 12 +#define ARDUINO_PIN_B5 13 +#define ARDUINO_PIN_C0 14 +#define ARDUINO_PIN_C1 15 +#define ARDUINO_PIN_C2 16 +#define ARDUINO_PIN_C3 17 +#define ARDUINO_PIN_C4 18 +#define ARDUINO_PIN_C5 19 +#define ARDUINO_PIN_D0 0 +#define ARDUINO_PIN_D1 1 +#define ARDUINO_PIN_D2 2 +#define ARDUINO_PIN_D3 3 +#define ARDUINO_PIN_D4 4 +#define ARDUINO_PIN_D5 5 +#define ARDUINO_PIN_D6 6 +#define ARDUINO_PIN_D7 7 + +const uint8_t PROGMEM digital_pin_to_port_bit_number_PGM[] = { + 0, // 0 == port D, 0 + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 0, // 8 == port B, 0 + 1, + 2, + 3, + 4, + 5, + 0, // 14 == port C, 0 + 1, + 2, + 3, + 4, + 5 +}; + +#if ! defined(EI_NOTEXTERNAL) && ! defined(EI_NOTINT0) && ! defined (EI_NOTINT1) +interruptFunctionType functionPointerArrayEXTERNAL[2]; +#endif + +#ifndef EI_NOTPORTB +// 2 of the interrupts are unsupported on Arduino UNO. +struct functionPointersPortB { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; +}; +typedef struct functionPointersPortB functionPointersPortB; + +functionPointersPortB portBFunctions = { NULL, NULL, NULL, NULL, NULL, NULL }; + +#endif // EI_NOTPORTB + +#ifndef EI_NOTPORTC +// 1 of the interrupts are used as RESET on Arduino UNO. +struct functionPointersPortC { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; +}; +typedef struct functionPointersPortC functionPointersPortC; + +functionPointersPortC portCFunctions = { NULL, NULL, NULL, NULL, NULL, NULL }; + +#endif // EI_NOTPORTC + +#ifndef EI_NOTPORTD +// 1 of the interrupts are used as RESET on Arduino UNO. +struct functionPointersPortD { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; + interruptFunctionType pinSix; + interruptFunctionType pinSeven; +}; +typedef struct functionPointersPortD functionPointersPortD; + +functionPointersPortD portDFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +#endif // EI_NOTPORTD +#endif // NEEDFORSPEED + +// For Pin Change Interrupts; since we're duplicating FALLING and RISING in software, +// we have to know how the ports were defined. +#ifndef EI_NOTPORTB +volatile uint8_t risingPinsPORTB=0; +volatile uint8_t fallingPinsPORTB=0; +// for the saved state of the ports +static volatile uint8_t portSnapshotB; +#endif + +#ifndef EI_NOTPORTC +volatile uint8_t risingPinsPORTC=0; +volatile uint8_t fallingPinsPORTC=0; +static volatile uint8_t portSnapshotC; +#endif + +#ifndef EI_NOTPORTD +volatile uint8_t risingPinsPORTD=0; +volatile uint8_t fallingPinsPORTD=0; +static volatile uint8_t portSnapshotD; +#endif + +// the PCINT?_vect's are defined in the avr.h files, like iom328p.h +#define PORTB_VECT PCINT0_vect +#define PORTC_VECT PCINT1_vect +#define PORTD_VECT PCINT2_vect/*}}}*/ + +/* MEGA2560/1280/640 SERIES ************************************************************************/ +/* MEGA2560/1280/640 SERIES ************************************************************************/ +/* MEGA2560/1280/640 SERIES ************************************************************************/ +#elif defined __AVR_ATmega640__ || defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ +#define ARDUINO_MEGA /*{{{*/ +#define EI_NOTPORTA +#define EI_NOTPORTC +#define EI_NOTPORTD /*}}}*/ + +#if defined EI_NOTPINCHANGE/*{{{*/ +#ifndef EI_NOTPORTB +#define EI_NOTPORTB +#endif +#ifndef EI_NOTPORTJ +#define EI_NOTPORTJ +#endif +#ifndef EI_NOTPORTK +#define EI_NOTPORTK +#endif +#endif + +volatile uint8_t portJPCMSK=0; // This is a shifted version of PCMSK for PortJ, so I + // don't have to perform a shift in the IRQ. + +#ifndef NEEDFORSPEED +// Pin change interrupts +#define ARDUINO_PIN_B0 53 +#define ARDUINO_PIN_B1 52 +#define ARDUINO_PIN_B2 51 +#define ARDUINO_PIN_B3 50 +#define ARDUINO_PIN_B4 10 +#define ARDUINO_PIN_B5 11 +#define ARDUINO_PIN_B6 12 +#define ARDUINO_PIN_B7 13 +#define ARDUINO_PIN_J0 15 +#define ARDUINO_PIN_J1 14 +// "fake" pins +#define ARDUINO_PIN_J2 70 +#define ARDUINO_PIN_J3 71 +#define ARDUINO_PIN_J4 72 +#define ARDUINO_PIN_J5 73 +#define ARDUINO_PIN_J6 74 + +#define ARDUINO_PIN_K0 62 +#define ARDUINO_PIN_K1 63 +#define ARDUINO_PIN_K2 64 +#define ARDUINO_PIN_K3 65 +#define ARDUINO_PIN_K4 66 +#define ARDUINO_PIN_K5 67 +#define ARDUINO_PIN_K6 68 +#define ARDUINO_PIN_K7 69 + +#define ARDUINO_PIN_D0 21 +#define ARDUINO_PIN_D1 20 +#define ARDUINO_PIN_D2 19 +#define ARDUINO_PIN_D3 18 +#define ARDUINO_PIN_E4 2 +#define ARDUINO_PIN_E5 3 +#define ARDUINO_PIN_E6 75 +#define ARDUINO_PIN_E7 76 + +const uint8_t PROGMEM digital_pin_to_port_bit_number_PGM[] = { + 0, // PE0 pin: 0 + 1, // PE1 pin: 1 + 4, // PE4 pin: 2 + 5, // PE5 pin: 3 + 5, // PG5 pin: 4 + 3, // PE3 pin: 5 + 3, // PH3 pin: 6 + 4, // PH4 pin: 7 + 5, // PH5 pin: 8 + 6, // PH6 pin: 9 + 4, // PB4 pin: 10 + 5, // PB5 pin: 11 + 6, // PB6 pin: 12 + 7, // PB7 pin: 13 + 1, // PJ1 pin: 14 + 0, // PJ0 pin: 15 + 1, // PH1 pin: 16 + 0, // PH0 pin: 17 + 3, // PD3 pin: 18 + 2, // PD2 pin: 19 + 1, // PD1 pin: 20 + 0, // PD0 pin: 21 + 0, // PA0 pin: 22 + 1, // PA1 pin: 23 + 2, // PA2 pin: 24 + 3, // PA3 pin: 25 + 4, // PA4 pin: 26 + 5, // PA5 pin: 27 + 6, // PA6 pin: 28 + 7, // PA7 pin: 29 + 7, // PC7 pin: 30 + 6, // PC6 pin: 31 + 5, // PC5 pin: 32 + 4, // PC4 pin: 33 + 3, // PC3 pin: 34 + 2, // PC2 pin: 35 + 1, // PC1 pin: 36 + 0, // PC0 pin: 37 + 7, // PD7 pin: 38 + 2, // PG2 pin: 39 + 1, // PG1 pin: 40 + 0, // PG0 pin: 41 + 7, // PL7 pin: 42 + 6, // PL6 pin: 43 + 5, // PL5 pin: 44 + 4, // PL4 pin: 45 + 3, // PL3 pin: 46 + 2, // PL2 pin: 47 + 1, // PL1 pin: 48 + 0, // PL0 pin: 49 + 3, // PB3 pin: 50 + 2, // PB2 pin: 51 + 1, // PB1 pin: 52 + 0, // PB0 pin: 53 + 0, // PF0 pin: 54 + 1, // PF1 pin: 55 + 2, // PF2 pin: 56 + 3, // PF3 pin: 57 + 4, // PF4 pin: 58 + 5, // PF5 pin: 59 + 6, // PF6 pin: 60 + 7, // PF7 pin: 61 + 0, // PK0 pin: 62 + 1, // PK1 pin: 63 + 2, // PK2 pin: 64 + 3, // PK3 pin: 65 + 4, // PK4 pin: 66 + 5, // PK5 pin: 67 + 6, // PK6 pin: 68 + 7, // PK7 pin: 69 + 2, // PJ2 pin: fake70, trick to allow software interrupts on Port J. PJ2 + 3, // PJ3 pin: fake71 PJ3 + 4, // PJ4 pin: fake72 PJ4 + 5, // PJ5 pin: fake73 PJ5 + 6, // PJ6 pin: fake74 PJ6 + 6, // PE6 pin: fake75 PE6 + 7 // PE7 pin: fake76 PE7 +}; + +#if ! defined(EI_NOTEXTERNAL) && ! defined(EI_NOTINT0) && ! defined(EI_NOTINT1) && ! defined(EI_NOTINT2) && ! defined(EI_NOTINT3) && ! defined(EI_NOTINT4) && ! defined(EI_NOTINT5) && ! defined(EI_NOTINT6) && ! defined(EI_NOTINT7) +interruptFunctionType functionPointerArrayEXTERNAL[8]; +#endif + +#ifndef EI_NOTPORTB +struct functionPointersPortB { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; + interruptFunctionType pinSix; + interruptFunctionType pinSeven; +}; +typedef struct functionPointersPortB functionPointersPortB; + +functionPointersPortB portBFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +#endif + +#ifndef EI_NOTPORTJ +// only 7 pins total of port J are supported as interrupts on the ATmega2560, +// and only PJ0 and 1 are supported on the Arduino MEGA. +// For PCI1 the 0th bit is PE0. PJ2-6 are not exposed on the Arduino pins, but +// we will support them anyway. There are clones that provide them, and users may +// solder in their own connections (...go, Makers!) +struct functionPointersPortJ { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; + interruptFunctionType pinSix; +}; +typedef struct functionPointersPortJ functionPointersPortJ; + +functionPointersPortJ portJFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +#endif + +#ifndef EI_NOTPORTK +struct functionPointersPortK { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; + interruptFunctionType pinSix; + interruptFunctionType pinSeven; +}; +typedef struct functionPointersPortK functionPointersPortK; + +functionPointersPortK portKFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +#endif +#endif // ifndef NEEDFORSPEED + +// For Pin Change Interrupts; since we're duplicating FALLING and RISING in software, +// we have to know how we were defined. +#ifndef EI_NOTPORTB +volatile uint8_t risingPinsPORTB=0; +volatile uint8_t fallingPinsPORTB=0; +static volatile uint8_t portSnapshotB; +#endif + +#ifndef EI_NOTPORTJ +volatile uint8_t risingPinsPORTJ=0; +volatile uint8_t fallingPinsPORTJ=0; +static volatile uint8_t portSnapshotJ; +#endif + +#ifndef EI_NOTPORTK +volatile uint8_t risingPinsPORTK=0; +volatile uint8_t fallingPinsPORTK=0; +static volatile uint8_t portSnapshotK; +#endif + +#define PORTB_VECT PCINT0_vect +#define PORTJ_VECT PCINT1_vect +#define PORTK_VECT PCINT2_vect +/*}}}*/ + +/* MEGA2561/1281 SERIES ************************************************************************/ +/* MEGA2561/1281 SERIES ************************************************************************/ +/* MEGA2561/1281 SERIES ************************************************************************/ +#elif defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ +#define ARDUINO_MEGA /*{{{*/ +#define EI_NOTPORTA +#define EI_NOTPORTC +#define EI_NOTPORTD +#define EI_NOTPORTJ +#define EI_NOTPORTK /*}}}*/ + +#if defined EI_NOTPINCHANGE/*{{{*/ +#ifndef EI_NOTPORTB +#define EI_NOTPORTB +#endif +#endif + +#ifndef NEEDFORSPEED +// Pin change interrupts +#define ARDUINO_PIN_B0 8 +#define ARDUINO_PIN_B1 9 +#define ARDUINO_PIN_B2 10 +#define ARDUINO_PIN_B3 11 +#define ARDUINO_PIN_B4 12 +#define ARDUINO_PIN_B5 13 +#define ARDUINO_PIN_B6 14 +#define ARDUINO_PIN_B7 15 + +const uint8_t PROGMEM digital_pin_to_port_bit_number_PGM[] = { + 0, // PE0 pin: 0 + 1, // PE1 pin: 1 + 2, // PE2 pin: 2 + 3, // PE3 pin: 3 + 4, // PE4 pin: 4 + 5, // PE5 pin: 5 + 6, // PE6 pin: 6 + 7, // PE7 pin: 7 + 0, // PB0 pin: 8 + 1, // PB1 pin: 9 + 2, // PB2 pin: 10 + 3, // PB3 pin: 11 + 4, // PB4 pin: 12 + 5, // PB5 pin: 13 + 6, // PB6 pin: 14 + 7, // PB7 pin: 15 + 3, // PG3 pin: 16 + 4, // PG4 pin: 17 + 0, // PD0 pin: 18 + 1, // PD1 pin: 19 + 2, // PD2 pin: 20 + 3, // PD3 pin: 21 + 4, // PD4 pin: 22 + 5, // PD5 pin: 23 + 6, // PD6 pin: 24 + 7, // PD7 pin: 25 + 0, // PG0 pin: 26 + 1, // PG1 pin: 27 + 0, // PC0 pin: 28 + 1, // PC1 pin: 29 + 2, // PC2 pin: 30 + 3, // PC3 pin: 31 + 4, // PC4 pin: 32 + 5, // PC5 pin: 33 + 6, // PC6 pin: 34 + 7, // PC7 pin: 35 + 2, // PG2 pin: 36 + 7, // PA7 pin: 37 + 6, // PA6 pin: 38 + 5, // PA5 pin: 39 + 4, // PA4 pin: 40 + 3, // PA3 pin: 41 + 2, // PA2 pin: 42 + 1, // PA1 pin: 43 + 0, // PA0 pin: 44 + 0, // PF0 pin: 45 + 1, // PF1 pin: 46 + 2, // PF2 pin: 47 + 3, // PF3 pin: 48 + 4, // PF4 pin: 49 + 5, // PF5 pin: 50 + 6, // PF6 pin: 51 + 7, // PF7 pin: 52 + 5 // PG5 pin: 53 +}; + +#if ! defined(EI_NOTEXTERNAL) && ! defined(EI_NOTINT0) && ! defined(EI_NOTINT1) && ! defined(EI_NOTINT2) && ! defined(EI_NOTINT3) && ! defined(EI_NOTINT4) && ! defined(EI_NOTINT5) && ! defined(EI_NOTINT6) && ! defined(EI_NOTINT7) +interruptFunctionType functionPointerArrayEXTERNAL[8]; +#endif + +#ifndef EI_NOTPORTB +struct functionPointersPortB { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; + interruptFunctionType pinSix; + interruptFunctionType pinSeven; +}; +typedef struct functionPointersPortB functionPointersPortB; + +functionPointersPortB portBFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +#endif + +#endif // ifndef NEEDFORSPEED + +// For Pin Change Interrupts; since we're duplicating FALLING and RISING in software, +// we have to know how we were defined. +#ifndef EI_NOTPORTB +volatile uint8_t risingPinsPORTB=0; +volatile uint8_t fallingPinsPORTB=0; +static volatile uint8_t portSnapshotB; +#endif + +#define PORTB_VECT PCINT0_vect +/*}}}*/ + +/* LEONARDO ***************************************************************************/ +/* LEONARDO ***************************************************************************/ +/* LEONARDO ***************************************************************************/ +#elif defined __AVR_ATmega32U4__ || defined __AVR_ATmega16U4__ +#define ARDUINO_LEONARDO /*{{{*/ +#define EI_NOTPORTA +#define EI_NOTPORTC +#define EI_NOTPORTD +#define EI_NOTPORTJ +#define EI_NOTPORTK +/*}}}*/ + +#if defined EI_NOTPINCHANGE/*{{{*/ +#ifndef EI_NOTPORTB +#define EI_NOTPORTB +#endif +#endif + +#ifndef NEEDFORSPEED +#define ARDUINO_PIN_B0 17 +#define ARDUINO_PIN_B1 15 +#define ARDUINO_PIN_B2 16 +#define ARDUINO_PIN_B3 14 +#define ARDUINO_PIN_B4 8 +#define ARDUINO_PIN_B5 9 +#define ARDUINO_PIN_B6 10 +#define ARDUINO_PIN_B7 11 +#define ARDUINO_PIN_D0 3 +#define ARDUINO_PIN_D1 2 +#define ARDUINO_PIN_D2 0 +#define ARDUINO_PIN_D3 1 +#define ARDUINO_PIN_E6 7 + +/* To derive this list: + sed -n -e '1,/digital_pin_to_port_PGM/d' -e '/^}/,$d' -e '/P/p' \ + /usr/share/arduino/hardware/arduino/variants/leonardo/pins_arduino.h | \ + awk '{print " ", $5 ", // " $5 " pin: " $3}' + ...then massage the output as necessary to create the below: +*/ + +const uint8_t PROGMEM digital_pin_to_port_bit_number_PGM[] = { + 2, // PD2 pin: D0 + 3, // PD3 pin: D1 + 1, // PD1 pin: D2 + 0, // PD0 pin: D3 + 4, // PD4 pin: D4 + 6, // PC6 pin: D5 + 7, // PD7 pin: D6 + 6, // PE6 pin: D7 + 4, // PB4 pin: D8 // we really only care about Port B, but I don't know that + 5, // PB5 pin: D9 // shortening this array and doing array index arithmetic + 6, // PB6 pin: D10 // would make the code any shorter. + 7, // PB7 pin: D11 + 6, // PD6 pin: D12 + 7, // PC7 pin: D13 + 3, // PB3 pin: D14 MISO + 1, // PB1 pin: D15 SCK + 2, // PB2 pin: D16 MOSI + 0 // PB0 pin: D17 SS (RXLED). Available on non-Leonardo 32u4 boards, at least (exposed on the Leonardo??) +// There are no ports we care about after pin 17. +}; + + +#if ! defined(EI_NOTEXTERNAL) && ! defined(EI_NOTINT0) && ! defined(EI_NOTINT1) && ! defined(EI_NOTINT2) && ! defined(EI_NOTINT3) && ! defined(EI_NOTINT6) +interruptFunctionType functionPointerArrayEXTERNAL[5]; +#endif + +#ifndef EI_NOTPORTB +struct functionPointersPortB { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; + interruptFunctionType pinSix; + interruptFunctionType pinSeven; +}; +typedef struct functionPointersPortB functionPointersPortB; + +functionPointersPortB portBFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +#endif +#endif // NEEDFOR SPEED + +#ifndef EI_NOTPORTB +// For Pin Change Interrupts; since we're duplicating FALLING and RISING in software, +// we have to know how we were defined. +volatile uint8_t risingPinsPORTB=0; +volatile uint8_t fallingPinsPORTB=0; + +// for the saved state of the ports +static volatile uint8_t portSnapshotB; +#endif +#define PORTB_VECT PCINT0_vect +/*}}}*/ + +/* 644/1284 ***************************************************************************/ +/* 644/1284 ***************************************************************************/ +/* 644/1284 ***************************************************************************/ +#elif defined __AVR_ATmega1284P__ || defined __AVR_ATmega1284__ || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) +#define MIGHTY1284 /*{{{*/ +#define EI_NOTPORTJ +#define EI_NOTPORTK /*}}}*/ + +#if defined EI_NOTPINCHANGE/*{{{*/ +#ifndef EI_NOTPORTA +#define EI_NOTPORTA +#endif +#ifndef EI_NOTPORTB +#define EI_NOTPORTB +#endif +#ifndef EI_NOTPORTC +#define EI_NOTPORTC +#endif +#ifndef EI_NOTPORTD +#define EI_NOTPORTD +#endif +#endif + +#ifndef INPUT_PULLUP +#define INPUT_PULLUP 0x2 +#endif + +#ifndef NEEDFORSPEED +#if defined BOBUINO_PINOUT +#define ARDUINO_PIN_A0 21 +#define ARDUINO_PIN_A1 20 +#define ARDUINO_PIN_A2 19 +#define ARDUINO_PIN_A3 18 +#define ARDUINO_PIN_A4 17 +#define ARDUINO_PIN_A5 16 +#define ARDUINO_PIN_A6 15 +#define ARDUINO_PIN_A7 14 +#define ARDUINO_PIN_B0 4 +#define ARDUINO_PIN_B1 5 +#define ARDUINO_PIN_B2 6 // INT2 +#define ARDUINO_PIN_B3 7 +#define ARDUINO_PIN_B4 10 +#define ARDUINO_PIN_B5 11 +#define ARDUINO_PIN_B6 12 +#define ARDUINO_PIN_B7 13 +#define ARDUINO_PIN_C0 22 +#define ARDUINO_PIN_C1 23 +#define ARDUINO_PIN_C2 24 +#define ARDUINO_PIN_C3 25 +#define ARDUINO_PIN_C4 26 +#define ARDUINO_PIN_C5 27 +#define ARDUINO_PIN_C6 28 +#define ARDUINO_PIN_C7 29 +#define ARDUINO_PIN_D0 0 +#define ARDUINO_PIN_D1 1 +#define ARDUINO_PIN_D2 2 // INT0 +#define ARDUINO_PIN_D3 3 // INT1 +#define ARDUINO_PIN_D4 30 +#define ARDUINO_PIN_D5 8 +#define ARDUINO_PIN_D6 9 +#define ARDUINO_PIN_D7 31 + +const uint8_t PROGMEM digital_pin_to_port_bit_number_PGM[] = { + 0, // PD0 + 1, // PD1 + 2, // PD2 + 3, // PD3 + 0, // PB0 + 1, // PB1 + 2, // PB2 + 3, // PB3 + 5, // PD5 + 6, // PD6 + + 4, // PB4 + 5, // PB5 + 6, // PB6 + 7, // PB7 + 7, // PA7 + 6, // PA6 + 5, // PA5 + 4, // PA4 + 3, // PA3 + 2, // PA2 + + 1, // PA1 + 0, // PA0 + 0, // PC0 + 1, // PC1 + 2, // PC2 + 3, // PC3 + 4, // PC4 + 5, // PC5 + 6, // PC6 + 7, // PC7 + + 4, // PD4 + 7, // PD7 +}; + +#else +#define ARDUINO_PIN_A0 24 +#define ARDUINO_PIN_A1 25 +#define ARDUINO_PIN_A2 26 +#define ARDUINO_PIN_A3 27 +#define ARDUINO_PIN_A4 28 +#define ARDUINO_PIN_A5 29 +#define ARDUINO_PIN_A6 30 +#define ARDUINO_PIN_A7 31 +#define ARDUINO_PIN_C0 16 +#define ARDUINO_PIN_C1 17 +#define ARDUINO_PIN_C2 18 +#define ARDUINO_PIN_C3 19 +#define ARDUINO_PIN_C4 20 +#define ARDUINO_PIN_C5 21 +#define ARDUINO_PIN_C6 22 +#define ARDUINO_PIN_C7 23 + +// For boards with the 44 pin options: vectors B & D are reversed +// Thanks to Sara Damiano for these updates!!! +#if defined ARDUINO_AVR_ENVIRODIY_MAYFLY || defined ARDUINO_AVR_SODAQ_MBILI +#define ARDUINO_PIN_B0 8 +#define ARDUINO_PIN_B1 9 +#define ARDUINO_PIN_B2 10 // INT2 +#define ARDUINO_PIN_B3 11 +#define ARDUINO_PIN_B4 12 +#define ARDUINO_PIN_B5 13 +#define ARDUINO_PIN_B6 14 +#define ARDUINO_PIN_B7 15 +#define ARDUINO_PIN_D0 0 +#define ARDUINO_PIN_D1 1 +#define ARDUINO_PIN_D2 2 // INT0 +#define ARDUINO_PIN_D3 3 // INT1 +#define ARDUINO_PIN_D4 4 +#define ARDUINO_PIN_D5 5 +#define ARDUINO_PIN_D6 6 +#define ARDUINO_PIN_D7 7 +#else +#define ARDUINO_PIN_B0 0 +#define ARDUINO_PIN_B1 1 +#define ARDUINO_PIN_B2 2 // INT2 +#define ARDUINO_PIN_B3 3 +#define ARDUINO_PIN_B4 4 +#define ARDUINO_PIN_B5 5 +#define ARDUINO_PIN_B6 6 +#define ARDUINO_PIN_B7 7 +#define ARDUINO_PIN_D0 8 +#define ARDUINO_PIN_D1 9 +#define ARDUINO_PIN_D2 10 // INT0 +#define ARDUINO_PIN_D3 11 // INT1 +#define ARDUINO_PIN_D4 12 +#define ARDUINO_PIN_D5 13 +#define ARDUINO_PIN_D6 14 +#define ARDUINO_PIN_D7 15 +#endif + +const uint8_t PROGMEM digital_pin_to_port_bit_number_PGM[] = { + 0, // 0 == port B, 0 + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 0, // 8 == port D, 0 + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 0, // 16 == port C, 0 + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 0, // 24 == port A, 0 + 1, + 2, + 3, + 4, + 5, + 6, + 7 +}; +#endif + + +#if ! defined(EI_NOTEXTERNAL) && ! defined(EI_NOTINT0) && ! defined(EI_NOTINT1) && ! defined(EI_NOTINT2) +interruptFunctionType functionPointerArrayEXTERNAL[3]; +#endif + +struct functionPointers { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; + interruptFunctionType pinSix; + interruptFunctionType pinSeven; +}; + +#ifndef EI_NOTPORTA +typedef struct functionPointers functionPointersPortA; +functionPointers portAFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +#endif + +#ifndef EI_NOTPORTB +typedef struct functionPointers functionPointersPortB; +functionPointersPortB portBFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +#endif + +#ifndef EI_NOTPORTC +typedef struct functionPointers functionPointersPortC; +functionPointersPortC portCFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +#endif + +#ifndef EI_NOTPORTD +typedef struct functionPointers functionPointersPortD; +functionPointersPortD portDFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +#endif +#endif // NEEDFORSPEED + +#ifndef EI_NOTPORTA +volatile uint8_t risingPinsPORTA=0; +volatile uint8_t fallingPinsPORTA=0; +// for the saved state of the ports +static volatile uint8_t portSnapshotA; +#endif + +#ifndef EI_NOTPORTB +volatile uint8_t risingPinsPORTB=0; +volatile uint8_t fallingPinsPORTB=0; +static volatile uint8_t portSnapshotB; +#endif + +#ifndef EI_NOTPORTC +volatile uint8_t risingPinsPORTC=0; +volatile uint8_t fallingPinsPORTC=0; +static volatile uint8_t portSnapshotC; +#endif + +#ifndef EI_NOTPORTD +volatile uint8_t risingPinsPORTD=0; +volatile uint8_t fallingPinsPORTD=0; +static volatile uint8_t portSnapshotD; +#endif + +// the vectors (eg, "PCINT0_vect") are defined in the avr.h files, like iom1284p.h +#define PORTA_VECT PCINT0_vect +#define PORTB_VECT PCINT1_vect +#define PORTC_VECT PCINT2_vect +#define PORTD_VECT PCINT3_vect +/*}}}*/ + +/* 24/44/84 ***************************************************************************/ +/* 24/44/84 ***************************************************************************/ +/* 24/44/84 ***************************************************************************/ +#elif defined __AVR_ATtiny24__ || defined __AVR_ATtiny24A__ || defined __AVR_ATtiny44__ || defined __AVR_ATtiny44A__ || defined __AVR_ATtiny84__ || defined __AVR_ATtiny84A_ +#define EI_ATTINY24 /*{{{*/ +#define EI_NOTPORTC +#define EI_NOTPORTD +#define EI_NOTPORTJ +#define EI_NOTPORTK +/*}}}*/ + +#define EI_NOTINT1 + +#if defined EI_NOTPINCHANGE/*{{{*/ +#ifndef EI_NOTPORTA +#define EI_NOTPORTA +#endif +#ifndef EI_NOTPORTB +#define EI_NOTPORTB +#endif +#endif + +#ifndef INPUT_PULLUP +#define INPUT_PULLUP 0x2 +#endif + +#ifndef NEEDFORSPEED + +#define ARDUINO_PIN_B3 11 +#define ARDUINO_PIN_B2 8 +#define ARDUINO_PIN_B1 9 +#define ARDUINO_PIN_B0 10 +#define ARDUINO_PIN_A0 0 +#define ARDUINO_PIN_A1 1 +#define ARDUINO_PIN_A2 2 +#define ARDUINO_PIN_A3 3 +#define ARDUINO_PIN_A4 4 +#define ARDUINO_PIN_A5 5 +#define ARDUINO_PIN_A6 6 +#define ARDUINO_PIN_A7 7 + +const uint8_t PROGMEM digital_pin_to_port_bit_number_PGM[] = { + 0, // pin 0 == port A, bit 0 + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 2, // pin 8 = port B, bit 2 + 1, + 0, + 3 +}; +#if ! defined(EI_NOTEXTERNAL) && ! defined(EI_NOTINT0) +interruptFunctionType externalFunctionPointer=0; +#endif + +// For Pin Change Interrupts; since we're duplicating FALLING and RISING in software, +// we have to know how the ports were defined. +#ifndef EI_NOTPORTA +struct functionPointersPortA { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; + interruptFunctionType pinSix; + interruptFunctionType pinSeven; +}; +typedef struct functionPointersPortA functionPointersPortA; + +functionPointersPortA portAFunctions = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +#endif // ifndef EI_NOTPORTA +#ifndef EI_NOTPORTB +struct functionPointersPortB { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; +}; +typedef struct functionPointersPortB functionPointersPortB; + +functionPointersPortB portBFunctions = { NULL, NULL, NULL, NULL }; +#endif // ifndef EI_NOTPORTB +#endif // NEEDFORSPEED + +// For Pin Change Interrupts; since we're duplicating FALLING and RISING in software, +// we have to know how we were defined. +#ifndef EI_NOTPORTA +volatile uint8_t risingPinsPORTA=0; +volatile uint8_t fallingPinsPORTA=0; +// for the saved state of the ports +static volatile uint8_t portSnapshotA; +#endif + +#ifndef EI_NOTPORTB +volatile uint8_t risingPinsPORTB=0; +volatile uint8_t fallingPinsPORTB=0; +// for the saved state of the ports +static volatile uint8_t portSnapshotB; +#endif + +#define PORTA_VECT PCINT0_vect +#define PORTB_VECT PCINT1_vect/*}}}*/ + +/* 25/45/85 ***************************************************************************/ +/* 25/45/85 ***************************************************************************/ +/* 25/45/85 ***************************************************************************/ +#elif defined __AVR_ATtiny25__ || defined __AVR_ATtiny45__ || defined __AVR_ATtiny85__ +#define EI_ATTINY25 /*{{{*/ +#define EI_NOTPORTA +#define EI_NOTPORTC +#define EI_NOTPORTD +#define EI_NOTPORTJ +#define EI_NOTPORTK +/*}}}*/ + +#if defined EI_NOTPINCHANGE/*{{{*/ +#ifndef EI_NOTPORTB +#define EI_NOTPORTB +#endif +#endif + +#ifndef INPUT_PULLUP +#define INPUT_PULLUP 0x2 +#endif + +#ifndef NEEDFORSPEED + +#define ARDUINO_PIN_B0 0 +#define ARDUINO_PIN_B1 1 +#define ARDUINO_PIN_B2 2 +#define ARDUINO_PIN_B3 3 +#define ARDUINO_PIN_B4 4 +#define ARDUINO_PIN_B5 5 + +const uint8_t PROGMEM digital_pin_to_port_bit_number_PGM[] = { + 0, // pin 0 == port B, bit 0 + 1, + 2, + 3, + 4, + 5 +}; +#if ! defined(EI_NOTEXTERNAL) && ! defined(EI_NOTINT0) +interruptFunctionType externalFunctionPointer=0; +#endif + +#ifndef EI_NOTPORTB +struct functionPointersPortB { + interruptFunctionType pinZero; + interruptFunctionType pinOne; + interruptFunctionType pinTwo; + interruptFunctionType pinThree; + interruptFunctionType pinFour; + interruptFunctionType pinFive; +}; +typedef struct functionPointersPortB functionPointersPortB; + +functionPointersPortB portBFunctions = { NULL, NULL, NULL, NULL, NULL, NULL }; + +#endif // ifndef EI_NOTPORTB +#endif // NEEDFORSPEED + +#ifndef EI_NOTPORTB +// the vectors (eg, "PCINT0_vect") are defined in the avr.h files, like iom1284p.h +// For Pin Change Interrupts; since we're duplicating FALLING and RISING in software, +// we have to know how the ports were defined. +volatile uint8_t risingPinsPORTB=0; +volatile uint8_t fallingPinsPORTB=0; +// for the saved state of the ports +static volatile uint8_t portSnapshotB; +#endif + +#define PORTB_VECT PCINT0_vect/*}}}*/ + +#endif // #if defined __AVR_ATmega168__ || defined __AVR_ATmega168A__ ... (etc.) ... + +// =========================================================================================== +// END END END DATA STRUCTURES =============================================================== +// =========================================================================================== + +// From /usr/share/arduino/hardware/arduino/cores/robot/Arduino.h +// #define CHANGE 1 +// #define FALLING 2 +// #define RISING 3 + +#if !(defined EI_ATTINY24) && !(defined EI_ATTINY25) +// Example: EI_printPSTR("This is a nice long string that takes no static ram"); +#define EI_printPSTR(x) EI_SerialPrint_P(PSTR(x)) +void EI_SerialPrint_P(const char *str) { + for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c); +} +#endif + + +// =========================================================================================== +// =========================================================================================== +// enableInterrupt(interrupDesignator, userFunction, mode); ================================== +// =========================================================================================== +// =========================================================================================== + +// "interruptDesignator" is simply the Arduino pin optionally OR'ed with +// PINCHANGEINTERRUPT (== 0x80) +void enableInterrupt(uint8_t interruptDesignator, interruptFunctionType userFunction, uint8_t mode) { + uint8_t arduinoPin; + uint8_t portNumber=0; + uint8_t portMask=0; +#ifndef NEEDFORSPEED + uint8_t portBitNumber; // when an interrupted pin is found, this will be used to choose the function. + interruptFunctionType *calculatedPointer; +#endif + + arduinoPin=interruptDesignator & ~PINCHANGEINTERRUPT; + + // ************************************************************************************* + // Pin Change Interrupts + // ************************************************************************************* + +/*{{{*/ +#if defined ARDUINO_328 + if ( (interruptDesignator & PINCHANGEINTERRUPT) || (arduinoPin != 2 && arduinoPin != 3) ) { +#elif defined MIGHTY1284 + if ( (interruptDesignator & PINCHANGEINTERRUPT) || + (arduinoPin != ARDUINO_PIN_B2 && arduinoPin != ARDUINO_PIN_D2 && arduinoPin != ARDUINO_PIN_D3) ) { +#elif defined ARDUINO_LEONARDO + if ( (arduinoPin > 3) && (arduinoPin != 7) ) { +#elif defined EI_ATTINY24 + if ( (interruptDesignator & PINCHANGEINTERRUPT) || (arduinoPin != 8) ) { +#elif defined EI_ATTINY25 + if ( (interruptDesignator & PINCHANGEINTERRUPT) || (arduinoPin != 2) ) { +#endif +#if defined ARDUINO_328 || defined MIGHTY1284 || defined ARDUINO_LEONARDO + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin]); + portNumber=pgm_read_byte(&digital_pin_to_port_PGM[arduinoPin]); +#elif defined EI_ATTINY25 + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin]); + portNumber=PB; +#elif defined EI_ATTINY24 + // This is not a true Arduino pin... it's pin 4 on the chip, which is RESET. + // I could imagine that one would want to use that pin for something other than RESET. + if (arduinoPin == 11) { + portMask=_BV(3); + portNumber=PB; + } else { + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin]); + portNumber=pgm_read_byte(&digital_pin_to_port_PGM[arduinoPin]); + } +#elif defined ARDUINO_MEGA +#if defined __AVR_ATmega640__ || defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ + // NOTE: PJ2-6 and PE6 & 7 are not exposed on the Arduino, but they are supported here + // for software interrupts and support of non-Arduino platforms which expose more pins. + // PJ2-6 are called pins 70-74, PE6 is pin 75, PE7 is pin 76. + if ( (arduinoPin != 2 && arduinoPin != 3 && arduinoPin != 75 && arduinoPin != 76 + && (arduinoPin < 18 || arduinoPin > 21)) + ) { + if (arduinoPin > 69) { // Dastardly tricks to support PortJ 2-7 + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin-6]); // Steal from PK + portNumber=PJ; + } else { + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin]); + portNumber=pgm_read_byte(&digital_pin_to_port_PGM[arduinoPin]); + } +#elif defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + if (!(((arduinoPin >= 4) && (arduinoPin <= 7)) || ((arduinoPin >= 18) && (arduinoPin <=21)))) { + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin]); + portNumber=pgm_read_byte(&digital_pin_to_port_PGM[arduinoPin]); +#endif +#else +#error Unsupported Arduino platform +#endif + + // ************************************************************************************* + // Store the rising/falling pins + // ************************************************************************************* + + if ((mode == RISING) || (mode == CHANGE)) { +#define EI_SECTION_RISING + +#if defined MIGHTY1284 +#include "utility/ei_PinChange1284.h" +#elif defined ARDUINO_328 +#include "utility/ei_PinChange328.h" +#elif defined ARDUINO_MEGA +#include "utility/ei_PinChange2560.h" +#elif defined ARDUINO_LEONARDO +#include "utility/ei_PinChangeLeonardo.h" +#elif defined EI_ATTINY24 +#include "utility/ei_PinChangeTiny24.h" +#elif defined EI_ATTINY25 +#include "utility/ei_PinChangeTiny25.h" +#endif +#undef EI_SECTION_RISING + } + + if ((mode == FALLING) || (mode == CHANGE)) { +#define EI_SECTION_FALLING +#if defined MIGHTY1284 +#include "utility/ei_PinChange1284.h" +#elif defined ARDUINO_328 +#include "utility/ei_PinChange328.h" +#elif defined ARDUINO_MEGA +#include "utility/ei_PinChange2560.h" +#elif defined ARDUINO_LEONARDO +#include "utility/ei_PinChangeLeonardo.h" +#elif defined EI_ATTINY24 +#include "utility/ei_PinChangeTiny24.h" +#elif defined EI_ATTINY25 +#include "utility/ei_PinChangeTiny25.h" +#endif +#undef EI_SECTION_FALLING + } + +#ifndef NEEDFORSPEED + // When an interrupted pin is found, this will be used to choose the function. + // This is used in the utility/<#included files>, below. + portBitNumber=pgm_read_byte(&digital_pin_to_port_bit_number_PGM[arduinoPin]); +#endif + + // ************************************************************************************* + // assign the function to be run in the ISR + // save the initial value of the port + // initialize interrupt registers PCMSKx and PCICR + // ************************************************************************************* + +#define EI_SECTION_ASSIGNFUNCTIONSREGISTERS +#if defined MIGHTY1284 +#include "utility/ei_PinChange1284.h" +#elif defined ARDUINO_328 +#include "utility/ei_PinChange328.h" +#elif defined ARDUINO_MEGA +#include "utility/ei_PinChange2560.h" +#elif defined ARDUINO_LEONARDO +#include "utility/ei_PinChangeLeonardo.h" +#elif defined EI_ATTINY24 +#include "utility/ei_PinChangeTiny24.h" +#elif defined EI_ATTINY25 +#include "utility/ei_PinChangeTiny25.h" +#endif +#undef EI_SECTION_ASSIGNFUNCTIONSREGISTERS + + *pcmsk |= portMask; // appropriate PCMSKn bit is set, e.g. this could be PCMSK1 |= portMask; + + // With the exception of the Global Interrupt Enable bit in SREG, interrupts on the arduinoPin + // are now ready. GIE may have already been set on a previous enable, so it's important + // to take note of the order in which things were done, above./*}}}*/ + + // ************************************************************************************* + // External Interrupts + // ************************************************************************************* + + } else {/*{{{*/ +#ifndef EI_NOTEXTERNAL + uint8_t origSREG; // to save for interrupts + origSREG = SREG; + cli(); // no interrupts while we're setting up an interrupt. + +#define EI_SECTION_ENABLEEXTERNAL +#if defined MIGHTY1284 +#include "utility/ei_External1284.h" +#elif defined ARDUINO_328 +#include "utility/ei_External328.h" +#elif defined ARDUINO_MEGA +#include "utility/ei_External2560.h" +#elif defined ARDUINO_LEONARDO +#include "utility/ei_ExternalLeonardo.h" +#elif defined EI_ATTINY24 +#include "utility/ei_ExternalTiny24.h" +#elif defined EI_ATTINY25 +#include "utility/ei_ExternalTiny25.h" +#endif +#undef EI_SECTION_ENABLEEXTERNAL + + SREG=origSREG; +#endif + } +} +/*}}}*/ + +// =========================================================================================== +// =========================================================================================== +// disableInterrupt(interrupDesignator); ===================================================== +// =========================================================================================== +// =========================================================================================== +void disableInterrupt (uint8_t interruptDesignator) { + + uint8_t origSREG; // to save for interrupts + uint8_t arduinoPin; + uint8_t portMask=0; +#if ! (defined EI_ATTINY25) + uint8_t portNumber=0; +#endif + + origSREG = SREG; + cli(); + arduinoPin=interruptDesignator & ~PINCHANGEINTERRUPT; + +/*{{{*/ +#if defined ARDUINO_328 + if ( (interruptDesignator & PINCHANGEINTERRUPT) || (arduinoPin != 2 && arduinoPin != 3) ) { +#elif defined MIGHTY1284 + if ( (interruptDesignator & PINCHANGEINTERRUPT) || + (arduinoPin != ARDUINO_PIN_B2 && arduinoPin != ARDUINO_PIN_D2 && arduinoPin != ARDUINO_PIN_D3) ) { +#elif defined EI_ATTINY24 + if ( (interruptDesignator & PINCHANGEINTERRUPT) || (arduinoPin != 8) ) { +#elif defined EI_ATTINY25 + if ( (interruptDesignator & PINCHANGEINTERRUPT) || (arduinoPin != 2) ) { +#elif defined ARDUINO_LEONARDO + if ( (arduinoPin > 3) && (arduinoPin != 7) ) { +#endif +#if defined ARDUINO_328 || defined MIGHTY1284 || defined ARDUINO_LEONARDO + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin]); + portNumber=pgm_read_byte(&digital_pin_to_port_PGM[arduinoPin]); +#elif defined EI_ATTINY24 + // This is not a true Arduino pin... it's pin 4 on the chip, which is RESET. + // I could imagine that one would want to use that pin for something other than RESET. + if (arduinoPin == 11) { + portMask=_BV(3); + portNumber=PB; + } else { + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin]); + portNumber=pgm_read_byte(&digital_pin_to_port_PGM[arduinoPin]); + } +#elif defined EI_ATTINY25 + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin]); +#elif defined ARDUINO_MEGA + // NOTE: PJ2-6 and PE6 & 7 are not exposed on the Arduino, but they are supported here + // for software interrupts and support of non-Arduino platforms which expose more pins. + // PJ2-6 are called pins 70-74, PE6 is pin 75, PE7 is pin 76. + if ( (arduinoPin != 2 && arduinoPin != 3 && arduinoPin != 75 && arduinoPin != 76 + && (arduinoPin < 18 || arduinoPin > 21)) + ) { + if (arduinoPin > 69) { // Dastardly tricks to support PortJ 2-7 + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin-6]); // Steal from PK + portNumber=PJ; + } else { + portMask=pgm_read_byte(&digital_pin_to_bit_mask_PGM[arduinoPin]); + portNumber=pgm_read_byte(&digital_pin_to_port_PGM[arduinoPin]); + } +#else +#error Unsupported Arduino platform +#endif + +#define EI_SECTION_DISABLEPINCHANGE +#if defined MIGHTY1284 +#include "utility/ei_PinChange1284.h" +#elif defined ARDUINO_328 +#include "utility/ei_PinChange328.h" +#elif defined ARDUINO_MEGA +#include "utility/ei_PinChange2560.h" +#elif defined LEONARDO +#include "utility/ei_PinChangeLeonardo.h" +#elif defined EI_ATTINY24 +#include "utility/ei_PinChangeTiny24.h" +#elif defined EI_ATTINY25 +#include "utility/ei_PinChangeTiny25.h" +#endif +#undef EI_SECTION_DISABLEPINCHANGE + } else { +#ifndef EI_NOTEXTERNAL +#define EI_SECTION_DISABLEEXTERNAL +#if defined MIGHTY1284 +#include "utility/ei_External1284.h" +#elif defined ARDUINO_328 +#include "utility/ei_External328.h" +#elif defined ARDUINO_MEGA +#include "utility/ei_External2560.h" +#elif defined ARDUINO_LEONARDO +#include "utility/ei_ExternalLeonardo.h" +#elif defined ATTINY24 +#include "utility/ei_ExternalTiny24.h" +#elif defined EI_ATTINY25 +#include "utility/ei_ExternalTiny25.h" +#endif +#undef EI_SECTION_DISABLEEXTERNAL +#endif + } + SREG = origSREG;/*}}}*/ + +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +////////////////////// ISRs ///////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +// ************************************************************************************* +// External Interrupts +// ************************************************************************************* +#ifndef EI_NOTEXTERNAL +#ifndef EI_NOTINT0 +ISR(INT0_vect) {/*{{{*/ +#ifndef NEEDFORSPEED +#ifdef EI_ARDUINO_INTERRUPTED_PIN +#if defined MIGHTY1284 + arduinoInterruptedPin=ARDUINO_PIN_D2; arduinoPinState=PIND & _BV(2); +#elif defined ARDUINO_MEGA + arduinoInterruptedPin=ARDUINO_PIN_D0; arduinoPinState=PIND & _BV(0); +#elif defined ARDUINO_LEONARDO + arduinoInterruptedPin=ARDUINO_PIN_D0; arduinoPinState=PIND & _BV(0); +#elif defined ARDUINO_328 + arduinoInterruptedPin=ARDUINO_PIN_D2; arduinoPinState=PIND & _BV(2); +#elif defined EI_ATTINY24 + arduinoInterruptedPin=ARDUINO_PIN_B2; arduinoPinState=PINB & _BV(2); +#elif defined EI_ATTINY25 + arduinoInterruptedPin=ARDUINO_PIN_B0; arduinoPinState=PINB & _BV(0); +#endif +#endif // EI_ARDUINO_INTERRUPTED_PIN +#if ! defined EI_ATTINY25 && ! defined EI_ATTINY24 + (*functionPointerArrayEXTERNAL[0])(); +#else + externalFunctionPointer(); +#endif +#else +#if defined ARDUINO_AVR_ENVIRODIY_MAYFLY || defined ARDUINO_AVR_SODAQ_MBILI + INTERRUPT_FLAG_PIN2++; +#elif defined MIGHTY1284 + INTERRUPT_FLAG_PIN10++; +#endif +#if defined ARDUINO_MEGA +#ifdef INTERRUPT_FLAG_PIN21 + INTERRUPT_FLAG_PIN21++; +#endif +#endif +#if defined ARDUINO_LEONARDO +#ifdef INTERRUPT_FLAG_PIN3 + INTERRUPT_FLAG_PIN3++; +#endif +#endif +#if defined ARDUINO_328 +#ifdef INTERRUPT_FLAG_PIN2 + INTERRUPT_FLAG_PIN2++; +#endif +#endif + +#if defined EI_ATTINY24 +#ifdef INTERRUPT_FLAG_PIN8 + INTERRUPT_FLAG_PIN8++; +#endif +#endif +#if defined EI_ATTINY25 +#ifdef INTERRUPT_FLAG_PIN2 + INTERRUPT_FLAG_PIN2++; +#endif +#endif + +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTINT0 + +#if ! defined(EI_ATTINY24) && ! defined(EI_ATTINY25) +#ifndef EI_NOTINT1 +ISR(INT1_vect) {/*{{{*/ +#ifndef NEEDFORSPEED +#ifdef EI_ARDUINO_INTERRUPTED_PIN +#if defined MIGHTY1284 + arduinoInterruptedPin=ARDUINO_PIN_D3; arduinoPinState=PIND & _BV(3); +#elif defined ARDUINO_MEGA + arduinoInterruptedPin=ARDUINO_PIN_D1; arduinoPinState=PIND & _BV(1); +#elif defined ARDUINO_LEONARDO + arduinoInterruptedPin=ARDUINO_PIN_D1; arduinoPinState=PIND & _BV(1); +#elif defined ARDUINO_328 + arduinoInterruptedPin=ARDUINO_PIN_D3; arduinoPinState=PIND & _BV(3); +#endif +#endif // EI_ARDUINO_INTERRUPTED_PIN + (*functionPointerArrayEXTERNAL[1])(); +#else +#if defined ARDUINO_AVR_ENVIRODIY_MAYFLY || defined ARDUINO_AVR_SODAQ_MBILI + INTERRUPT_FLAG_PIN3++; +#elif defined MIGHTY1284 + INTERRUPT_FLAG_PIN11++; +#endif +#if defined ARDUINO_MEGA +#ifdef INTERRUPT_FLAG_PIN20 + INTERRUPT_FLAG_PIN20++; +#endif +#endif +#if defined ARDUINO_LEONARDO +#ifdef INTERRUPT_FLAG_PIN2 + INTERRUPT_FLAG_PIN2++; +#endif +#endif +#if defined ARDUINO_328 +#ifdef INTERRUPT_FLAG_PIN3 + INTERRUPT_FLAG_PIN3++; +#endif +#endif +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTINT1 +#endif + +#if defined ARDUINO_MEGA || defined ARDUINO_LEONARDO || defined MIGHTY1284 +#ifndef EI_NOTINT2 +ISR(INT2_vect) {/*{{{*/ +#ifndef NEEDFORSPEED +#ifdef EI_ARDUINO_INTERRUPTED_PIN +#if defined MIGHTY1284 + arduinoInterruptedPin=ARDUINO_PIN_B2; arduinoPinState=PINB & _BV(2); +#elif defined ARDUINO_MEGA + arduinoInterruptedPin=ARDUINO_PIN_D2; arduinoPinState=PIND & _BV(2); +#elif defined ARDUINO_LEONARDO + arduinoInterruptedPin=ARDUINO_PIN_D2; arduinoPinState=PIND & _BV(2); +#endif +#endif // EI_ARDUINO_INTERRUPTED_PIN + (*functionPointerArrayEXTERNAL[2])(); +#else +#if defined ARDUINO_AVR_ENVIRODIY_MAYFLY || defined ARDUINO_AVR_SODAQ_MBILI + INTERRUPT_FLAG_PIN10++; +#elif defined MIGHTY1284 + INTERRUPT_FLAG_PIN2++; +#endif +#if defined ARDUINO_MEGA +#ifdef INTERRUPT_FLAG_PIN19 + INTERRUPT_FLAG_PIN19++; +#endif +#else +#ifdef INTERRUPT_FLAG_PIN0 + INTERRUPT_FLAG_PIN0++; +#endif +#endif +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTINT2 +#endif // ARDUINO_MEGA || ARDUINO_LEONARDO || MIGHTY1284 + +#if defined ARDUINO_MEGA || defined ARDUINO_LEONARDO +#ifndef EI_NOTINT3 +ISR(INT3_vect) {/*{{{*/ +#ifndef NEEDFORSPEED +#ifdef EI_ARDUINO_INTERRUPTED_PIN +#if defined ARDUINO_MEGA + arduinoInterruptedPin=ARDUINO_PIN_D3; arduinoPinState=PIND & _BV(3); +#elif defined ARDUINO_LEONARDO + arduinoInterruptedPin=ARDUINO_PIN_D3; arduinoPinState=PIND & _BV(3); +#endif +#endif // EI_ARDUINO_INTERRUPTED_PIN + (*functionPointerArrayEXTERNAL[3])(); +#else +#if defined ARDUINO_MEGA +#ifdef INTERRUPT_FLAG_PIN18 + INTERRUPT_FLAG_PIN18++; +#endif +#else +#ifdef INTERRUPT_FLAG_PIN1 + INTERRUPT_FLAG_PIN1++; +#endif +#endif +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTINT3 +#endif // ARDUINO_MEGA || ARDUINO_LEONARDO + +#if defined ARDUINO_MEGA +#ifndef EI_NOTINT4 +ISR(INT4_vect) {/*{{{*/ +#ifndef NEEDFORSPEED +#ifdef EI_ARDUINO_INTERRUPTED_PIN + arduinoInterruptedPin=ARDUINO_PIN_E4; arduinoPinState=PINE & _BV(4); +#endif // EI_ARDUINO_INTERRUPTED_PIN + (*functionPointerArrayEXTERNAL[4])(); +#else +#ifdef INTERRUPT_FLAG_PIN2 + INTERRUPT_FLAG_PIN2++; +#endif +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTINT4 + +#ifndef EI_NOTINT5 +ISR(INT5_vect) {/*{{{*/ +#ifndef NEEDFORSPEED +#ifdef EI_ARDUINO_INTERRUPTED_PIN + arduinoInterruptedPin=ARDUINO_PIN_E5; arduinoPinState=PINE & _BV(5); +#endif // EI_ARDUINO_INTERRUPTED_PIN + (*functionPointerArrayEXTERNAL[5])(); +#else +#ifdef INTERRUPT_FLAG_PIN3 + INTERRUPT_FLAG_PIN3++; +#endif +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTINT5 + +#ifndef EI_NOTINT6 +ISR(INT6_vect) {/*{{{*/ +#ifndef NEEDFORSPEED +#ifdef EI_ARDUINO_INTERRUPTED_PIN + arduinoInterruptedPin=ARDUINO_PIN_E6; arduinoPinState=PINE & _BV(6); +#endif // EI_ARDUINO_INTERRUPTED_PIN + (*functionPointerArrayEXTERNAL[6])(); +#else +#ifdef INTERRUPT_FLAG_PIN75 + INTERRUPT_FLAG_PIN75++; +#endif +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTINT6 + +#ifndef EI_NOTINT7 +ISR(INT7_vect) {/*{{{*/ +#ifndef NEEDFORSPEED +#ifdef EI_ARDUINO_INTERRUPTED_PIN + arduinoInterruptedPin=ARDUINO_PIN_E7; arduinoPinState=PINE & _BV(7); +#endif // EI_ARDUINO_INTERRUPTED_PIN + (*functionPointerArrayEXTERNAL[7])(); +#else +#ifdef INTERRUPT_FLAG_PIN76 + INTERRUPT_FLAG_PIN76++; +#endif +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTINT7 +#endif // defined ARDUINO_MEGA + +#if defined ARDUINO_LEONARDO +#ifndef EI_NOTINT6 +ISR(INT6_vect) {/*{{{*/ +#ifndef NEEDFORSPEED +#ifdef EI_ARDUINO_INTERRUPTED_PIN + arduinoInterruptedPin=ARDUINO_PIN_E6; arduinoPinState=PINE & _BV(6); +#endif // EI_ARDUINO_INTERRUPTED_PIN + (*functionPointerArrayEXTERNAL[4])(); +#else +#ifdef INTERRUPT_FLAG_PIN7 + INTERRUPT_FLAG_PIN7++; +#endif +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTINT6 +#endif // defined ARDUINO_LEONARDO +#endif // EI_NOTEXTERNAL +// ************************************************************************************* +// ************************************************************************************* + +// ************************************************************************************* +// Pin Change Interrupts +// ************************************************************************************* +#ifndef EI_NOTPORTA +ISR(PORTA_VECT) {/*{{{*/ + uint8_t current; + uint8_t interruptMask; + uint8_t changedPins; + uint8_t tmp; + + current=PINA; +// If we trust the compiler to do this, it will use an extra register... +// changedPins=(portSnapshotA ^ current) & +// ((risingPinsPORTA & current) | (fallingPinsPORTA & ~current)); +// ...so we do it ourselves: + changedPins = portSnapshotA ^ current; + tmp = risingPinsPORTA & current; + interruptMask = fallingPinsPORTA & ~current; + interruptMask = interruptMask | tmp; + interruptMask = changedPins & interruptMask; + interruptMask = PCMSK0 & interruptMask; + + + portSnapshotA = current; +#ifdef NEEDFORSPEED +#include "utility/ei_porta_speed.h" +#else + if (interruptMask == 0) goto exitPORTAISR; // get out quickly if not interested. +#ifdef EI_ARDUINO_INTERRUPTED_PIN + if (interruptMask & _BV(0)) { arduinoInterruptedPin=ARDUINO_PIN_A0; arduinoPinState=current & _BV(0); portAFunctions.pinZero(); } + if (interruptMask & _BV(1)) { arduinoInterruptedPin=ARDUINO_PIN_A1; arduinoPinState=current & _BV(1); portAFunctions.pinOne(); } + if (interruptMask & _BV(2)) { arduinoInterruptedPin=ARDUINO_PIN_A2; arduinoPinState=current & _BV(2); portAFunctions.pinTwo(); } + if (interruptMask & _BV(3)) { arduinoInterruptedPin=ARDUINO_PIN_A3; arduinoPinState=current & _BV(3); portAFunctions.pinThree(); } + if (interruptMask & _BV(4)) { arduinoInterruptedPin=ARDUINO_PIN_A4; arduinoPinState=current & _BV(4); portAFunctions.pinFour(); } + if (interruptMask & _BV(5)) { arduinoInterruptedPin=ARDUINO_PIN_A5; arduinoPinState=current & _BV(5); portAFunctions.pinFive(); } + if (interruptMask & _BV(6)) { arduinoInterruptedPin=ARDUINO_PIN_A6; arduinoPinState=current & _BV(6); portAFunctions.pinSix(); } + if (interruptMask & _BV(7)) { arduinoInterruptedPin=ARDUINO_PIN_A7; arduinoPinState=current & _BV(7); portAFunctions.pinSeven(); } +#else + if (interruptMask & _BV(0)) portAFunctions.pinZero(); + if (interruptMask & _BV(1)) portAFunctions.pinOne(); + if (interruptMask & _BV(2)) portAFunctions.pinTwo(); + if (interruptMask & _BV(3)) portAFunctions.pinThree(); + if (interruptMask & _BV(4)) portAFunctions.pinFour(); + if (interruptMask & _BV(5)) portAFunctions.pinFive(); + if (interruptMask & _BV(6)) portAFunctions.pinSix(); + if (interruptMask & _BV(7)) portAFunctions.pinSeven(); +#endif // EI_ARDUINO_INTERRUPTED_PIN + exitPORTAISR: return; +#endif // NEEDFORSPEED + // FOR MEASUREMENT ONLY + // exitPORTBISR: PORTC &= ~(1 << PC5); // SIGNAL THAT WE ARE LEAVING THE INTERRUPT +}/*}}}*/ +#endif // EI_NOTPORTA + +#ifndef EI_NOTPORTB +ISR(PORTB_VECT) {/*{{{*/ + uint8_t current; + uint8_t interruptMask; + uint8_t changedPins; + uint8_t tmp; + + current=PINB; +// If we trust the compiler to do this, it will use an extra register... +// changedPins=(portSnapshotB ^ current) & +// ((risingPinsPORTB & current) | (fallingPinsPORTB & ~current)); +// ...so we do it ourselves: + changedPins = portSnapshotB ^ current; + tmp = risingPinsPORTB & current; + interruptMask = fallingPinsPORTB & ~current; + interruptMask = interruptMask | tmp; + interruptMask = changedPins & interruptMask; +#if (defined MIGHTY1284) || (defined EI_ATTINY24) + interruptMask = PCMSK1 & interruptMask; +#else +#ifdef EI_ATTINY25 + interruptMask = PCMSK & interruptMask; +#else + interruptMask = PCMSK0 & interruptMask; +#endif +#endif + + portSnapshotB = current; +#ifdef NEEDFORSPEED +#include "utility/ei_portb_speed.h" +#else + if (interruptMask == 0) goto exitPORTBISR; // get out quickly if not interested. +#ifdef EI_ARDUINO_INTERRUPTED_PIN + if (interruptMask & _BV(0)) { arduinoInterruptedPin=ARDUINO_PIN_B0; arduinoPinState=current & _BV(0); portBFunctions.pinZero(); } + if (interruptMask & _BV(1)) { arduinoInterruptedPin=ARDUINO_PIN_B1; arduinoPinState=current & _BV(1); portBFunctions.pinOne(); } + if (interruptMask & _BV(2)) { arduinoInterruptedPin=ARDUINO_PIN_B2; arduinoPinState=current & _BV(2); portBFunctions.pinTwo(); } + if (interruptMask & _BV(3)) { arduinoInterruptedPin=ARDUINO_PIN_B3; arduinoPinState=current & _BV(3); portBFunctions.pinThree(); } +#if ! (defined EI_ATTINY24) + if (interruptMask & _BV(4)) { arduinoInterruptedPin=ARDUINO_PIN_B4; arduinoPinState=current & _BV(4); portBFunctions.pinFour(); } + if (interruptMask & _BV(5)) { arduinoInterruptedPin=ARDUINO_PIN_B5; arduinoPinState=current & _BV(5); portBFunctions.pinFive(); } +#endif +#if ! (defined ARDUINO_328) && ! (defined EI_ATTINY24) && ! (defined EI_ATTINY25) + if (interruptMask & _BV(6)) { arduinoInterruptedPin=ARDUINO_PIN_B6; arduinoPinState=current & _BV(6); portBFunctions.pinSix(); } + if (interruptMask & _BV(7)) { arduinoInterruptedPin=ARDUINO_PIN_B7; arduinoPinState=current & _BV(7); portBFunctions.pinSeven(); } +#endif +#else // EI_ARDUINO_INTERRUPTED_PIN + if (interruptMask & _BV(0)) portBFunctions.pinZero(); + if (interruptMask & _BV(1)) portBFunctions.pinOne(); + if (interruptMask & _BV(2)) portBFunctions.pinTwo(); + if (interruptMask & _BV(3)) portBFunctions.pinThree(); +#if ! (defined EI_ATTINY24) + if (interruptMask & _BV(4)) portBFunctions.pinFour(); + if (interruptMask & _BV(5)) portBFunctions.pinFive(); +#endif +#if ! (defined ARDUINO_328) && ! (defined EI_ATTINY24) && ! (defined EI_ATTINY25) + if (interruptMask & _BV(6)) portBFunctions.pinSix(); + if (interruptMask & _BV(7)) portBFunctions.pinSeven(); +#endif +#endif // EI_ARDUINO_INTERRUPTED_PIN + exitPORTBISR: return; + // FOR MEASUREMENT ONLY + // exitPORTBISR: PORTC &= ~(1 << PC5); // SIGNAL THAT WE ARE LEAVING THE INTERRUPT +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTPORTB + +#ifndef EI_NOTPORTC +ISR(PORTC_VECT) {/*{{{*/ + uint8_t current; + uint8_t interruptMask; + uint8_t changedPins; + uint8_t tmp; + + current=PINC; +// If we trust the compiler to do this, it will use an extra register... +// changedPins=(portSnapshotB ^ current) & +// ((risingPinsPORTB & current) | (fallingPinsPORTB & ~current)); +// ...so we do it ourselves: + changedPins = portSnapshotC ^ current; + tmp = risingPinsPORTC & current; + interruptMask = fallingPinsPORTC & ~current; + interruptMask = interruptMask | tmp; + interruptMask = changedPins & interruptMask; +#if (defined MIGHTY1284) + interruptMask = PCMSK2 & interruptMask; +#else + interruptMask = PCMSK1 & interruptMask; +#endif + + portSnapshotC = current; +#ifdef NEEDFORSPEED +#include "utility/ei_portc_speed.h" +#else + if (interruptMask == 0) goto exitPORTCISR; // get out quickly if not interested. +#ifdef EI_ARDUINO_INTERRUPTED_PIN + if (interruptMask & _BV(0)) { arduinoInterruptedPin=ARDUINO_PIN_C0; arduinoPinState=current & _BV(0); portCFunctions.pinZero(); } + if (interruptMask & _BV(1)) { arduinoInterruptedPin=ARDUINO_PIN_C1; arduinoPinState=current & _BV(1); portCFunctions.pinOne(); } + if (interruptMask & _BV(2)) { arduinoInterruptedPin=ARDUINO_PIN_C2; arduinoPinState=current & _BV(2); portCFunctions.pinTwo(); } + if (interruptMask & _BV(3)) { arduinoInterruptedPin=ARDUINO_PIN_C3; arduinoPinState=current & _BV(3); portCFunctions.pinThree(); } + if (interruptMask & _BV(4)) { arduinoInterruptedPin=ARDUINO_PIN_C4; arduinoPinState=current & _BV(4); portCFunctions.pinFour(); } + if (interruptMask & _BV(5)) { arduinoInterruptedPin=ARDUINO_PIN_C5; arduinoPinState=current & _BV(5); portCFunctions.pinFive(); } +#ifdef MIGHTY1284 + if (interruptMask & _BV(6)) { arduinoInterruptedPin=ARDUINO_PIN_C6; arduinoPinState=current & _BV(6); portCFunctions.pinSix(); } + if (interruptMask & _BV(7)) { arduinoInterruptedPin=ARDUINO_PIN_C7; arduinoPinState=current & _BV(7); portCFunctions.pinSeven(); } +#endif +#else + if (interruptMask & _BV(0)) portCFunctions.pinZero(); + if (interruptMask & _BV(1)) portCFunctions.pinOne(); + if (interruptMask & _BV(2)) portCFunctions.pinTwo(); + if (interruptMask & _BV(3)) portCFunctions.pinThree(); + if (interruptMask & _BV(4)) portCFunctions.pinFour(); + if (interruptMask & _BV(5)) portCFunctions.pinFive(); +#ifdef MIGHTY1284 + if (interruptMask & _BV(6)) portCFunctions.pinSix(); + if (interruptMask & _BV(7)) portCFunctions.pinSeven(); +#endif +#endif // EI_ARDUINO_INTERRUPTED_PIN + exitPORTCISR: return; +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTPORTC + +#ifndef EI_NOTPORTD +ISR(PORTD_VECT) {/*{{{*/ + uint8_t current; + uint8_t interruptMask; + uint8_t changedPins; + uint8_t tmp; + + current=PIND; +// If we trust the compiler to do this, it will use an extra register... +// changedPins=(portSnapshotB ^ current) & +// ((risingPinsPORTB & current) | (fallingPinsPORTB & ~current)); +// ...so we do it ourselves: + changedPins = portSnapshotD ^ current; + tmp = risingPinsPORTD & current; + interruptMask = fallingPinsPORTD & ~current; + interruptMask = interruptMask | tmp; + interruptMask = changedPins & interruptMask; +#if (defined MIGHTY1284) + interruptMask = PCMSK3 & interruptMask; +#else + interruptMask = PCMSK2 & interruptMask; +#endif + + portSnapshotD = current; +#ifdef NEEDFORSPEED +#include "utility/ei_portd_speed.h" +#else + if (interruptMask == 0) goto exitPORTDISR; // get out quickly if not interested. +#ifdef EI_ARDUINO_INTERRUPTED_PIN + if (interruptMask & _BV(0)) { arduinoInterruptedPin=ARDUINO_PIN_D0; arduinoPinState=current & _BV(0); portDFunctions.pinZero(); } + if (interruptMask & _BV(1)) { arduinoInterruptedPin=ARDUINO_PIN_D1; arduinoPinState=current & _BV(1); portDFunctions.pinOne(); } + if (interruptMask & _BV(2)) { arduinoInterruptedPin=ARDUINO_PIN_D2; arduinoPinState=current & _BV(2); portDFunctions.pinTwo(); } + if (interruptMask & _BV(3)) { arduinoInterruptedPin=ARDUINO_PIN_D3; arduinoPinState=current & _BV(3); portDFunctions.pinThree(); } + if (interruptMask & _BV(4)) { arduinoInterruptedPin=ARDUINO_PIN_D4; arduinoPinState=current & _BV(4); portDFunctions.pinFour(); } + if (interruptMask & _BV(5)) { arduinoInterruptedPin=ARDUINO_PIN_D5; arduinoPinState=current & _BV(5); portDFunctions.pinFive(); } + if (interruptMask & _BV(6)) { arduinoInterruptedPin=ARDUINO_PIN_D6; arduinoPinState=current & _BV(6); portDFunctions.pinSix(); } + if (interruptMask & _BV(7)) { arduinoInterruptedPin=ARDUINO_PIN_D7; arduinoPinState=current & _BV(7); portDFunctions.pinSeven(); } +#else + if (interruptMask & _BV(0)) portDFunctions.pinZero(); + if (interruptMask & _BV(1)) portDFunctions.pinOne(); + if (interruptMask & _BV(2)) portDFunctions.pinTwo(); + if (interruptMask & _BV(3)) portDFunctions.pinThree(); + if (interruptMask & _BV(4)) portDFunctions.pinFour(); + if (interruptMask & _BV(5)) portDFunctions.pinFive(); + if (interruptMask & _BV(6)) portDFunctions.pinSix(); + if (interruptMask & _BV(7)) portDFunctions.pinSeven(); +#endif // EI_ARDUINO_INTERRUPTED_PIN + exitPORTDISR: return; +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTPORTD + +#ifndef EI_NOTPORTJ +ISR(PORTJ_VECT) {/*{{{*/ + uint8_t current; + uint8_t interruptMask; + uint8_t changedPins; + uint8_t tmp; + + current=PINJ; +// If we trust the compiler to do this, it will use an extra register... +// changedPins=(portSnapshotB ^ current) & +// ((risingPinsPORTB & current) | (fallingPinsPORTB & ~current)); +// ...so we do it ourselves: + changedPins = portSnapshotJ ^ current; + tmp = risingPinsPORTJ & current; + interruptMask = fallingPinsPORTJ & ~current; + interruptMask = interruptMask | tmp; + interruptMask = changedPins & interruptMask; + interruptMask = portJPCMSK & interruptMask; // because PCMSK1 is shifted wrt. PortJ. + + portSnapshotJ = current; +#ifdef NEEDFORSPEED +#include "utility/ei_portj_speed.h" +#else + if (interruptMask == 0) goto exitPORTJISR; // get out quickly if not interested. +#ifdef EI_ARDUINO_INTERRUPTED_PIN + if (interruptMask & _BV(0)) { arduinoInterruptedPin=ARDUINO_PIN_J0; arduinoPinState=current & _BV(0); portJFunctions.pinZero(); } + if (interruptMask & _BV(1)) { arduinoInterruptedPin=ARDUINO_PIN_J1; arduinoPinState=current & _BV(1); portJFunctions.pinOne(); } + if (interruptMask & _BV(2)) { arduinoInterruptedPin=ARDUINO_PIN_J2; arduinoPinState=current & _BV(2); portJFunctions.pinTwo(); } + if (interruptMask & _BV(3)) { arduinoInterruptedPin=ARDUINO_PIN_J3; arduinoPinState=current & _BV(3); portJFunctions.pinThree(); } + if (interruptMask & _BV(4)) { arduinoInterruptedPin=ARDUINO_PIN_J4; arduinoPinState=current & _BV(4); portJFunctions.pinFour(); } + if (interruptMask & _BV(5)) { arduinoInterruptedPin=ARDUINO_PIN_J5; arduinoPinState=current & _BV(5); portJFunctions.pinFive(); } + if (interruptMask & _BV(6)) { arduinoInterruptedPin=ARDUINO_PIN_J6; arduinoPinState=current & _BV(6); portJFunctions.pinSix(); } +#else + if (interruptMask & _BV(0)) portJFunctions.pinZero(); + if (interruptMask & _BV(1)) portJFunctions.pinOne(); + if (interruptMask & _BV(2)) portJFunctions.pinTwo(); + if (interruptMask & _BV(3)) portJFunctions.pinThree(); + if (interruptMask & _BV(4)) portJFunctions.pinFour(); + if (interruptMask & _BV(5)) portJFunctions.pinFive(); + if (interruptMask & _BV(6)) portJFunctions.pinSix(); +#endif // EI_ARDUINO_INTERRUPTED_PIN + exitPORTJISR: return; +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTPORTJ + +#ifndef EI_NOTPORTK +ISR(PORTK_VECT) {/*{{{*/ + uint8_t current; + uint8_t interruptMask; + uint8_t changedPins; + uint8_t tmp; + + current=PINK; +// If we trust the compiler to do this, it will use an extra register... +// changedPins=(portSnapshotB ^ current) & +// ((risingPinsPORTB & current) | (fallingPinsPORTB & ~current)); +// ...so we do it ourselves: + changedPins = portSnapshotK ^ current; + tmp = risingPinsPORTK & current; + interruptMask = fallingPinsPORTK & ~current; + interruptMask = interruptMask | tmp; + interruptMask = changedPins & interruptMask; + interruptMask = PCMSK2 & interruptMask; + + portSnapshotK = current; +#ifdef NEEDFORSPEED +#include "utility/ei_portk_speed.h" +#else + if (interruptMask == 0) goto exitPORTKISR; // get out quickly if not interested. +#ifdef EI_ARDUINO_INTERRUPTED_PIN + if (interruptMask & _BV(0)) { arduinoInterruptedPin=ARDUINO_PIN_K0; arduinoPinState=current & _BV(0); portKFunctions.pinZero(); } + if (interruptMask & _BV(1)) { arduinoInterruptedPin=ARDUINO_PIN_K1; arduinoPinState=current & _BV(1); portKFunctions.pinOne(); } + if (interruptMask & _BV(2)) { arduinoInterruptedPin=ARDUINO_PIN_K2; arduinoPinState=current & _BV(2); portKFunctions.pinTwo(); } + if (interruptMask & _BV(3)) { arduinoInterruptedPin=ARDUINO_PIN_K3; arduinoPinState=current & _BV(3); portKFunctions.pinThree(); } + if (interruptMask & _BV(4)) { arduinoInterruptedPin=ARDUINO_PIN_K4; arduinoPinState=current & _BV(4); portKFunctions.pinFour(); } + if (interruptMask & _BV(5)) { arduinoInterruptedPin=ARDUINO_PIN_K5; arduinoPinState=current & _BV(5); portKFunctions.pinFive(); } + if (interruptMask & _BV(6)) { arduinoInterruptedPin=ARDUINO_PIN_K6; arduinoPinState=current & _BV(6); portKFunctions.pinSix(); } + if (interruptMask & _BV(7)) { arduinoInterruptedPin=ARDUINO_PIN_K7; arduinoPinState=current & _BV(7); portKFunctions.pinSeven(); } +#else + if (interruptMask & _BV(0)) portKFunctions.pinZero(); + if (interruptMask & _BV(1)) portKFunctions.pinOne(); + if (interruptMask & _BV(2)) portKFunctions.pinTwo(); + if (interruptMask & _BV(3)) portKFunctions.pinThree(); + if (interruptMask & _BV(4)) portKFunctions.pinFour(); + if (interruptMask & _BV(5)) portKFunctions.pinFive(); + if (interruptMask & _BV(6)) portKFunctions.pinSix(); + if (interruptMask & _BV(7)) portKFunctions.pinSeven(); +#endif // EI_ARDUINO_INTERRUPTED_PIN + exitPORTKISR: return; +#endif // NEEDFORSPEED +}/*}}}*/ +#endif // EI_NOTPORTK + +// ************************************************************************************* +// ************************************************************************************* + +#endif // #ifndef LIBCALL_ENABLEINTERRUPT ********************************************************* +#endif // #if defined __SAM3U4E__ || defined __SAM3X8E__ || defined __SAM3X8H__ +#endif // #ifndef EnableInterrupt_h *************************************************************** diff --git a/libraries/EnableInterrupt/Interrupt Timing.odt b/libraries/EnableInterrupt/Interrupt Timing.odt new file mode 100644 index 0000000..ec049f2 Binary files /dev/null and b/libraries/EnableInterrupt/Interrupt Timing.odt differ diff --git a/libraries/EnableInterrupt/Interrupt Timing.pdf b/libraries/EnableInterrupt/Interrupt Timing.pdf new file mode 100644 index 0000000..0623c1c Binary files /dev/null and b/libraries/EnableInterrupt/Interrupt Timing.pdf differ diff --git a/libraries/EnableInterrupt/README.md b/libraries/EnableInterrupt/README.md new file mode 100644 index 0000000..691ac28 --- /dev/null +++ b/libraries/EnableInterrupt/README.md @@ -0,0 +1,487 @@ +# EnableInterrupt +New Arduino interrupt library, designed for all versions of the Arduino. + +Functions: + +enableInterrupt- Enables interrupt on a selected Arduino pin. +disableInterrupt - Disables interrupt on the selected Arduino pin. + + +*_What's New?_ +- Wed Sep 4 19:30:45 CDT 2019 + - Version 1.1.0 of the library has been released. We add support for the ATmega2561 and 1281 chips, +with pinouts defined from the MCUdude/MegaCore project. Code donations by Kizmit99. Plus, a documentation +bugfix from Greg Bowler. Thanks, folks! + +The EnableInterrupt library is an Arduino interrupt library, designed for +8-bit versions of the Arduino- at this writing, the Uno (and other ATmega328p-based +boards, like the mini), Due, Zero, Leonardo (and other ATmega32u4-based boards, like the +Micro), the Mega2560 (and other ATmega2560-based boards, like the MegaADK), +and for non-Arduino chips: the 644/1284p (Mighty1284, Sodaq Mbili and EnviroDIY Mayfly) +ATtiny 44/84, and ATtiny 45/85 (using DA Mellis' support files). +The library enables you to assign an interrupt to pins on your chip +that support them, and presents a common interface to all supported chips. This +means that on the Arduino Uno and Mega you don't give it an interrupt number, as per +http://arduino.cc/en/Reference/attachInterrupt. Rather, your first argument is a +pin number of a pin that's supported on that chip (see +https://github.com/GreyGnome/EnableInterrupt/wiki/Usage#pin--port-bestiary ). + +32-bit support for Due comes only in the form of a macro that enables your code +to be shared unchanged between 32- and 8-bit Arduinos. No further support for +32-bit Arduinos is planned. + +## Download +See the https://github.com/GreyGnome/EnableInterrupt/wiki/Download page to +download the library. + +## More Information +See the Wiki at https://github.com/GreyGnome/EnableInterrupt/wiki/Home . +For detailed usage information see https://github.com/GreyGnome/EnableInterrupt/wiki/Usage . + +See the examples subdirectory in the distribution or in this Git site for code examples. + +See the extras subdirectory in the distribution or in this Git site for License and Release Notes. + +For a tutorial on interrupts, see +http://www.engblaze.com/we-interrupt-this-program-to-bring-you-a-tutorial-on-arduino-interrupts/ +The posting gets into low-level details on interrupts. + +IMPORTANT NOTE: In 0.9.2 I discovered a rather pernicious bug, wherein the library was setting the global interrupt enable bit. This could cause a serious and difficult-to-debug race condition, as it is not the job of the library to manage that bit. The chips come with interrupts enabled so existing code should not be affected, but if you were relying on that behavior note that it has changed. My thanks to http://gammon.com.au/interrupts (the 'How are interrupts queued?' section). + +## ATmega Processor Interrupt Types +Note that the ATmega processor at the heart of the Arduino Uno/Mega2560/Leonardo/ATmega1284 +has two different kinds of interrupts: “external”, and “pin change”. +For the list of available interrupt pins and their interrupt types, see the +PORT / PIN BESTIARY, below. + +### External Interrupts +There are a varying number of external interrupt pins on the different +processors. The Uno supports only 2 and they are mapped to Arduino pins 2 and 3. +The 2560 supports 6 usable, the Leonardo supports 5, and the ATmega1284p supports 3. +These interrupts can be set to trigger on one of three signal values: RISING, +FALLING, or CHANGE (for both), or on LOW level. The triggers are interpreted by +hardware, so by the time your user function is running, you know exactly which +pin interrupted at the time of the event, and how it changed. On the other hand, +as mentioned there are a limited number of these pins. + +### Pin Change Interrupts +On the Arduino Uno (and again, all 328p-based boards) and 644/1284-based boards, +the pin change interrupts can be enabled on any or all of the pins. The two +pins 2 and 3 on 328p-based boards, or three pins (2, 10, and 11) on the +1284-based boards support *either* pin change or external interrupts. On 2560-based +Arduinos, there are 18 pin change interrupt pins in addition to the 6 external +interrupt pins. On the Leonardo there are 7 pin change interrupt pins in addition +to the 5 external interrupt pins. See PIN BESTIARY below for the pin numbers and +other details. + +Pin Change interrupts trigger on all RISING and FALLING (ie, "CHANGE") signal edges. +Furthermore, the processor's pins, and pin change interrupts, are grouped into +“port”s, so for example on the Arduino Uno there are three ports and therefore +only 3 interrupt vectors (subroutines) available for the entire body of 20 pin +change interrupt pins. + +### The Library and Pin Change Interrupts +The foregoing means that not only do pin change interrupts trigger on +all pin transitions, but a number of pins share a +single interrupt subroutine. It's the library's function to make pin change interrupts +appear that each pin can support RISING, FALLING, or CHANGE, and each pin +can support its own user-defined interrupt subroutine. + +When an event triggers an interrupt on any interrupt-enabled pin on a port, a +library subroutine ("interrupt handler", "interrupt service routine", or "ISR") +attached to that pin's port is triggered. It is up to the EnableInterrupt +library to set the proper port to receive interrupts for a pin, to determine +what happened when an interrupt is triggered (which pin? ...did the signal rise, +or fall?), to handle it properly (Did we care if the signal fell? Did we care +if it rose?), then to call the programmer's chosen subroutine (ISR). This makes the +job of resolving the action on a single pin somewhat complicated. There is a +definitive slowdown in the interrupt routine because of this complication. +So there is a significant* +time between when the interrupt triggers and when the pins are read to determine +what actually happened (rising or falling) and which pin changed. +So the signal could have changed by the time the pin's status is read, returning +a false reading back to your sketch. Therefore, these +pins are *not* suitable for fast changing signals, and under the right conditions +such events as a bouncing switch may actually be missed. Caveat Programmer. +If you're concerned about this, continue to read the following information and +make sure to read the wiki pages; especially see https://github.com/GreyGnome/EnableInterrupt/wiki/Usage#atmega-processor-interrupt-types . +For a further review of this issue see +https://github.com/GreyGnome/EnableInterrupt/blob/master/Interrupt%20Timing.pdf + +# USAGE: +## Basic Usage +*enableInterrupt*- Enables interrupt on a selected Arduino pin. +```C +enableInterrupt(uint8_t pinNumber, void (*userFunction)(void), uint8_t mode); +or +enableInterrupt(uint8_t interruptDesignator, void (*userFunction)(void), uint8_t mode); + +The arguments are: +* pinNumber - The number of the Arduino pin, such as 3, or A0, or SCK. Note that +these are *not* strings, so when you use A0 for example, do not use quotes. +* interruptDesignator- very much like a pin. See below. +* userFunction - The name of the function you want the interrupt to run. Do not +use a pointer here, just give it the name of your function. See the example code +in the Examples directory. +* mode - What you want the interrupt to interrupt on. For Pin Change Interrupt +pins, the modes supported are RISING, FALLING, or CHANGE. +** RISING - The signal went from "0", or zero volts, to "1", or 5 volts. +** FALLING - The signal went from "1" to "0". +** CHANGE - The signal either rose or fell. + +For External Interrupts, the same modes are supported plus the additional mode +of LOW signal level. +** LOW - The signal is at a low level for some time. + +Each pin supports only 1 function and 1 mode at a time. +``` + +*disableInterrupt*- Disables interrupt on a selected Arduino pin. + +```C +disableInterrupt(uint8_t pinNumber); +or +disableInterrupt(uint8_t interruptDesignator); +``` + +* interruptDesignator: Essentially this is an Arduino pin, and if that's all you want to give +the function, it will work just fine. Why is it called an "interruptDesignator", then? Because +there's a twist: You can perform a bitwise "and" with the pin number and PINCHANGEINTERRUPT +to specify that you want to use a Pin Change Interrupt type of interrupt on those pins that +support both Pin Change and External Interrupts. Otherwise, the library will choose whatever +interrupt type (External, or Pin Change) normally applies to that pin, +with priority to External Interrupt. + +* The complexity is because of pins 2 and 3 on the ATmega328-based Arduinos, and pins 2, 10, +and 11 on 1284-based boards. Those are the only pins on the processors supported by this +library that can share External or Pin Change Interrupt types. Otherwise, each pin only supports +a single type of interrupt and the PINCHANGEINTERRUPT scheme changes nothing. This means you can +ignore this whole discussion for ATmega2560, ATmega32U4, or SAM3X8E (Due)-based Arduinos. + +It is possible to change the user function assigned to an interrupt after enabling it (if you +want). Later in your code simply disable the interrupt and enable it with a different function. + +## Determine the Pin That Was Interrupted +There is a facility in the library to identify the most recent pin that triggered an interrupt. Set the following definition '''before''' including the EnableInterrupt.h file in your sketch: +``` + #define EI_ARDUINO_INTERRUPTED_PIN +``` +Then, the ATmega chip will set a variable with every interrupt, and you can query it to find which pin interrupted your sketch. The variable is arduinoInterruptedPin and it is of type uint8_t. + +See the https://github.com/GreyGnome/EnableInterrupt/wiki/Usage wiki page for more information. + +# PIN / PORT BESTIARY +Theoretically pins 0 and 1 (RX and TX) are supported but as these pins have +a special purpose on the Arduino, their use in this library has not been tested. + +## Summary +### Arduino Uno/Duemilanove/etc. +Interrupt Type | Pins +-------------- | -------------- +External | 2 3 +Pin Change | 2-13 and A0-A5 +### Arduino Mega2560 +Interrupt Type | Pins +-------------- | -------------- +External | 2 3 and 18-21 +Pin Change | 10-15 and A8-A15 and SS, SCK, MOSI, MISO +### Arduino Leonardo +Interrupt Type | Pins +-------------- | -------------- +External | 0-3 and 7 +Pin Change | 8-11 and SCK, MOSI, MISO +### Mighty 1284, Sodaq Mbili, EnviroDIY Mayfly +Interrupt Type | Pins +-------------- | -------------- +External | 2 10 11 +Pin Change | 0-31 (aka: 0-23 and A0-A7) + +## Details +### Arduino Uno + +
+Interrupt Pins:
+Arduino	External                Arduino Pin Change      Arduino Pin Change
+Pin     Interrupt               Pin     Interrupt       Pin     Interrupt
+                Port                           Port                     Port
+2       INT0    PD2             2       PCINT18 PD2     A0      PCINT8  PC0
+3       INT1    PD3             3       PCINT19 PD3     A1      PCINT9  PC1
+                                4       PCINT20 PD4     A2      PCINT10 PC2
+                                5       PCINT21 PD5     A3      PCINT11 PC3
+                                6       PCINT22 PD6     A4      PCINT12 PC4
+                                7       PCINT23 PD7     A5      PCINT13 PC5
+                                8       PCINT0  PB0
+                                9       PCINT1  PB1
+                                10      PCINT2  PB2
+                                11      PCINT3  PB3
+                                12      PCINT4  PB4
+                                13      PCINT5  PB5
+
+ +### Leonardo Pins LEONARDO + +
+Interrupt pins:
+Arduino                         Arduino
+Pin     External                Pin     Pin Change
+        Interrupt                       Interrupt
+               Port                               Port
+ 3      INT0   PD0              8       PCINT4    PB4
+ 2      INT1   PD1              9       PCINT5    PB5
+ 0      INT2   PD2              10      PCINT6    PB6
+ 1      INT3   PD3              11      PCINT7    PB7
+ 7      INT6   PE6              SCK/15  PCINT1    PB1
+                                MOSI/16 PCINT2    PB2
+                                MISO/14 PCINT3    PB3
+
+                                on ICSP:
+                                SCK/15:  PCINT1 (PB1)
+                                MOSI/16: PCINT2 (PB2)
+                                MISO/14: PCINT3 (PB3)
+
+// Map SPI port to 'new' pins D14..D17
+static const uint8_t SS   = 17;
+static const uint8_t MOSI = 16;
+static const uint8_t MISO = 14;
+static const uint8_t SCK  = 15;
+// A0 starts at 18
+
+
+ +### ATmega2560 Support + +
+External Interrupts ------------------------------------------------------------
+The following External Interrupts are available on the Arduino:
+Arduino           
+  Pin  PORT INT  ATmega2560 pin
+  21     PD0  0     43
+  20     PD1  1     44
+  19     PD2  2     45
+  18     PD3  3     46
+   2     PE4  4      6
+   3     PE5  5      7
+ n/c     PE6  6      8  (fake pin 75) **
+ n/c     PE7  7      9  (fake pin 76)
+
+
+Pin Change Interrupts ----------------------------------------------------------
+
+ATMEGA2560 Pin Change Interrupts
+Arduino              Arduino              Arduino
+  Pin  PORT PCINT     Pin   PORT PCINT     Pin   PORT PCINT
+  A8     PK0  16       10     PB4   4       SS     PB0   0
+  A9     PK1  17       11     PB5   5       SCK    PB1   1
+ A10     PK2  18       12     PB6   6       MOSI   PB2   2
+ A11     PK3  19       13     PB7   7       MISO   PB3   3
+ A12     PK4  20       14     PJ1  10
+ A13     PK5  21       15     PJ0   9
+ A14     PK6  22        0     PE0   8 - this one is a little odd. *
+ A15     PK7  23
+
+ +The library supports all interrupt pins, even though not all pins to the +ATmega-2560 processor are exposed on the Arduino board. These pins are +supported as "fake pins", and begin with pin 70 (there are 70 pins on the +ATmega 2560 board). The fake pins are as follows: + +
+pin: fake70 PJ2 this is Pin Change Interrupt PCINT11
+pin: fake71 PJ3 this is Pin Change Interrupt PCINT12
+pin: fake72 PJ4 this is Pin Change Interrupt PCINT13
+pin: fake73 PJ5 this is Pin Change Interrupt PCINT14
+pin: fake74 PJ6 this is Pin Change Interrupt PCINT15
+pin: fake75 PE6 this is External Interrupt INT6
+pin: fake76 PE7 this is External Interrupt INT7
+
+ +* Note: Arduino Pin 0 is PE0 (PCINT8), which is RX0. Also, it is the only other +pin on another port on PCI1. This would make it very costly to integrate with +the library's code and thus is not supported by this library. It is the same +pin the Arduino uses to upload sketches, and it is connected to the FT232RL +USB-to-Serial chip (ATmega16U2 on the R3). + +### ATmega2561/1281 (MegaCore) Support + +
+External Interrupts ------------------------------------------------------------
+The following External Interrupts are available on the Arduino/MegaCore:
+MegaCore           
+  Pin  PORT INT  ATmega2561/1281 pin
+  18     PD0  0     25
+  19     PD1  1     26
+  20     PD2  2     27
+  21     PD3  3     28
+   4     PE4  4      6
+   5     PE5  5      7
+   6     PE6  6      8
+   7     PE7  7      9
+
+
+Pin Change Interrupts ----------------------------------------------------------
+
+ATMEGA2561/1281 (MegaCore) Pin Change Interrupts
+MegaCore
+ Pin      PORT   PCINT
+  8/SS     PB0     0
+  9/SCK    PB1     1
+  10/MOSI  PB2     2
+  11/MISO  PB3     3
+  12       PB4     4
+  13       PB5     5
+  14       PB6     6
+  15       PB7     7
+   0       PE0     8 - this one is a little odd. *
+
+ +* Note: Arduino Pin 0 is PE0 (PCINT8), which is RX0. Also, it is the only other +pin on another port on PCI1. This would make it very costly to integrate with +the library's code and thus is not supported by this library. It is the same +pin the Arduino uses to upload sketches, and it is connected to the FT232RL +USB-to-Serial chip (ATmega16U2 on the R3). + +### Mighty 1284, Bobuino, EnviroDIY Mayfly, Sodaq Mbili Support +The ATmega 1284p shares pinout with the 644; the only difference is in memory +size. We use the "Mighty 1284" platform as our model, because the needed files are +mature and complete. + +
+Interrupt Pins:
+Mighty  External                Mighty                                 Mighty           
+Pin     Interrupt               Pin*  PORT PCINT ATmega644/1284 pin    Pin*  PORT PCINT ATmega644/1284 pin
+                Port            0     PB0   8         1                15    PD7  31        21
+2       INT2    PB2             1     PB1   9         2                16    PC0  16        22
+10      INT1    PD2             2     PB2   2         3                17    PC1  17        23
+11      INT0    PD3             3     PB3  11         4                18    PC2  18        24
+                                4     PB4  12         5                19    PC3  19        25
+                                5     PB5  13         6                20    PC4  20        26
+                                6     PB6  14         7                21    PC5  21        27
+                                7     PB7  15         8                22    PC6  22        28
+                                8     PD0  24        14                23    PC7  23        29
+                                9     PD1  25        15             31/A7    PA7   7        33
+                               10     PD2  26        16             30/A6    PA6   6        34
+                               11     PD3  27        17             29/A5    PA5   5        35
+                               12     PD4  28        18             28/A4    PA4   4        36
+                               13     PD5  29        19             27/A3    PA3   3        37
+                               14     PD6  30        20             26/A2    PA2   2        38
+                                                                    25/A1    PA1   1        39
+                                                                    24/A0    PA0   0        40
+
+Bobuino External                Bobuino                                Bobuino           
+Pin     Interrupt               Pin*  PORT PCINT ATmega644/1284 pin    Pin*  PORT PCINT ATmega644/1284 pin
+                Port            4     PB0   8         1                31    PD7  31        21
+2       INT2    PB2             5     PB1   9         2                22    PC0  16        22
+10      INT1    PD2             6     PB2   2         3                23    PC1  17        23
+11      INT0    PD3             7     PB3  11         4                24    PC2  18        24
+                               10     PB4  12         5                25    PC3  19        25
+                               11     PB5  13         6                26    PC4  20        26
+                               12     PB6  14         7                27    PC5  21        27
+                               13     PB7  15         8                28    PC6  22        28
+                                0     PD0  24        14                29    PC7  23        29
+                                1     PD1  25        15             14/A0    PA7   7        33
+                                2     PD2  26        16             15/A1    PA6   6        34
+                                3     PD3  27        17             16/A2    PA5   5        35
+                               30     PD4  28        18             17/A3    PA4   4        36
+                                8     PD5  29        19             18/A4    PA3   3        37
+                                9     PD6  30        20             19/A5    PA2   2        38
+                                                                    20/A6    PA1   1        39
+                                                                    21/A7    PA0   0        40
+
+Mayfly                          Mayfly                                 Mayfly
+Mbili   External                Mbili                                  Mbili           
+Pin     Interrupt               Pin*  PORT PCINT ATmega644/1284 pin    Pin*  PORT PCINT ATmega644/1284 pin
+                Port            8     PB0   8         1                 7    PD7  31        21
+2       INT2    PB2             9     PB1   9         2                16    PC0  16        22
+10      INT1    PD2            10     PB2   2         3                17    PC1  17        23
+11      INT0    PD3            11     PB3  11         4                18    PC2  18        24
+                               12     PB4  12         5                19    PC3  19        25
+                               13     PB5  13         6                20    PC4  20        26
+                               14     PB6  14         7                21    PC5  21        27
+                               15     PB7  15         8                22    PC6  22        28
+                                0     PD0  24        14                23    PC7  23        29
+                                1     PD1  25        15             31/A7    PA7   7        33
+                                2     PD2  26        16             30/A6    PA6   6        34
+                                3     PD3  27        17             29/A5    PA5   5        35
+                                4     PD4  28        18             28/A4    PA4   4        36
+                                5     PD5  29        19             27/A3    PA3   3        37
+                                6     PD6  30        20             26/A2    PA2   2        38
+                                                                    25/A1    PA1   1        39
+                                                                    24/A0    PA0   0        40
+
+ +# Thanks! +Thank you for downloading and enjoying the EnableInterrupt library. +I hope you find it useful. Heck, I wrote it for you- yeah, that's right- you. +The Maker and/or Geek sitting before your project and trying to make little +computers do fun stuff. It's not easy, and my hat goes off to you. I hope I've +made stuff a little easier for you. + +This software would not be nearly as useful as it is +without the help of the following people: + +Thanks to Loranzo Cafaro for his switch debounce example, to Jevon Wild for his changes to make the +library more functional with PlatformIO (http://docs.platformio.org/en/latest/what-is-platformio.html), +Ricardo JL Rufino for some PlatformIO fixes to the library.json file, and Sara Damiano for +adding support for the Sodaq Mbili and EnviroDIY Mayfly. + +And, from the past, this library's predecessor was the PinChangeInt library. +I have done a complete rewrite and not used any of its code, but I learned +a lot by doing the previous one and I feel like I still owe a debt of gratitude +to all the geeks who created/contributed/helped/debugged. So without further +ado, I present the "ACKNOWLEDGEMENTS" section from the previous library. Note +that "this" library in the following refers to PinChangeInt: + +> This library was originally written by Chris J. Kiick, Robot builder and all +around geek, who said of it, +> "Hi, Yeah, I wrote the original PCint library. It was a bit of a hack + and the new one has better features. I intended the code to be freely + usable. Didn't really think about a license. Feel free to use it in + your code: I hereby grant you permission." +> Thanks, Chris! A hack? I dare say not, if I have taken this any further it's +merely by standing on the shoulders of giants. This library was the best +"tutorial" I found on Arduino Pin Change Interrupts and because of that I +decided to continue to maintain and (hopefully) improve it. We, the Arduino +community of robot builders and geeks, owe you a great debt of gratitude for +your hack- a hack in the finest sense. + +> The library was then picked up by Lex Talionis, who created the Google Code +website. We all owe a debt of thanks to Lex, too, for all his hard work! He is +currently the other official maintainer of this code. + +> Many thanks to all the contributors who have contributed bug fixes, code, and +suggestions to this project: + +> John Boiles and Baziki (who added fixes to PcInt), Maurice Beelen, nms277, +Akesson Karlpetter, and Orly Andico for various fixes to this code, Rob Tillaart +for some excellent code reviews and nice optimizations, Andre' Franken for a +good bug report that kept me thinking, cserveny.tamas a special shout out for +providing the MEGA code to PinChangeInt, and Pat O'Brien for testing and +reporting on the Arduino Yun.- Thanks! + +> A HUGE thanks to JRHelbert for fixing the PJ0 and PJ1 interrupt PCMSK1 issue on +the Mega... 06/2014 + +> A HUGE thanks to Jan Baeyens ("jantje"), who has graciously DONATED an Arduino +Mega ADK to the PinChangeInt project!!! Wow, thanks Jan! This makes the +2560-based Arduino Mega a first class supported platform- I will be able to test +it and verify that it works. + +- In 2018, Alex Reinert contributed Bobuino support. Thanks, Alex! + +- In 4/2019 Kizmit99 contributed support for the ATmega2561 and 1281 chips, with +pinouts defined from the MCUdude/MegaCore project. Thanks, Kizmit99! + +- In 8/2019 Greg Bowler helped suss out a documentation bug, and contributed +a patch to make the README.md less confusing. Much appreciated. + +> Finally, a shout out to Leonard Bernstein. I was inspired by him +(https://www.youtube.com/watch?feature=player_detailpage&v=R9g3Q-qvtss#t=1160) +from a Ted talk by Itay Talgam. None of the contributors, myself included, has +any interest in making money from this library and so I decided to free up the +code as much as possible for any purpose. ...But! You must give credit where +credit is due (it's not only a nice idea, it's the law- as in, the license +terms)! + +> "If you love something, give it away." + +I apologize if I have forgotten anyone here. Please let me know if so. diff --git a/libraries/EnableInterrupt/ReleaseChecklist b/libraries/EnableInterrupt/ReleaseChecklist new file mode 100644 index 0000000..e22c857 --- /dev/null +++ b/libraries/EnableInterrupt/ReleaseChecklist @@ -0,0 +1,23 @@ +- examples/test.sh compiles +- #pragma message in .h file up-to-date? +- Use Arduino IDE, compile "SimpleDueZero" +- Tests: + - Simple + - HiSpeed + - HiSpeedAllPins328 + - AllPins328 + - HiSpeedAllPins2560 + - AllPins2560 + - ATtinyBlink +- README.md up-to-date? +- extras/RELEASE_NOTES consistent with README.md? +- library.properties current? +- library.json current? +- Git Tagged? git tag -a 2.31 -m 'my version 1.4'; git push origin 2.31 OR git push origin --tags +- Zip file created? ~/bin/zipei 0.9.0 +- BinTray: + - Upload Zip file + - Update the downloads area +- Git commit +- Push files to GitHub +- Post to Arduino forums diff --git a/libraries/EnableInterrupt/Technical_Notes b/libraries/EnableInterrupt/Technical_Notes new file mode 100644 index 0000000..9ecabee --- /dev/null +++ b/libraries/EnableInterrupt/Technical_Notes @@ -0,0 +1,929 @@ +// in vim, :set ts=2 sts=2 sw=2 et + +// Enable Interrupts + +===================================================================================================== +===================================================================================================== +ATmega328 Support +===================================================================================================== +===================================================================================================== + +Interrupt pins: +Pin External Pin Pin Change Pin Pin Change + Interrupt Interrupt Interrupt + 3 INT1 PD3 0 PCINT16 PD0 A0 PCINT8 PC0 + 2 INT0 PD2 1 PCINT17 PD1 A1 PCINT9 PC1 + 2 PCINT18 PD2 A2 PCINT10 PC2 + 3 PCINT19 PD3 A3 PCINT11 PC3 + 4 PCINT20 PD4 A4 PCINT12 PC4 + 5 PCINT21 PD5 A5 PCINT13 PC5 + 6 PCINT22 PD6 + 7 PCINT23 PD7 + 8 PCINT0 PB0 + 9 PCINT1 PB1 + 10 PCINT2 PB2 + 11 PCINT3 PB3 + 12 PCINT4 PB4 + 13 PCINT5 PB5 + +// The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins. + +// PIN CHANGE INTERRUPT REGISTER BESTIARY +// ATmega328p and similar (328, 168) +The pin change interrupt PCI2 will trigger if any enabled PCINT[23:16] pin toggles. +The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] pin toggles. +The pin change interrupt PCI0 will trigger if any enabled PCINT[7:0] pin toggles. +The PCMSK2, PCMSK1 and PCMSK0 Registers control which pins contribute to the pin change interrupts. +Pin change interrupts on PCINT23...0 are detected asynchronously. This implies that these interrupts +can be used for waking the part also from sleep modes other than Idle mode. + +// GLOBALLY +SREG: 7 6 5 4 3 2 1 0 (AVR Status Register) + I -Global Interrupt Enable bit Set to enable interrupts. + rw + +// PIN CHANGE INTERRUPTS REGISTER BESTIARY +PCICR: 7 6 5 4 3 2 1 0 (When PCIE2 is set and GIE is set, PCI2 is enabled) + PCIE2 1 0 Likewise for 1 and 0. + - - - - - rw rw rw + +PCMSK2:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT23:16 + PCINT23 ... PCINT16 If PCIE2 in PCICR and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0 =PORTD + +PCMSK1:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT14:8 + - PCINT14 ... PCINT8 If PCIE1 in PCICR and this bit is set, it is enabled on that + r rw rw rw rw rw rw rw pin.) + PC6 PC5 PC4 PC3 PC2 PC1 PC0 =PORTC + +PCMSK0:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT7:0 + PCINT7 ... PCINT0 If PCIE0 in PCICR and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0 =PORTB + +// set... +PCIFR: 7 6 5 4 3 2 1 0 (When logic change triggers IRQ, bececomes set. Cleared when + PCIF2 1 0 IRQ is executed. PCIF2 == PCIE2, etc.) + - - - - - rw rw rw + +// EXTERNAL INTERRUPTS REGISTER BESTIARY +For ATmega328p and the like. + +INT0=pin2, INT1=pin3 + +EICRA: 7 6 5 4 3 2 1 0 (External Interrupt Control Register A) + ISC 11 10 01 00 Interrupt Sense Control Bits + - - - - rw rw rw rw + + ISC11 / ISC10 : INT1 ISC01 / ISC00 + 0 0 Low (similar to ISC11/10) + 0 1 Change + 1 0 Falling + 1 1 Rising + +EIMSK: 7 6 5 4 3 2 1 0 (External Interrupt Mask Register) + INT1 INT0 + - - - - - - rw rw set to 1 to enable this interrupt + +// set... +EIFR: INTF1: Bit 1: set when edge/logic chg on INT1 triggers IRQ. Cleared when IRQ executed. + INTF0: Bit 0: set when edge/logic chg on INT0 triggers IRQ. Cleared when IRQ executed. + + +The INT0 and INT1 interrupts can be triggered by a falling or rising edge or a low level. This is +set up as indicated in the specification for the External Interrupt Control Register A – EICRA. +When the INT0 or INT1 interrupts are enabled and are configured as level triggered, the inter- +rupts will trigger as long as the pin is held low. +Low level interrupt on INT0 and INT1 is detected asynchronously. This implies that this interrupt +can be used for waking the part also from sleep modes other than Idle mode. The I/O clock is halted +in all sleep modes except Idle mode. + +============================================================================================= + +Fri Jan 23 21:51:01 CST 2015 +PROBLEM: +I have a "dirty" switch: it bounces a lot when pressed. The bounces can occur on the order of +microseconds apart. So pretend I have turned on a port as an input port, and the pullup resistor +is on. I have enabled a Pin Change Interrupt on the pin. It will trigger on any level change. +So when I press the switch, the signal goes from high to low and the interrupt is triggered. + +Notice that for Pin Change Interrupts, the interrupt can take place when any pin on the port is +interrupted. If you have the luxury of knowing ahead of time which pin(s) are interrupting, you +can design fast, custom code that will react to your simple situation. But remember that I am +writing a library: I don't know which pin may be doing the interrupting. So I have to survey the +pins to figure out which one(s) changed, and had triggered the interrupt. Furthermore, there is +an appreciable amount of time that it takes from the moment the triggering event happened to +when I enter the interrupt subroutine (ISR) and have gone through the logic to figure out which +pins did the triggering. ...How much time? That I aim to find out. + +Why is this a big deal? Remember my bouncy switch? ...The interrupt triggers, the ISR starts up, +and the first thing I need to do is query the port to see the state of its pins. Well, some time +has elapsed since the triggering event and this query. In the course of that time, it's entirely +possible- and I'm writing this because it's not only possible, but it can happen quite readily- +that the state of the pin changes before I get a chance to sample it. So I get an interrupt but +it looks like a false alarm! The ISR never calls the user's function because none of the user's +interrupt pins appear to have changed. + +There is no complete solution to this problem, because of the nature of Pin Change Interrupts. +All you can do is mitigate the situation. I will attempt to do so by capturing the state of the +port as early as possible in the ISR. The question is, how early is that? + +I attempt a test: my ISR looks like this; this will turn on and off the Arduino Uno's pin 13 LED: + +ISR(PORTC_VECT, ISR_NAKED) { + uint8_t interruptMask; + uint8_t ledon, ledoff; + + ledon=0b00100000; ledoff=0b0; + + PORTB=ledoff; // LOW + PORTB=ledon; // HIGH + PORTB=ledoff; // LOW + PORTB=ledon; // HIGH + PORTB=ledoff; // LOW + (...) +} + +The generated assembly code looks like this: + +00000292 <__vector_4>: + ledon=0b00100000; ledoff=0b0; + + PORTB=ledoff; // LOW + 292: 15 b8 out 0x05, r1 ; 5 + PORTB=ledon; // HIGH + 294: 80 e2 ldi r24, 0x20 ; 32 + 296: 85 b9 out 0x05, r24 ; 5 + PORTB=ledoff; // LOW + 298: 15 b8 out 0x05, r1 ; 5 + PORTB=ledon; // HIGH + 29a: 85 b9 out 0x05, r24 ; 5 + PORTB=ledoff; // LOW + 29c: 15 b8 out 0x05, r1 ; 5 + +Notice a little optimization here: r1 is defined to always contain 0, so we don't even have to load +a value from memory. 0 is an important number! This makes the initial command very quick, and by using +an oscilloscope we can see just how quickly the chip reacts after receiving the signal. +see just how fast + + +***** MACRO vs. INLINE the ISR frontend ************************** +The code compiles to very similar assembler. However, the inline is better looking C code. +Refer to the "testing0" branch for comparison. + +I will use the INLINE method in the production code. +***** MACRO vs. INLINE the ISR frontend ************************** + +A lot of the basic Pin and Port definitions are in /usr/avr/include/avr/iom328p.h + +================== ================== ================== ================== ================== + +===================================================================================================== +===================================================================================================== +Leonardo Support LEONARDO +===================================================================================================== +===================================================================================================== + +// Map SPI port to 'new' pins D14..D17 +static const uint8_t SS = 17; +static const uint8_t MOSI = 16; +static const uint8_t MISO = 14; +static const uint8_t SCK = 15; +// A0 starts at 18 + + +Interrupt pins: +Pin External Pin Pin Change + Interrupt Interrupt + 3 INT0 PD0 8 PCINT4 PB4 + 2 INT1 PD1 9 PCINT5 PB5 + 0 INT2 PD2 10 PCINT6 PB6 + 1 INT3 PD3 11 PCINT7 PB7 + 7 INT6 PE6 SCK/15 PCINT1 PB1 + MOSI/16 PCINT2 PB2 + MISO/14 PCINT3 PB3 + SS/17 PCINT0 PB0 (on 3rd party boards) + +on ICSP: +SCK/15: PCINT1 (PB1) +MOSI/16: PCINT2 (PB2) +MISO/14: PCINT3 (PB3) + +PCINT0 (PB0) is RXLED and is not exposed as a pin on the Leonardo board. + +External Interrupts ------------------------------------------------------------------------------ + +...it is recommended to first disable INTn by clearing its Interrupt Enable bit in the +EIMSK Register. Then, the ISCn bit can be changed. Finally, the INTn interrupt flag should be +cleared by writing a logical one to its Interrupt Flag bit (INTFn) in the EIFR Register before the +interrupt is re-enabled. + +EICRA: 7 6 5 4 3 2 1 0 (External Interrupt Control Register A) + ISC: 31 30 21 20 11 10 01 00 Interrupt Sense Control Bits + rw rw rw rw rw rw rw rw + +EICRB: 7 6 5 4 3 2 1 0 (External Interrupt Control Register A) + ISC: - - 61 60 - - - - Interrupt Sense Control Bits + rw rw rw rw rw rw rw rw + + ISCx1 / ISCx0 : INTx + 0 0 Low + 0 1 Change + 1 0 Falling + 1 1 Rising + +EIMSK: 7 6 5 4 3 2 1 0 (External Interrupt Mask Register) + n n n n n + - rw - - rw rw rw rw set to 1 to enable this interrupt + +n= INTn number + +External Interrupt Flag Register is set to 1 when a signal generates an IRQ. +Cleared upon entering the ISR. Can be cleared by writing a 1 to it. +EIFR: 7 6 5 4 3 2 1 0 (External Interrupt Flag Register) + n n n n n + - rw - - rw rw rw rw + +n= INTn number + + +Pin Change Interrupts --------------------------------------------------------------------------- +// PIN CHANGE INTERRUPTS REGISTER BESTIARY +PCICR: 7 6 5 4 3 2 1 0 (When PCIE0 is set and GIE is set, PCI0 is enabled) + PCIE0 + - - - - - - - rw + +// set... +PCIFR: 7 6 5 4 3 2 1 0 (When logic change triggers IRQ, bececomes set. Cleared when + PCIF0 IRQ is executed. PCIF0 == PCIE0.) + - - - - - - - rw Can be cleared by writing 1 to it. + +PCMSK0:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT7:0 + PCINT7 ... PCINT0 If PCIE0 in PCICR and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0 =PORTB + +===================================================================================================== +===================================================================================================== +ATmega2560 Support +===================================================================================================== +===================================================================================================== + +External Interrupts ------------------------------------------------------------------------------ +The following External Interrupts are available on the Arduino: +Arduino + Pin* PORT INT ATmega2560 pin + 21 PD0 0 43 + 20 PD1 1 44 + 19 PD2 2 45 + 18 PD3 3 46 + 2 PE4 4 6 + 3 PE5 5 7 + n/c PE6 6 8 (fake pin 75) + n/c PE7 7 9 (fake pin 76) + +...it is recommended to first disable INTn by clearing its Interrupt Enable bit in the +EIMSK Register. Then, the ISCn bit can be changed. Finally, the INTn interrupt flag should be +cleared by writing a logical one to its Interrupt Flag bit (INTFn) in the EIFR Register before the +interrupt is re-enabled. + +EICRA: 7 6 5 4 3 2 1 0 (External Interrupt Control Register A) + ISC: 31 30 21 20 11 10 01 00 Interrupt Sense Control Bits + rw rw rw rw rw rw rw rw + +EICRB: 7 6 5 4 3 2 1 0 (External Interrupt Control Register B) + ISC: 71 70 61 60 51 50 41 40 Interrupt Sense Control Bits + rw rw rw rw rw rw rw rw NOTE: NO CONNECTION for INT6 and INT7 on ATmega2560** + + ISCx1 / ISCx0 : INTx + 0 0 Low + 0 1 Change + 1 0 Falling + 1 1 Rising + +EIMSK: 7 6 5 4 3 2 1 0 (External Interrupt Mask Register) + n n n n n n n n NOTE: NO CONNECTION FOR INT6 and INT7 on ATmega2560** + rw rw rw rw rw rw rw rw +n= INTn number + +External Interrupt Flag Register is set to 1 when a signal generates an IRQ. +Cleared upon entering the ISR. Can be cleared by writing a 1 to it. +EIFR: 7 6 5 4 3 2 1 0 (External Interrupt Flag Register) + n n n n n n n n NOTE: NO CONNECTION FOR INT6 and INT7 on ATmega2560** + rw rw rw rw rw rw rw rw +n= INTn number + +** But that doesn't mean they wouldn't make an excellent resource for software interrupts! ;-) ) + +Pin Change Interrupts --------------------------------------------------------------------------- + +ATMEGA2560 Pin Change Interrupts +Arduino Arduino Arduino + Pin* PORT PCINT Pin PORT PCINT Pin PORT PCINT + A8 PK0 16 10 PB4 4 SS PB0 0 + A9 PK1 17 11 PB5 5 SCK PB1 1 + A10 PK2 18 12 PB6 6 MOSI PB2 2 + A11 PK3 19 13 PB7 7 MISO PB3 3 + A12 PK4 20 14 PJ1 10 + A13 PK5 21 15 PJ0 9 + A14 PK6 22 0 PE0 8 - this one is a little odd.* + A15 PK7 23 +...indeed, the ATmega2560 chip supports many more Pin Change Interrupt pins but +they are unavailable on the Arduino, unless you want to solder teeny tiny wires. +(However, that doesn't mean they wouldn't make an excellent resource for software interrupts! :-) ) + +* Note: Arduino Pin 0 is PE0 (PCINT8), which is RX0. Also, it is the only other +pin on another port on PCI1. This would make it very costly to integrate with +the library's code and thus is not supported by this library. It is the same +pin the Arduino uses to upload sketches, and it is connected to the FT232RL +USB-to-Serial chip (ATmega16U2 on the R3). + +static const uint8_t SS = 53; +static const uint8_t MOSI = 51; +static const uint8_t MISO = 50; +static const uint8_t SCK = 52; +static const uint8_t A8 = 62; +static const uint8_t A9 = 63; +static const uint8_t A10 = 64; +static const uint8_t A11 = 65; +static const uint8_t A12 = 66; +static const uint8_t A13 = 67; +static const uint8_t A14 = 68; +static const uint8_t A15 = 69; + + + +// PIN CHANGE INTERRUPTS REGISTER BESTIARY for the ATmega2560 + +PCICR: 7 6 5 4 3 2 1 0 (When PCIE2 is set and GIE is set, PCI2 is enabled) + PCIE2 1 0 Likewise for 1 and 0. + - - - - - rw rw rw + +// set... +PCIFR: 7 6 5 4 3 2 1 0 (When logic change triggers IRQ, bececomes set. Cleared when + PCIF2 1 0 IRQ is executed. PCIF2 == PCIE2, etc.) + - - - - - rw rw rw + +PCMSK2:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT23:16 + PCINT23 ... PCINT16 If PCIE2 in PCICR and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PK7 PK6 PK5 PK4 PK3 PK2 PK1 PK0 =PORTK + + + + + + + + + + == available on the Arduino board. + +PCMSK1:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT15:8 + PCINT15 ... PCINT8 If PCIE1 in PCICR and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PJ6 PJ5 PJ4 PJ3 PJ2 PJ1 PJ0 PE0 =PORTJ/E Note pin PE0 is the Arduino's RX pin for programming. + + + + + +PCMSK0:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled o2560n PCINT7:0 + PCINT7 ... PCINT0 If PCIE0 in PCICR and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0 =PORTB + + + + + + + + + + +===================================================================================================== +===================================================================================================== +ATmega644 / 1284 Support (MIGHTY1284 used as a reference, NOT Sanguino) +===================================================================================================== +===================================================================================================== +// Sanguino, Mosquino uino bobino bonanafannafofino, me my momino... +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) + +// Here I use the mighty-1284p pinout from https://maniacbug.wordpress.com/2011/11/27/arduino-on-atmega1284p-4/ + +---\/---+ + (D 0) PB0 |1 40| PA0 (AI 0 / D24) + (D 1) PB1 |2 39| PA1 (AI 1 / D25) + INT2 (D 2) PB2 |3 38| PA2 (AI 2 / D26) + PWM (D 3) PB3 |4 37| PA3 (AI 3 / D27) + PWM SS (D 4) PB4 |5 36| PA4 (AI 4 / D28) + MOSI (D 5) PB5 |6 35| PA5 (AI 5 / D29) + PWM MISO (D 6) PB6 |7 34| PA6 (AI 6 / D30) + PWM SCK (D 7) PB7 |8 33| PA7 (AI 7 / D31) + RST |9 32| AREF + VCC |10 31| GND + GND |11 30| AVCC + XTAL2 |12 29| PC7 (D 23) + XTAL1 |13 28| PC6 (D 22) + RX0 (D 8) PD0 |14 27| PC5 (D 21) TDI + TX0 (D 9) PD1 |15 26| PC4 (D 20) TDO +INT0 RX1 (D 10) PD2 |16 25| PC3 (D 19) TMS +INT1 TX1 (D 11) PD3 |17 24| PC2 (D 18) TCK + PWM (D 12) PD4 |18 23| PC1 (D 17) SDA + PWM (D 13) PD5 |19 22| PC0 (D 16) SDL + PWM (D 14) PD6 |20 21| PD7 (D 15) PWM + +--------+ + +External Interrupts ------------------------------------------------------------------------------ +The following External Interrupts are available on the Sanguino: +Sanguino + Pin* PORT INT ATmega644/1284 pin + 2 PB2 2 3 + 10 PD2 0 16 + 11 PD3 1 17 + +The following Pin Change Interrupts are available on the ATmega1284p: +Mighty Mighty + Pin* PORT PCINT ATmega644/1284 pin Pin* PORT PCINT ATmega644/1284 pin + 0 PB0 8 1 15 PD7 31 21 + 1 PB1 9 2 16 PC0 16 22 + 2 PB2 2 3 17 PC1 17 23 + 3 PB3 11 4 18 PC2 18 24 + 4 PB4 12 5 19 PC3 19 25 + 5 PB5 13 6 20 PC4 20 26 + 6 PB6 14 7 21 PC5 21 27 + 7 PB7 15 8 22 PC6 22 28 + 8 PD0 24 14 23 PC7 23 29 + 9 PD1 25 15 31/A7 PA7 7 33 + 10 PD2 26 16 30/A6 PA6 6 34 + 11 PD3 27 17 29/A5 PA5 5 35 + 12 PD4 28 18 28/A4 PA4 4 36 + 13 PD5 29 19 27/A3 PA3 3 37 + 14 PD6 30 20 26/A2 PA2 2 38 + 25/A1 PA1 1 39 + 24/A0 PA0 0 40 + +EICRA: 7 6 5 4 3 2 1 0 (External Interrupt Control Register A) + ISC: - - 21 20 11 10 01 00 Interrupt Sense Control Bits (ISCxx) + r r rw rw rw rw rw rw + +EIMSK: 7 6 5 4 3 2 1 0 (External Interrupt Mask Register) + - - - - - n n n NOTE: NO CONNECTION FOR INT6 and INT7 on ATmega2560** + r r r r r rw rw rw +n= INTn number + +EIFR: External Interrupt Flag Register is set to 1 when a signal generates an IRQ. +Cleared upon entering the ISR. Can be cleared by writing a 1 to it. +EIFR: 7 6 5 4 3 2 1 0 (External Interrupt Flag Register) + - - - - - n n n NOTE: NO CONNECTION FOR INT6 and INT7 on ATmega2560** + rw r r r rw rw rw rw +n= INTn number + +PCICR: 7 6 5 4 3 2 1 0 (When PCIE2 is set and GIE is set, PCI2 is enabled) + PCIE3 2 1 0 Likewise for 1 and 0. + r r r r rw rw rw rw + +PCIFR: 7 6 5 4 3 2 1 0 (When logic change triggers IRQ, becomes set. Cleared when + PCIF3 2 1 0 IRQ is executed. PCIF2 == PCIE2, etc.) + r r r r rw rw rw rw + +0x73 +PCMSK3:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT23:16 + PCINT31 ... PCINT24 If PCIE2 in PCICR and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0 =PORTD + 15 14 13 12 11 10 09 08 -->Sanguino Pins, DIP40 package + +0x6D +PCMSK2:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT23:16 + PCINT23 ... PCINT16 If PCIE2 in PCICR and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0 =PORTC + 23 22 21 20 19 18 17 16 -->Sanguino Pins, DIP40 package + +PCMSK1:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT15:8 + PCINT15 ... PCINT8 If PCIE1 in PCICR and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0 =PORTB + 7 6 5 4 3 2 1 0 -->Sanguino Pins, DIP40 package + +PCMSK0:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled o2560n PCINT7:0 + PCINT7 ... PCINT0 If PCIE0 in PCICR and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0 =PORTB + 24 25 26 27 28 29 30 31 -->Sanguino Pins, DIP40 package + + +===================================================================================================== +===================================================================================================== +ATtiny 24/44/84 support ATTINY24 +===================================================================================================== +===================================================================================================== +Only the 44/84 are supported. + +Support for this chip is based on David Mellis' work at https://github.com/damellis/attiny +This is an ATmega that comes in a 14-pin configuration. There are two ports, A and B. PCint pins are +configured on both ports. The following is the pinout, and shows the Arduino pin numbering scheme: +// ATtiny24/44/84 / ARDUINO +// +// +-\/-+ +// VCC 1| |14 GND +// (D 10) PB0 2| |13 PA0 (D 0) == AREF +// (D 9) PB1 3| |12 PA1 (D 1) +// PB3 4| |11 PA2 (D 2) +// PWM INT0 (D 8) PB2 5| |10 PA3 (D 3) +// PWM (D 7) PA7 6| |9 PA4 (D 4) +// PWM (D 6) PA6 7| |8 PA5 (D 5) PWM +// +----+ + +gcc CPU designations are as follows: +__AVR_ATtiny24__ __AVR_ATtiny24A__ __AVR_ATtiny44__ __AVR_ATtiny44A__ +__AVR_ATtiny84__ __AVR_ATtiny84A__ + +The following External Interrupts are available on the ATtiny24/44/84: +Arduino(tiny) + Pin* PORT INT ATtiny44/84 pin + 8 PB2 0 5 + +The following Pin Change Interrupts are available on the ATmega24/44/84: +Arduino(tiny) Arduino(tiny) + Pin* PORT PCINT ATmega24/44/84 pin Pin* PORT PCINT ATmega24/44/84 pin + 0 PA0 0 13 5 PA5 5 8 + 1 PA1 1 12 6 PA6 6 7 + 2 PA2 2 11 7 PA7 7 6 + 3 PA3 3 10 8 PB2 10 5 + 4 PA4 4 9 9 PB1 9 3 + 10 PB0 8 2 + "fake" 11 PB3 11 4 + +Interrupt registers are different on the Tiny series. Interrupts are set by MCUCR, GIMSK, GIFR, PCMSK0, and PCMSK1. + +EXTERNAL INTERRUPTS +------------------- +MCUCR: + ISC: - - - - - - 01 00 Interrupt Sense Control Bits (ISCxx) + rw rw rw rw rw rw rw rw + ISC01 00 + +INT0 "is activated if the SREG I-flag and the MCUCR mask is set" (but see GIMSK, below). +ISC01 ISC00 + 0 0 INT0 interrupted on LOW level + 1 1 INT0 interrupted on CHANGE + 0 0 INT0 interrupted on FALLING + 1 1 INT0 interrupted on RISING + +GIMSK: +When INT0 == 1 and SREG I-flag set, External Interrupt enabled. +When PCIE1 == 1 and SREG I-flag set, pin change Interrupt PCINT11:8 enabled. +When PCIE0 == 1 and SREG I-flag set, pin change Interrupt PCINT7:0 enabled. + - INT0 PCIE0 - - - - + PCIE1 + rw rw rw rw rw rw rw rw + -------------------------------- + + +GIFR: 7 6 5 4 3 2 1 0 (When logic change triggers IRQ, becomes set. Cleared when + INTF0 PCIF0 2 1 0 IRQ is executed. INTF0 == INT0, etc.) + - PCIF1 - - - - INT0 is always cleared when INT0 is a LOW interrupt + r rw rw rw r r r r + +PCMSK1:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT15:8 + PCINT11 ... PCINT8 If PCIE1 in GIMSK and this bit is set, it is enabled on that + r r r r rw rw rw rw pin.) + - - - - PB3 PB2 PB1 PB0 =PORTB + - - - - 4 5 3 2 -->ATtiny 24/44/84 Pins, DIP14 package + - - - - 11* 8 9 10 -->Arduino Pins, DIP14 package. * - "Fake" Arduino pin. + +PCMSK0:7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT7:0 + PCINT7 ... PCINT0 If PCIE0 in GIMSK and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0 =PORTA + 7 6 5 4 3 2 1 1 -->ATtiny 24/44/84 Pins, DIP14 package + 6 7 8 9 10 11 12 13 -->Arduino Pins, DIP14 package. * - "Fake" Arduino pin. + +===================================================================================================== +===================================================================================================== +ATtiny 25/45/85 support ATTINY25 +===================================================================================================== +===================================================================================================== +Only the ATtiny 45/85 are supported. +Support for this chip is based on David Mellis' work at https://github.com/damellis/attiny +This is an ATmega that comes in an 8-pin configuration. There is a single port, B. + +gcc CPU designations are as follows: +__AVR_ATtiny25__ __AVR_ATtiny45__ __AVR_ATtiny85__ + +The following is the pinout, and shows the Arduino pin numbering scheme: +// ATtiny25/45/85 / ARDUINO +// +// +-\/-+ +// (D 5) PB5 1| |8 Vcc +// (D 3) PB3 2| |7 PB2 (D 2) (INT0) (== Gemma B2) +// (D 4) PB4 3| |6 PB1 (D 1) (== Gemma B1) +// GND 4| |5 PB0 (D 0) (== Gemma B0) +// +----+ + +The following External Interrupts are available on the ATtiny25/45/85: +Arduino(tiny) + Pin* PORT INT ATtiny25/45/85 pin + 2 PB2 0 7 + +The following Pin Change Interrupts are available on the ATmega25/45/85: +Arduino(tiny) Arduino(tiny) + Pin* PORT PCINT ATmega25/45/85 pin Pin* PORT PCINT ATmega25/45/85 pin + 0 PB0 0 5 3 PB3 3 2 + 1 PB1 1 6 4 PB4 4 3 + 2 PB2 2 7 5 PB5 5 1 + +Interrupt registers are different on the Tiny series. Interrupts are set by MCUCR, GIMSK, GIFR, PCMSK0, and PCMSK1. + + +MCUCR: + ISC: - - - - - - 01 00 Interrupt Sense Control Bits (ISCxx) + rw rw rw rw rw rw rw rw + ISC01 00 + +INT0 "is activated if the SREG I-flag and the MCUCR mask is set" (but see GIMSK, below). +ISC01 ISC00 + 0 0 INT0 interrupted on LOW level + 1 1 INT0 interrupted on CHANGE + 0 0 INT0 interrupted on FALLING + 1 1 INT0 interrupted on RISING + +GIMSK: +When INT0 == 1 and SREG I-flag set, External Interrupt enabled. +When PCIE == 1 and SREG I-flag set, pin change Interrupt PCINT5:0 enabled. + - INT0 - - - - - + PCIE + r rw rw r r r r r + -------------------------------- + + +GIFR: 7 6 5 4 3 2 1 0 (When logic change triggers IRQ, becomes set. Cleared when + INT0 IRQ is executed. INT0 == INT0, etc.) + - PCIE - - - - - INT0 is always cleared when INT0 is a LOW interrupt + r rw rw r r r r r + +PCMSK :7 6 5 4 3 2 1 0 (Selects whether pin change interrupt is enabled on PCINT7:0 + PCINT5 ... PCINT0 If PCIE0 in GIMSK and this bit is set, it is enabled on that + rw rw rw rw rw rw rw rw pin.) + - - PB5 PB4 PB3 PB2 PB1 PB0 =PORTB + 1 3 2 7 6 5 -->ATtiny 25/45/85 Pins, DIP8 package + + +================================================================================================================= +From http://www.atmel.com/Images/doc8468.pdf: + +External interrupts can be sensed and registered either synchronously or asynchronously. Synchronous sensing +requires I/O clock whereas asynchronous sensing does not requires I/O clock. This implies that the interrupts +that are detected asynchronously can be used for waking the device from sleep modes other than idle +mode because the I/O clock is halted in all sleep modes except idle mode. The sense configuration for +external interrupts and pin change interrupts for Atmel ATmega2560 is given in Table 2-2. For device +specific sense configuration, please refer to the respective datasheet. + +Table 2-2. External interrupts sense configuration. +Program address Interrupt source Sensing +$0002 INT0 Asynchronous (Edges and level) +$0004 INT1 Asynchronous (Edges and level) +$0006 INT2 Asynchronous (Edges and level) +$0008 INT3 Asynchronous (Edges and level) +$000A INT4 Synchronous (Edges and level) +$000C INT5 Synchronous (Edges and level) +$000E INT6 Synchronous (Edges and level) +$0010 INT7 Synchronous (Edges and level) +$0012 PCINT0 Asynchronous +$0014 PCINT1 Asynchronous +$0016 PCINT2 Asynchronous +From Table 2-2, all the pin change interrupts are detected asynchronously. + +... +The interrupt execution response for all the enabled AVR interrupts is four/five clock cycle’s minimum. +This four/five clock cycles depends on the program counter width. If the program counter width is not +more than two bytes, then the interrupt response time will be four clock cycles minimum and if the +program counter width is more than two bytes, then the interrupt response time will be minimum five +clock cycles. These four/five clock cycles include: +1. Two/Three cycles for pushing the Program Counter (PC) value into the stack. +2. One cycle for updating the stack pointer. +3. One cycle for clearing the Global interrupt enable (I) bit. +If an interrupt occurs when the MCU is in sleep mode, the interrupt execution response time is increased +by five clock cycles. This increase comes in addition to the start-up time from the selected sleep mode. +This start up time is the time it will take to start the clock source. + +===================================================================================================== +ARDUINO CPU BESTIARY +===================================================================================================== +See /usr/avr/include/avr/io.h for the actual #defines for the different CPUs. +The CPUs are converted to the #defined macros (eg., __AVR_ATmega169__) by the compiler from +the source file "avr-mcus.def". See +https://github.com/gcc-mirror/gcc/blob/master/gcc/config/avr/avr-mcus.def + +$ grep mcu /usr/share/arduino/hardware/arduino/boards.txt +uno.build.mcu=atmega328p +atmega328.build.mcu=atmega328p +diecimila.build.mcu=atmega168 +nano328.build.mcu=atmega328p +nano.build.mcu=atmega168 +mega2560.build.mcu=atmega2560 +mega.build.mcu=atmega1280 +leonardo.build.mcu=atmega32u4 +esplora.build.mcu=atmega32u4 +micro.build.mcu=atmega32u4 +mini328.build.mcu=atmega328p +mini.build.mcu=atmega168 +ethernet.build.mcu=atmega328p +fio.build.mcu=atmega328p +bt328.build.mcu=atmega328p +bt.build.mcu=atmega168 +LilyPadUSB.build.mcu=atmega32u4 +lilypad328.build.mcu=atmega328p +lilypad.build.mcu=atmega168 +pro5v328.build.mcu=atmega328p +pro5v.build.mcu=atmega168 +pro328.build.mcu=atmega328p +pro.build.mcu=atmega168 +atmega168.build.mcu=atmega168 +atmega8.build.mcu=atmega8 +robotControl.build.mcu=atmega32u4 +robotMotor.build.mcu=atmega32u4 + +ISR Register handling + +Tested the following code to ensure that all registers would be pushed/popped correctly, even +if I was using NAKED_ISR. Note that I did not run code, I merely eyeballed the output to ensure +it was doing what I expected: + +volatile uint8_t storage0; +volatile uint8_t storage1; +volatile uint8_t storage2; +volatile uint8_t storage3; +volatile uint8_t storage4; +volatile uint8_t storage5; +volatile uint8_t storage6; +volatile uint8_t storage7; +volatile uint8_t storage8; +volatile uint8_t storage9; +volatile uint8_t storage10; +volatile uint8_t storage11; +volatile uint8_t storage12; +volatile uint8_t storage13; +volatile uint8_t storage14; +volatile uint8_t storage15; +volatile uint8_t storage16; +volatile uint8_t storage17; +volatile uint8_t storage18; +volatile uint8_t storage19; + +void test_ISR(uint8_t current) { + + uint8_t local0=storage0; + uint8_t local1=storage1; + uint8_t local2=storage2; + uint8_t local3=storage3; + uint8_t local4=storage4; + uint8_t local5=storage5; + uint8_t local6=storage6; + uint8_t local7=storage7; + uint8_t local8=storage8; + uint8_t local9=storage9; + uint8_t local10=storage10; + uint8_t local11=storage11; + uint8_t local12=storage12; + uint8_t local13=storage13; + uint8_t local14=storage14; + uint8_t local15=storage15; + uint8_t local16=storage16; + uint8_t local17=storage17; + uint8_t local18=storage18; + uint8_t local19=storage19; + + local0+=current; + local1+=current; + local2+=current; + local3+=current; + local4+=current; + local5+=current; + local6+=current; + local7+=current; + local8+=current; + local9+=current; + local10+=current; + local11+=current; + local12+=current; + local13+=current; + local14+=current; + local15+=current; + local16+=current; + local17+=current; + local18+=current; + local19+=current; + + storage0=local0; + storage1=local1; + storage2=local2; + storage3=local3; + storage4=local4; + storage5=local5; + storage6=local6; + storage7=local7; + storage8=local8; + storage9=local9; + storage10=local10; + storage11=local11; + storage12=local12; + storage13=local13; + storage14=local14; + storage15=local15; + storage16=local16; + storage17=local17; + storage18=local18; + storage19=local19; +} + +ISR(PORTD_VECT, ISR_NAKED) { + register uint8_t current asm("r18"); + EI_ASM_PREFIX(PIND); + + test_ISR(current); + + EI_ASM_SUFFIX; +} + +MISCELLANEOUS: +STORING FUNCTION POINTERS IN PROGMEM: +http://stackoverflow.com/questions/28261595/put-progmem-function-pointer-array-into-another-progmem-array + + +Calling the function pointers by checking each pin's bitmask individually: + + if (interruptMask & _BV(0)) functionPointerB0(); Cycles + 8b8: c0 ff sbrs r28, 0 1 if move on, 2 if skip (to 8bc) + 8ba: 05 c0 rjmp .+10 2 (move on) + 8bc: e0 91 60 02 lds r30, 0x0260 2 + 8c0: f0 91 61 02 lds r31, 0x0261 2 + 8c4: 19 95 eicall 4 + 8c6: (move on) TOTAL: 10 if matches, 3 if not + == 21 cycles till get to last function call, + then 10 cycles to execute it: 31 cycles + + If an interrupt on third pin: + 2 x 3 (not matched) + 10 == 16, plus + 4 x 3 (not matched) = 28 total. + +Calling the function pointers referred to in an array, using while loop: + + 8c6: d0 e0 ldi r29, 0x00 ; 0 this is the "i" variable + + while (1) { + if (interruptMask & 0x01) { + 8c8: c0 ff sbrs r28, 0 1 if it's not set, 2 if skip + 8ca: 0a c0 rjmp .+20 2 (move on to try next bit at 0x8e0) + (*functionPointerArray[i])(); + 8cc: ed 2f mov r30, r29 1 (it's set, execute the function) + 8ce: f0 e0 ldi r31, 0x00 1 ; loads 0 + 8d0: ee 0f add r30, r30 1 + 8d2: ff 1f adc r31, r31 1 + 8d4: e7 57 subi r30, 0x77 1 ; 119 + 8d6: fd 4f sbci r31, 0xFD 1 ; 253 + 8d8: 01 90 ld r0, Z+ 1 load from data memory + 8da: f0 81 ld r31, Z 1 + 8dc: e0 2d mov r30, r0 1 + 8de: 19 95 eicall 4 + } + interruptMask=interruptMask >> 1; + 8e0: c6 95 lsr r28 1 + if (interruptMask == 0) goto exitISR; + 8e2: 11 f0 breq .+4 1 if not zero, 2 if zero (jumps out...) ; 0x8e8 <__vector_9+0x86> + i++; + 8e4: df 5f subi r29, 0xFF 1 ; 255 + 8e6: f0 cf rjmp .-32 2 ; 0x8c8 <__vector_9+0x66> + + TOTAL: 14 if matches, 9 if not + == 63 cycles to get to last function call, + then 14 cycles to execute it: 77 cycles + + If an interrupt on third pin: + 2 x 7 (not matched) == 14 + 14 == 28 total. + Then a couple of cycles to get out. + + +=========================================================================================================== +Space Optimizations +=========================================================================================================== +Compile Simple.ino, using pin 10, compile for ATmega2560: +Program: 6402 bytes (2.4% Full) +(.text + .data + .bootloader) + +Data: 859 bytes (10.5% Full) +(.data + .bss + .noinit) + + +Compile Simple.ino, using pin 10, define EI_NOTEXTERNAL: +Program: 5328 bytes (2.0% Full) +(.text + .data + .bootloader) + +Data: 843 bytes (10.3% Full) +(.data + .bss + .noinit) + +Compile Simple.ino, using pin 10, define EI_NOTPORTJ: +Program: 5006 bytes (1.9% Full) +(.text + .data + .bootloader) + +Data: 825 bytes (10.1% Full) +(.data + .bss + .noinit) + +Compile Simple.ino, using pin 10, define EI_NOTPORTJ EI_NOTPORTK: +Program: 4686 bytes (1.8% Full) +(.text + .data + .bootloader) + +Data: 806 bytes (9.8% Full) +(.data + .bss + .noinit) + + +Compile Simple.ino, using pin 10, define EI_NOTPORTJ EI_NOTPORTK EI_NOTEXTERNAL: +Program: 4674 bytes (1.8% Full) +(.text + .data + .bootloader) + +Data: 806 bytes (9.8% Full) +(.data + .bss + .noinit) + diff --git a/libraries/EnableInterrupt/examples/ATtinyBlink/ATtinyBlink.ino b/libraries/EnableInterrupt/examples/ATtinyBlink/ATtinyBlink.ino new file mode 100644 index 0000000..5245232 --- /dev/null +++ b/libraries/EnableInterrupt/examples/ATtinyBlink/ATtinyBlink.ino @@ -0,0 +1,48 @@ +#include + +#ifdef EI_ATTINY24 +#define OUTPUTPIN 10 // == B0 +#define INTERRUPTEDPIN 9 // == B1 +// Modify this at your leisure. But you must be aware of which port it's on (see below). +#elif defined EI_ATTINY25 +#define OUTPUTPIN 0 // == B0 +#define INTERRUPTEDPIN 1 // == B1 +#else +#error Dang, only ATtiny chips supported by this sketch. +#endif + +// Connect a LED to Pin 3. It might be different in different ATtiny micro controllers +//const uint8_t outputBitMask = 0x01; +const uint8_t outputBitMask = digital_pin_to_bit_mask_PGM[OUTPUTPIN]; +const uint8_t inputBitMask = digital_pin_to_bit_mask_PGM[INTERRUPTEDPIN]; + +volatile uint16_t endlessCounter=0; // The count will go back to 0 after hitting 65535. +volatile uint8_t interruptState=0; + +void interruptFunction() { + if (interruptState) { + interruptState=0; + PORTB &= ~_BV(outputBitMask); + } else { + interruptState=1; + PORTB |= 1 << outputBitMask; + } +} + +// the setup routine runs once when you press reset: +void setup() { + DDRB |= outputBitMask; // OUTPUTPIN is set to output + DDRB &= ~inputBitMask; // INPUTPIN is set to input + PORTB |= inputBitMask; // Pull up the resistor + MCUCR &= ~PUD; // ensure Pull Up Disable is off + enableInterrupt(INTERRUPTEDPIN, interruptFunction, CHANGE); +} + +// the loop routine runs over and over again forever: +void loop() { + //digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) + //delay(1000); // wait for a second + //digitalWrite(led, LOW); // turn the LED off by making the voltage LOW + //delay(1000); // wait for a second + endlessCounter++; // give it something to do +} diff --git a/libraries/EnableInterrupt/examples/ATtinyBlink/Makefile b/libraries/EnableInterrupt/examples/ATtinyBlink/Makefile new file mode 100644 index 0000000..af27677 --- /dev/null +++ b/libraries/EnableInterrupt/examples/ATtinyBlink/Makefile @@ -0,0 +1,19 @@ +## Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +ARDUINO_DIR = /home/schwager/bin/arduino-1.8.5 + +# ISP_PORT = /dev/ttyACM0 +#BOARD_TAG = attiny85at8 +BOARD_TAG = attiny44at8 +ALTERNATE_CORE = tiny +BOARDS_TXT = ~/sketchbook/hardware/arduino-tiny/boards.txt +ARDUINO_CORE_PATH = /home/schwager/sketchbook/hardware/arduino-tiny/cores/tiny +# ARDUINO_VAR_PATH = ~/sketchbook/hardware/arduino-tiny/cores/tiny +#AVR_TOOLS_DIR = /home/schwager/bin/arduino-1.8.4/hardware/tools/avr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +ISP_PROG = usbtiny +F_CPU = 1000000L + +include /usr/share/arduino/Arduino.mk diff --git a/libraries/EnableInterrupt/examples/AllPins2560/AllPins2560.ino b/libraries/EnableInterrupt/examples/AllPins2560/AllPins2560.ino new file mode 100644 index 0000000..b80ea66 --- /dev/null +++ b/libraries/EnableInterrupt/examples/AllPins2560/AllPins2560.ino @@ -0,0 +1,228 @@ +// EnableInterrupt Simple example sketch +// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information. + +#include + +volatile uint8_t externalInterruptCounter=0; +volatile uint8_t anyInterruptCounter=0; + +#ifdef ARDUINO_MEGA +#define PINCOUNT(x) pin ##x ##Count + +// Do not use any Serial.print() in interrupt subroutines. Serial.print() uses interrupts, +// and by default interrupts are off in interrupt subroutines. Interrupt routines should also +// be as fast as possible. Here we just increment counters. +#define interruptFunction(x) \ + volatile uint8_t PINCOUNT(x); \ + void interruptFunction ##x () { \ + anyInterruptCounter++; \ + PINCOUNT(x)++; \ + } + +#define interruptExFunction(x) \ + volatile uint8_t PINCOUNT(x); \ + void interruptExFunction ##x () { \ + externalInterruptCounter++; \ + anyInterruptCounter++; \ + PINCOUNT(x)++; \ + } + +#define updateOn(x) \ + if (PINCOUNT(x) != 0) { \ + printIt((char *) #x, PINCOUNT(x)); \ + PINCOUNT(x)=0; \ + } + +#define disablePCInterrupt(x) \ + disableInterrupt( x | PINCHANGEINTERRUPT) + +#define setupInterrupt(x) \ + EI_printPSTR("Add pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x, interruptFunction##x, CHANGE) + +#define setupExInterrupt(x) \ + EI_printPSTR("Add External pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x, interruptExFunction##x, CHANGE) + +interruptFunction(SS); +interruptFunction(SCK); +interruptFunction(MOSI); +interruptFunction(MISO); +interruptFunction(10); +interruptFunction(11); +interruptFunction(12); +interruptFunction(13); +interruptFunction(14); +interruptFunction(15); +interruptFunction(A8); +interruptFunction(A9); +interruptFunction(A10); +interruptFunction(A11); +interruptFunction(A12); +interruptFunction(A13); +interruptFunction(A14); +interruptFunction(A15); +interruptFunction(70); // fake 70, trick to allow software interrupts on Port J. PJ2 +interruptFunction(71); // fake 71. PJ3 +interruptFunction(72); // fake 72. PJ4 +interruptFunction(73); // fake 73. PJ5 +interruptFunction(74); // fake 74. PJ6 +// External Interrupts +interruptExFunction(21); +interruptExFunction(20); +interruptExFunction(19); +interruptExFunction(18); +interruptExFunction(2); +interruptExFunction(3); +interruptExFunction(75); // fake 75. PE6 +interruptExFunction(76); // fake 76. PE7 +#else +#error This sketch supports 2560-based Arduinos only. +#endif + +void printIt(char *pinNumber, uint8_t count) { + EI_printPSTR("Pin "); + Serial.print(pinNumber); + EI_printPSTR(" was interrupted: "); + Serial.println(count, DEC); +} + +// Attach the interrupt in setup() +// NOTE: PORTJ2-6 (aka, "Pin '70', '71', '72', '73', '74'" are turned on as OUTPUT. +// These are not true pins on the Arduino Mega series! +void setup() { + //uint8_t pind, pink; + Serial.begin(115200); + EI_printPSTR("---------------------------------------"); + // PINS 0 and 1 NOT USED BECAUSE OF Serial.print() + setupInterrupt(SS); + setupInterrupt(SCK); + setupInterrupt(MOSI); + setupInterrupt(MISO); + setupInterrupt(10); + setupInterrupt(11); + setupInterrupt(12); + setupInterrupt(13); + setupInterrupt(14); + setupInterrupt(15); + setupInterrupt(A8); + setupInterrupt(A9); + setupInterrupt(A10); + setupInterrupt(A11); + setupInterrupt(A12); + setupInterrupt(A13); + setupInterrupt(A14); + setupInterrupt(A15); + //// + DDRJ |=0b01111100; // Non-Arduino Port J pins all become output. + PORTJ|=0b01111100; // Turn them all high. + enableInterrupt(70, interruptFunction70, CHANGE); + enableInterrupt(71, interruptFunction71, CHANGE); + enableInterrupt(72, interruptFunction72, CHANGE); + enableInterrupt(73, interruptFunction73, CHANGE); + enableInterrupt(74, interruptFunction74, CHANGE); + // External Interrupts + setupExInterrupt(21); + setupExInterrupt(20); + setupExInterrupt(19); + setupExInterrupt(18); + setupExInterrupt(2); + setupExInterrupt(3); + //// + DDRE |=0b11000000; // Non-Arduino Port E pins all become output. + PORTE|=0b11000000; // Turn them all high. + enableInterrupt(75, interruptExFunction75, CHANGE); + enableInterrupt(76, interruptExFunction76, CHANGE); +} + +uint8_t otherToggle=1; +uint8_t enabledToggle=1; +uint8_t disableCounter=0; +// In the loop, we just check to see where the interrupt count is at. The value gets updated by the +// interrupt routine. +void loop() { + uint8_t jbits =0b01111110; // PJ2 + uint8_t njbits=0b00000001; // PJ2 + uint8_t ebits =0b11000000; // PE6/7 + uint8_t nebits=0b00111111; // PE6/7 + + EI_printPSTR("------\r\n"); + delay(1000); // Every second, + if (disableCounter & 0x08) { + EI_printPSTR("Toggle 20, 71, 75, A8, 15, MISO..."); + delay(1000); + if (enabledToggle==1) { + EI_printPSTR("---OFF---"); + disableInterrupt(20); + disableInterrupt(71); + disableInterrupt(75); + disableInterrupt(15); + disableInterrupt(A8); + disableInterrupt(MISO); + enabledToggle=0; + } + else { + EI_printPSTR("***ON***"); + setupExInterrupt(20); + setupInterrupt(71); + setupExInterrupt(75); + setupInterrupt(15); + setupInterrupt(A8); + setupInterrupt(MISO); + enabledToggle=1; + } + disableCounter=0; + } + PORTE &= nebits; + PORTJ &= njbits; + // *out &= njbits; + delay(1); + PORTE |= ebits; + PORTJ |= jbits; + // *out |= jbits; + delay(1); + updateOn(SS); + updateOn(SCK); + updateOn(MOSI) + updateOn(MISO); + updateOn(10); + updateOn(11); + updateOn(12); + updateOn(13); + updateOn(14); + updateOn(15); + updateOn(A8); + updateOn(A9); + updateOn(A10); + updateOn(A11); + updateOn(A12); + updateOn(A13); + updateOn(A14); + updateOn(A15); + // External Interrupts + updateOn(2); + updateOn(3); + updateOn(18); + updateOn(19); + updateOn(20); + updateOn(21); + // Fake Arduino Pins + updateOn(70); + updateOn(71); + updateOn(72); + updateOn(73); + updateOn(74); + // External Interrupts + updateOn(75); + updateOn(76); + if (externalInterruptCounter > 0) { EI_printPSTR(" ext: "); Serial.println(externalInterruptCounter); }; \ + externalInterruptCounter=0; + disableCounter++; +} + diff --git a/libraries/EnableInterrupt/examples/AllPins2560/Makefile b/libraries/EnableInterrupt/examples/AllPins2560/Makefile new file mode 100644 index 0000000..0b3415a --- /dev/null +++ b/libraries/EnableInterrupt/examples/AllPins2560/Makefile @@ -0,0 +1,12 @@ +# Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +BOARD_TAG = mega +BOARD_SUB = atmega2560 +ARDUINO_PORT = /dev/ttyACM0 +ARDUINO_LIBS = +AVR_TOOLS_DIR = /usr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +include /usr/share/arduino/Arduino.mk + diff --git a/libraries/EnableInterrupt/examples/AllPins328/AllPins328.ino b/libraries/EnableInterrupt/examples/AllPins328/AllPins328.ino new file mode 100644 index 0000000..74445a3 --- /dev/null +++ b/libraries/EnableInterrupt/examples/AllPins328/AllPins328.ino @@ -0,0 +1,200 @@ +// EnableInterrupt Simple example sketch +// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information. + +// This example demonstrates the use of the EnableInterrupt library on all pins. +// The library has only been tested on an Arduino Duemilanove and Mega ADK. + +#include + +volatile uint8_t externalInterruptCounter=0; +volatile uint8_t anyInterruptCounter=0; + +#ifdef ARDUINO_328 +#define PINCOUNT(x) pin ##x ##Count + +// Do not use any Serial.print() in interrupt subroutines. Serial.print() uses interrupts, +// and by default interrupts are off in interrupt subroutines. Interrupt routines should also +// be as fast as possible. Here we just increment counters. +#define interruptFunction(x) \ + volatile uint8_t PINCOUNT(x); \ + void interruptFunction ##x () { \ + anyInterruptCounter++; \ + PINCOUNT(x)++; \ + } + +#define interruptExFunction(x) \ + volatile uint8_t PINCOUNT(x); \ + void interruptExFunction ##x () { \ + externalInterruptCounter++; \ + anyInterruptCounter++; \ + PINCOUNT(x)++; \ + } + +#define updateOn(x) \ + if (PINCOUNT(x) != 0) { \ + printIt((char *) #x, PINCOUNT(x)); \ + if (externalInterruptCounter > 0) { \ + EI_printPSTR(" ext: "); Serial.println(externalInterruptCounter); \ + externalInterruptCounter=0; \ + }; \ + PINCOUNT(x)=0; \ + } + +#define disablePCInterrupt(x) \ + disableInterrupt( x | PINCHANGEINTERRUPT) + +#define setupPCInterrupt(x) \ + EI_printPSTR("Add PinChange pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x | PINCHANGEINTERRUPT, interruptFunction##x, CHANGE) + +#define setupInterrupt(x) \ + EI_printPSTR("Add pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x, interruptFunction##x, CHANGE) + +#define setupExInterrupt(x) \ + EI_printPSTR("Add External pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x , interruptExFunction##x, CHANGE) + +interruptFunction(2); +interruptExFunction(3); +interruptFunction(4); +interruptFunction(5); +interruptFunction(6); +interruptFunction(7); +interruptFunction(8); +interruptFunction(9); +interruptFunction(10); +interruptFunction(11); +interruptFunction(12); +interruptFunction(13); +interruptFunction(A0); +interruptFunction(A1); +interruptFunction(A2); +interruptFunction(A3); +interruptFunction(A4); +interruptFunction(A5); + +volatile uint8_t otherCounter=0; +void otherInterrupt3Function(void) { // Must appear after interruptFunction(3) + pin3Count++; + otherCounter++; +} +#else +#error This sketch supports 328-based Arduinos only. +#endif + +void printIt(char *pinNumber, uint8_t count) { + EI_printPSTR(" Pin "); + Serial.print(pinNumber); + EI_printPSTR(" was interrupted: "); + Serial.println(count, DEC); +} + +// Attach the interrupt in setup() +// NOTE: PORTJ2-6 (aka, "Pin '70', '71', '72', '73', '74'" are turned on as OUTPUT. +// These are not true pins on the Arduino Mega series! +void setup() { + Serial.begin(115200); + EI_printPSTR("--- START ------------------------------------\r\n"); +#ifdef DEBUG + pinMode(PINSIGNAL, OUTPUT); +#endif + // PINS 0 and 1 NOT USED BECAUSE OF Serial.print() + setupPCInterrupt(2); // by default, will be External Interrupt + setupExInterrupt(3); + setupInterrupt(4); + setupInterrupt(5); + setupInterrupt(6); + setupInterrupt(7); + setupInterrupt(8); + setupInterrupt(9); + setupInterrupt(10); + setupInterrupt(11); + setupInterrupt(12); +#ifndef DEBUG + // NOTE: Because the Arduino Duemilanove has an LED to ground and a 1k resistor in series with + // it to the pin, Voltage at the pin should be hovering between 1-3 volts. 'nearly' ground. So + // a wire to ground will not trip an interrupt, even though we have INPUT_PULLUP. A wire to PWR + // will trigger an interrupt. The Uno has a op-amp buffer/driver to the LED, so will not have + // this problem; it will behave like the other pins. + setupInterrupt(13); +#endif + setupInterrupt(A0); + setupInterrupt(A1); + setupInterrupt(A2); + setupInterrupt(A3); + setupInterrupt(A4); + setupInterrupt(A5); +} + +uint8_t otherToggle=1; +uint8_t enabledToggle=1; +uint8_t disableCounter=0; +// In the loop, we just check to see where the interrupt count is at. The value gets updated by +// the interrupt routine. +void loop() { + EI_printPSTR("------\r\n"); + delay(1000); // Perform the loop every second. + if (disableCounter & 0x08) { + EI_printPSTR("Toggle 2, 3, 8, A0..."); + delay(1000); + if (enabledToggle==1) { + disablePCInterrupt(2); + disableInterrupt(3); + disableInterrupt(8); + disableInterrupt(A0); + enabledToggle=0; + } + else { + if (otherToggle == 1) { + EI_printPSTR("3 is now a Pin Change Interrupt.\r\n"); + enableInterrupt(3, otherInterrupt3Function, CHANGE); // make sure we can switch functions. + otherToggle=0; + } else { + EI_printPSTR("3 is now an External Interrupt.\r\n"); + otherToggle=1; + setupExInterrupt(3); + } + setupPCInterrupt(2); + setupInterrupt(8); + setupInterrupt(A0); + enabledToggle=1; + } + disableCounter=0; + } + updateOn(2); + updateOn(3); + updateOn(4); + updateOn(5); + updateOn(6); + updateOn(7); + updateOn(8); + updateOn(9); + updateOn(10); + updateOn(11); + updateOn(12); + updateOn(13); + updateOn(A0); + updateOn(A1); + updateOn(A2); + updateOn(A3); + updateOn(A4); + updateOn(A5); + EI_printPSTR("Consolidated interrupt count: "); Serial.println(anyInterruptCounter); + if (otherCounter) { + printIt((char *) "OTHER3", otherCounter); + otherCounter=0; + } + externalInterruptCounter=0; + disableCounter++; +} + diff --git a/libraries/EnableInterrupt/examples/AllPins328/Makefile b/libraries/EnableInterrupt/examples/AllPins328/Makefile new file mode 100644 index 0000000..6a75e20 --- /dev/null +++ b/libraries/EnableInterrupt/examples/AllPins328/Makefile @@ -0,0 +1,12 @@ +# Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +BOARD_TAG = pro +BOARD_SUB = 16MHzatmega328 +ARDUINO_PORT = /dev/ttyUSB0 +ARDUINO_LIBS = +AVR_TOOLS_DIR = /usr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +include /usr/share/arduino/Arduino.mk + diff --git a/libraries/EnableInterrupt/examples/Debounce/Debounce.ino b/libraries/EnableInterrupt/examples/Debounce/Debounce.ino new file mode 100644 index 0000000..0e32b19 --- /dev/null +++ b/libraries/EnableInterrupt/examples/Debounce/Debounce.ino @@ -0,0 +1,42 @@ +/* + * This example shows how to combine the EnableInterrupt + * library with some simple debouncing code for reading + * button presses consistently. + * + * The interrupt is attached to digital input 5 and the + * service routine just toggles the onboard LED status. + * + * Tested on: ATmega328P + * + * Example by Lorenzo Cafaro + * +*/ + +#include + +#define BUTTON_PIN 5 +#define DEBOUNCE_DELAY 100 // in ms + +uint32_t last_interrupt_time = 0; +uint8_t led_status = 0; + +void setup() { + pinMode(BUTTON_PIN, INPUT); + pinMode(LED_BUILTIN, OUTPUT); + enableInterrupt(BUTTON_PIN, isr_handler, RISING); +} + +void loop() { + // zZz +} + +void isr_handler() { + uint32_t interrupt_time = millis(); + + if (interrupt_time - last_interrupt_time > DEBOUNCE_DELAY) { + led_status = !led_status; + digitalWrite(LED_BUILTIN, led_status); + } + + last_interrupt_time = interrupt_time; +} diff --git a/libraries/EnableInterrupt/examples/HiSpeed/HiSpeed.ino b/libraries/EnableInterrupt/examples/HiSpeed/HiSpeed.ino new file mode 100644 index 0000000..e478233 --- /dev/null +++ b/libraries/EnableInterrupt/examples/HiSpeed/HiSpeed.ino @@ -0,0 +1,64 @@ +// EnableInterrupt HiSpeed example sketch +// See https://github.com/GreyGnome/EnableInterrupt and the README.md for more information. + +// This example demonstrates the use of the EnableInterrupt library on a single pin of your choice. +// It uses the "HiSpeed" mode of the library. +// This has only been tested on an Arduino Duemilanove and Mega ADK. +// It is designed to work with the Arduino Duemilanove/Uno, Arduino Mega2560/ADK, the Arduino +// Leonardo, and the Arduino Due. Please let me know how you fare on the Leonardo or Due. + +// To use: + +// 1. You must be using a fairly recent version of the Arduino IDE software on your PC/Mac, +// that is, version 1.0.1 or later. Check Help->About Arduino in the IDE. + +// 2. Wire a simple switch to an Analog or Digital pin (pin 8 in the example below) +// that supports interrupts. See https://github.com/GreyGnome/EnableInterrupt/wiki/Usage#Summary +// Attach the other end to a GND pin. A "single pole single throw momentary contact normally +// open" // pushbutton switch is best for the most interrupting fun. +// See https://www.sparkfun.com/products/97 and https://octopart.com/b3f-1000-omron-3117 + +// 3. When pressed, the switch will connect the pin to ground ("low", or "0") voltage, and interrupt the +// processor. See http://arduino.cc/en/Tutorial/DigitalPins + +// 4. The interrupt is serviced immediately, and the ISR (Interrupt SubRoutine) sets the value of a global +// variable. Open Tools->Serial Monitor in the IDE to see the results of your interrupts. + +// 5. Peruse the Examples directory for more elaborate examples. + +// 6. Create your own sketch using the EnableInterrupt library! + +// Refer to +// https://github.com/GreyGnome/EnableInterrupt/wiki/Usage#Summary + +#define NEEDFORSPEED + +#define INTERRUPT_FLAG_PIN8 myvariable_pin8 // NOTICE: NO semicolon!!! + +#include + +// Attach the interrupt in setup() +void setup() { + //uint8_t pind, pink; + Serial.begin(115200); + EI_printPSTR("---------------------------------------\r\n"); + pinMode(8, INPUT_PULLUP); // Configure the pin as an input, and turn on the pullup resistor. + // See http://arduino.cc/en/Tutorial/DigitalPins + enableInterruptFast(8, CHANGE); +} + +// In the loop, we just check to see where the interrupt count is at. The value gets updated by the +// interrupt routine. +void loop() { + EI_printPSTR("---------------------------------------\r\n"); + delay(1000); // Every second, + if (myvariable_pin8) { + EI_printPSTR("Pin 8 was interrupted: "); + Serial.print(myvariable_pin8, DEC); // print the interrupt count. + EI_printPSTR(" times so far.\r\n"); + myvariable_pin8=0; + } + else { + EI_printPSTR("No interrupts.\r\n"); + } +} diff --git a/libraries/EnableInterrupt/examples/HiSpeed/Makefile b/libraries/EnableInterrupt/examples/HiSpeed/Makefile new file mode 100644 index 0000000..b10e505 --- /dev/null +++ b/libraries/EnableInterrupt/examples/HiSpeed/Makefile @@ -0,0 +1,14 @@ +# Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +BOARD_TAG = pro +BOARD_SUB = 16MHzatmega328 +ARDUINO_PORT = /dev/ttyUSB0 +#BOARD_TAG = 2560 +#ARDUINO_PORT = /dev/ttyACM0 +ARDUINO_LIBS = +AVR_TOOLS_DIR = /usr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +include /usr/share/arduino/Arduino.mk + diff --git a/libraries/EnableInterrupt/examples/HiSpeed/README b/libraries/EnableInterrupt/examples/HiSpeed/README new file mode 100644 index 0000000..c82c2cf --- /dev/null +++ b/libraries/EnableInterrupt/examples/HiSpeed/README @@ -0,0 +1,4 @@ +Note: This code has not been tested! Caveat Programmer. I will do it asap. +(I have tested the HiSpeed code using the HiSpeedTest sketch, so I'm confident +the library is working properly. Also this sketch compiles.). +-GreyGnome diff --git a/libraries/EnableInterrupt/examples/HiSpeedAllPins2560/HiSpeedAllPins2560.ino b/libraries/EnableInterrupt/examples/HiSpeedAllPins2560/HiSpeedAllPins2560.ino new file mode 100644 index 0000000..51ee428 --- /dev/null +++ b/libraries/EnableInterrupt/examples/HiSpeedAllPins2560/HiSpeedAllPins2560.ino @@ -0,0 +1,205 @@ +// EnableInterrupt example sketch: Hi Speed Interrupts, ATmega2560/compatible, all pins +// See the Wiki at https://github.com/GreyGnome/EnableInterrupt/wiki + +#define NEEDFORSPEED + +#define INTERRUPT_FLAG_PINSS iflag_pinSS +#define INTERRUPT_FLAG_PINSCK iflag_pinSCK +#define INTERRUPT_FLAG_PINMOSI iflag_pinMOSI +#define INTERRUPT_FLAG_PINMISO iflag_pinMISO +#define INTERRUPT_FLAG_PIN10 iflag_pin10 +#define INTERRUPT_FLAG_PIN11 iflag_pin11 +#define INTERRUPT_FLAG_PIN12 iflag_pin12 +#define INTERRUPT_FLAG_PIN13 iflag_pin13 +#define INTERRUPT_FLAG_PIN14 iflag_pin14 +#define INTERRUPT_FLAG_PIN15 iflag_pin15 +#define INTERRUPT_FLAG_PINA8 iflag_pinA8 +#define INTERRUPT_FLAG_PINA9 iflag_pinA9 +#define INTERRUPT_FLAG_PINA10 iflag_pinA10 +#define INTERRUPT_FLAG_PINA11 iflag_pinA11 +#define INTERRUPT_FLAG_PINA12 iflag_pinA12 +#define INTERRUPT_FLAG_PINA13 iflag_pinA13 +#define INTERRUPT_FLAG_PINA14 iflag_pinA14 +#define INTERRUPT_FLAG_PINA15 iflag_pinA15 +#define INTERRUPT_FLAG_PIN70 iflag_pin70 +#define INTERRUPT_FLAG_PIN71 iflag_pin71 +#define INTERRUPT_FLAG_PIN72 iflag_pin72 +#define INTERRUPT_FLAG_PIN73 iflag_pin73 +#define INTERRUPT_FLAG_PIN74 iflag_pin74 +#define INTERRUPT_FLAG_PIN21 iflag_pin21 +#define INTERRUPT_FLAG_PIN20 iflag_pin20 +#define INTERRUPT_FLAG_PIN19 iflag_pin19 +#define INTERRUPT_FLAG_PIN18 iflag_pin18 +#define INTERRUPT_FLAG_PIN2 iflag_pin2 +#define INTERRUPT_FLAG_PIN3 iflag_pin3 +#define INTERRUPT_FLAG_PIN75 iflag_pin75 +#define INTERRUPT_FLAG_PIN76 iflag_pin76 + +#define INTERRUPT_FLAG_PIN18 iflag_pin18 +#define INTERRUPT_FLAG_PIN19 iflag_pin19 +#define INTERRUPT_FLAG_PIN20 iflag_pin20 +#define INTERRUPT_FLAG_PIN21 iflag_pin21 + +#include + +volatile uint8_t externalInterruptCounter=0; +volatile uint8_t anyInterruptCounter=0; + +#ifdef ARDUINO_MEGA +#define PINCOUNT(x) iflag_pin ##x + +#define setupInterrupt(x) \ + EI_printPSTR("Add pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterruptFast(x, CHANGE) + +#define updateOn(x) \ + if (PINCOUNT(x) != 0) { \ + printIt((char *) #x, PINCOUNT(x)); \ + PINCOUNT(x)=0; \ + } + +#else +#error This sketch supports 2560-based Arduinos only. +#endif + +void printIt(char *pinNumber, uint8_t count) { + EI_printPSTR("Pin "); + Serial.print(pinNumber); + EI_printPSTR(" was interrupted: "); + Serial.println(count, DEC); +} + +// Attach the interrupt in setup() +// NOTE: PORTJ2-6 (aka, "Pin '70', '71', '72', '73', '74'" are turned on as OUTPUT. +// These are not true pins on the Arduino Mega series! +void setup() { + Serial.begin(115200); + EI_printPSTR("---------------------------------------"); + // PINS 0 and 1 NOT USED BECAUSE OF Serial.print() + setupInterrupt(SS); + setupInterrupt(SCK); + setupInterrupt(MOSI); + setupInterrupt(MISO); + setupInterrupt(10); + setupInterrupt(11); + setupInterrupt(12); + setupInterrupt(13); + setupInterrupt(14); + setupInterrupt(15); + setupInterrupt(A8); + setupInterrupt(A9); + setupInterrupt(A10); + setupInterrupt(A11); + setupInterrupt(A12); + setupInterrupt(A13); + setupInterrupt(A14); + setupInterrupt(A15); + //// + DDRJ |=0b01111100; // Non-Arduino Port J pins all become output. + PORTJ|=0b01111100; // Turn them all high. + enableInterruptFast(70, CHANGE); + enableInterruptFast(71, CHANGE); + enableInterruptFast(72, CHANGE); + enableInterruptFast(73, CHANGE); + enableInterruptFast(74, CHANGE); + // External Interrupts + setupInterrupt(21); + setupInterrupt(20); + setupInterrupt(19); + setupInterrupt(18); + setupInterrupt(2); + setupInterrupt(3); + //// + DDRE |=0b11000000; // Non-Arduino Port E pins all become output. + PORTE|=0b11000000; // Turn them all high. + enableInterruptFast(75, CHANGE); + enableInterruptFast(76, CHANGE); +} + +uint8_t otherToggle=1; +uint8_t enabledToggle=1; +uint8_t disableCounter=0; +// In the loop, we just check to see where the interrupt count is at. The value gets updated by the +// interrupt routine. +void loop() { + uint8_t jbits =0b01111110; // PJ2 + uint8_t njbits=0b00000001; // PJ2 + uint8_t ebits =0b11000000; // PE6/7 + uint8_t nebits=0b00111111; // PE6/7 + + EI_printPSTR("------\r\n"); + delay(1000); // Every second, + if (disableCounter & 0x08) { + EI_printPSTR("Toggle 20, 71, 75, A8, 15, MISO..."); + delay(1000); + if (enabledToggle==1) { + EI_printPSTR("---OFF---"); + disableInterrupt(20); + disableInterrupt(71); + disableInterrupt(75); + disableInterrupt(15); + disableInterrupt(A8); + disableInterrupt(MISO); + enabledToggle=0; + } + else { + EI_printPSTR("***ON***"); + setupInterrupt(20); + enableInterruptFast(71, CHANGE); + enableInterruptFast(75, CHANGE); + setupInterrupt(15); + setupInterrupt(A8); + setupInterrupt(MISO); + enabledToggle=1; + } + disableCounter=0; + } + PORTE &= nebits; + PORTJ &= njbits; + // *out &= njbits; + delay(1); + PORTE |= ebits; + PORTJ |= jbits; + // *out |= jbits; + delay(1); + updateOn(SS); + updateOn(SCK); + updateOn(MOSI) + updateOn(MISO); + updateOn(10); + updateOn(11); + updateOn(12); + updateOn(13); + updateOn(14); + updateOn(15); + updateOn(A8); + updateOn(A9); + updateOn(A10); + updateOn(A11); + updateOn(A12); + updateOn(A13); + updateOn(A14); + updateOn(A15); + // External Interrupts + updateOn(2); + updateOn(3); + updateOn(18); + updateOn(19); + updateOn(20); + updateOn(21); + // Fake Arduino Pins + updateOn(70); + updateOn(71); + updateOn(72); + updateOn(73); + updateOn(74); + // External Interrupts + updateOn(75); + updateOn(76); + if (externalInterruptCounter > 0) { EI_printPSTR(" ext: "); Serial.println(externalInterruptCounter); }; \ + externalInterruptCounter=0; + disableCounter++; +} diff --git a/libraries/EnableInterrupt/examples/HiSpeedAllPins2560/Makefile b/libraries/EnableInterrupt/examples/HiSpeedAllPins2560/Makefile new file mode 100644 index 0000000..e07adf0 --- /dev/null +++ b/libraries/EnableInterrupt/examples/HiSpeedAllPins2560/Makefile @@ -0,0 +1,13 @@ +# Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +BOARD_TAG = mega +BOARD_SUB = atmega2560 + +ARDUINO_PORT = /dev/ttyACM0 +ARDUINO_LIBS = +AVR_TOOLS_DIR = /usr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +include /usr/share/arduino/Arduino.mk + diff --git a/libraries/EnableInterrupt/examples/HiSpeedAllPins328/HiSpeedAllPins328.ino b/libraries/EnableInterrupt/examples/HiSpeedAllPins328/HiSpeedAllPins328.ino new file mode 100644 index 0000000..575733c --- /dev/null +++ b/libraries/EnableInterrupt/examples/HiSpeedAllPins328/HiSpeedAllPins328.ino @@ -0,0 +1,177 @@ +// EnableInterrupt Simple example sketch +// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information. + +// This example demonstrates the use of the EnableInterrupt library on all pins. +// The library has only been tested on an Arduino Duemilanove and Mega ADK. + +#define NEEDFORSPEED +#define INTERRUPT_FLAG_PIN2 iflag_pin2 +#define INTERRUPT_FLAG_PIN3 iflag_pin3 +#define INTERRUPT_FLAG_PIN4 iflag_pin4 +#define INTERRUPT_FLAG_PIN5 iflag_pin5 +#define INTERRUPT_FLAG_PIN6 iflag_pin6 +#define INTERRUPT_FLAG_PIN7 iflag_pin7 +#define INTERRUPT_FLAG_PIN8 iflag_pin8 +#define INTERRUPT_FLAG_PIN9 iflag_pin9 +#define INTERRUPT_FLAG_PIN10 iflag_pin10 +#define INTERRUPT_FLAG_PIN11 iflag_pin11 +#define INTERRUPT_FLAG_PIN12 iflag_pin12 +#define INTERRUPT_FLAG_PIN13 iflag_pin13 +#define INTERRUPT_FLAG_PINA0 iflag_pinA0 +#define INTERRUPT_FLAG_PINA1 iflag_pinA1 +#define INTERRUPT_FLAG_PINA2 iflag_pinA2 +#define INTERRUPT_FLAG_PINA3 iflag_pinA3 +#define INTERRUPT_FLAG_PINA4 iflag_pinA4 +#define INTERRUPT_FLAG_PINA5 iflag_pinA5 + +#include + +volatile uint8_t anyInterruptCounter=0; + +#ifdef ARDUINO_328 +#define PINCOUNT(x) iflag_pin ##x + +#define updateOn(x) \ + if (PINCOUNT(x) != 0) { \ + printIt((char *) #x, PINCOUNT(x)); \ + PINCOUNT(x)=0; \ + } + +#define disablePCInterrupt(x) \ + disableInterrupt( x | PINCHANGEINTERRUPT) + +#define setupPCInterrupt(x) \ + EI_printPSTR("Add PinChange pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterruptFast( x | PINCHANGEINTERRUPT, CHANGE) + +#define setupInterrupt(x) \ + EI_printPSTR("Add pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterruptFast( x, CHANGE) + +#define setupExInterrupt(x) \ + EI_printPSTR("Add External pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterruptFast( x , CHANGE) + +#else +#error This sketch supports 328-based Arduinos only. +#endif + +void printIt(char *pinNumber, uint8_t count) { + EI_printPSTR(" Pin "); + Serial.print(pinNumber); + EI_printPSTR(" was interrupted: "); + Serial.println(count, DEC); +} + +// Attach the interrupt in setup() +// NOTE: PORTJ2-6 (aka, "Pin '70', '71', '72', '73', '74'" are turned on as OUTPUT. +// These are not true pins on the Arduino Mega series! +void setup() { + Serial.begin(115200); + EI_printPSTR("--- START ------------------------------------\r\n"); +#ifdef DEBUG + pinMode(PINSIGNAL, OUTPUT); +#endif + // PINS 0 and 1 NOT USED BECAUSE OF Serial.print() + setupPCInterrupt(2); // by default, would be External Interrupt + setupExInterrupt(3); + setupInterrupt(4); + setupInterrupt(5); + setupInterrupt(6); + setupInterrupt(7); + setupInterrupt(8); + setupInterrupt(9); + setupInterrupt(10); + setupInterrupt(11); + setupInterrupt(12); +#ifndef DEBUG + // NOTE: Because the Arduino Duemilanove has an LED to ground and a 1k resistor in series with + // it to the pin, Voltage at the pin should be hovering between 1-3 volts. 'nearly' ground. So + // a wire to ground will not trip an interrupt, even though we have INPUT_PULLUP. A wire to PWR + // will trigger an interrupt. The Uno has a op-amp buffer/driver to the LED, so will not have + // this problem; it will behave like the other pins. + setupInterrupt(13); +#endif + setupInterrupt(A0); + setupInterrupt(A1); + setupInterrupt(A2); + setupInterrupt(A3); + setupInterrupt(A4); + setupInterrupt(A5); +} + +uint8_t externalFlag=1; +uint8_t enabledToggle=1; +uint8_t disableCounter=0; +// In the loop, we just check to see where the interrupt count is at. The value gets updated by +// the interrupt routine. +void loop() { + EI_printPSTR("------\r\n"); + delay(1000); // Perform the loop every second. + if (disableCounter & 0x08) { + EI_printPSTR("Toggle 2, 3, 4, 8, A0..."); + delay(1000); + if (enabledToggle==1) { + EI_printPSTR(" off\r\n"); + disablePCInterrupt(2); + if (externalFlag == 1) { + EI_printPSTR("Disable pin 3 external interrupt\r\n"); + disableInterrupt(3); + } + else { + EI_printPSTR("Disable pin 3 pin change interrupt\r\n"); + disablePCInterrupt(3); + } + disableInterrupt(4); + disableInterrupt(8); + disableInterrupt(A0); + enabledToggle=0; + } + else { + if (externalFlag == 1) { + EI_printPSTR("3 is now a Pin Change Interrupt.\r\n"); + setupPCInterrupt(3); // make sure we can switch functions. + externalFlag=0; + } else { + EI_printPSTR("3 is now an External Interrupt.\r\n"); + setupExInterrupt(3); + externalFlag=1; + } + setupPCInterrupt(2); + setupInterrupt(4); + setupInterrupt(8); + setupInterrupt(A0); + enabledToggle=1; + } + disableCounter=0; + } + updateOn(2); + updateOn(3); + updateOn(4); + updateOn(5); + updateOn(6); + updateOn(7); + updateOn(8); + updateOn(9); + updateOn(10); + updateOn(11); + updateOn(12); + updateOn(13); + updateOn(A0); + updateOn(A1); + updateOn(A2); + updateOn(A3); + updateOn(A4); + updateOn(A5); + disableCounter++; +} + diff --git a/libraries/EnableInterrupt/examples/HiSpeedAllPins328/Makefile b/libraries/EnableInterrupt/examples/HiSpeedAllPins328/Makefile new file mode 100644 index 0000000..b10e505 --- /dev/null +++ b/libraries/EnableInterrupt/examples/HiSpeedAllPins328/Makefile @@ -0,0 +1,14 @@ +# Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +BOARD_TAG = pro +BOARD_SUB = 16MHzatmega328 +ARDUINO_PORT = /dev/ttyUSB0 +#BOARD_TAG = 2560 +#ARDUINO_PORT = /dev/ttyACM0 +ARDUINO_LIBS = +AVR_TOOLS_DIR = /usr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +include /usr/share/arduino/Arduino.mk + diff --git a/libraries/EnableInterrupt/examples/HiSpeedTest/HiSpeedTest.ino b/libraries/EnableInterrupt/examples/HiSpeedTest/HiSpeedTest.ino new file mode 100644 index 0000000..76f40e7 --- /dev/null +++ b/libraries/EnableInterrupt/examples/HiSpeedTest/HiSpeedTest.ino @@ -0,0 +1,103 @@ +// EnableInterrupt Simple example sketch +// See https://github.com/GreyGnome/EnableInterrupt and the README.md for more information. +// +// https://github.com/GreyGnome/EnableInterrupt/wiki/Usage#Summary + +//#define OLDLIBRARY + +#define NEEDFORSPEED + +#define USEINTERRUPTPIN8 // PORTB +// Define the above, and undefine this for External Interrupt measurements. +//#define USEINTERRUPTPIN2 + +#if defined USEINTERRUPTPIN8 +#define PININTERRUPT 8 +#define PININTERRUPT_ON PORTB |= (1 << PB0) +#define PININTERRUPT_OFF PORTB &= ~(1 << PB0) +#define THEINTERRUPTVARIABLE myvariable_pin8 +//#define EI_NOTPORTD // will not produce __vector_5 code +#ifdef NEEDFORSPEED +#define INTERRUPT_FLAG_PIN8 myvariable_pin8 // NOTICE: NO semicolon!!! This needs to track the PININTERRUPT pin +#else +#define EI_NOTPORTB +volatile uint8_t myvariable_pin8=0; +#endif +#endif + +#if defined USEINTERRUPTPIN2 // PORTD +#define PININTERRUPT 2 +#define PININTERRUPT_ON PORTD |= (1 << PD2) +#define PININTERRUPT_OFF PORTD &= ~(1 << PD2) +#define THEINTERRUPTVARIABLE myvariable_pin2 +#ifdef NEEDFORSPEED +#define INTERRUPT_FLAG_PIN2 myvariable_pin2 // NOTICE: NO semicolon!!! This needs to track the PININTERRUPT pin +#else +volatile uint8_t myvariable_pin2=0; +#endif +#endif + + +#ifdef OLDLIBRARY +#include +#define EI_printPSTR(x) SerialPrint_P(PSTR(x)) +void SerialPrint_P(const char *str) { + for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c); +} +#else +#include +#endif +#include + +void incrementMyVariable() { // This isn't used or compiled if NEEDFORSPEED is defined. + THEINTERRUPTVARIABLE++; +} + +// Attach the interrupt in setup() +void setup() { + //uint8_t pind, pink; + Serial.begin(115200); + EI_printPSTR("---------------------------------------\r\n"); + pinMode(PININTERRUPT, OUTPUT); // Configure the pin as an output + PININTERRUPT_OFF; +#ifdef OLDLIBRARY + attachPinChangeInterrupt(PININTERRUPT, incrementMyVariable, CHANGE); +#else +#ifdef NEEDFORSPEED + enableInterruptFast(PININTERRUPT, CHANGE); +#else + enableInterrupt(PININTERRUPT, incrementMyVariable, CHANGE); +#endif +#endif + EI_printPSTR("Interrupt enabled, let's go!\r\n"); + EI_printPSTR("Make sure nothing is connected to pin "); + Serial.println(PININTERRUPT, DEC); + EI_printPSTR("This sketch sends a software interrupt to that pin.\r\n"); +} + +// In the loop, we just check to see where the interrupt count is at. The value gets updated by the +// interrupt routine. +void loop() { + + EI_printPSTR("---------------------------------------\r\n"); + delay(1000); // Every second, + PININTERRUPT_ON; // software interrupt + _NOP(); // See "8-bit AVR Microcontroller with 4/8/16/32K Bytes In-System Programmable + _NOP(); // Flash" document, Rev. 8271C-AVR-08/10, p. 71. + _NOP(); // The interrupt signal must be held until PCIFR is changed, in order for the +#if defined USEINTERRUPTPIN8 + _NOP(); // CPU to execute the ISR. This requires 4 nop assembler instructions. +#else + // (three nop's for an External Interrupt) +#endif + PININTERRUPT_OFF; // ...This is after the interrupt. + if (THEINTERRUPTVARIABLE > 0) { + EI_printPSTR("Pin was interrupted: "); + Serial.print(THEINTERRUPTVARIABLE, DEC); // print the interrupt count. + EI_printPSTR(" times this iteration.\r\n"); + THEINTERRUPTVARIABLE=0; + } + else { + EI_printPSTR("No interrupts.\r\n"); + } +} diff --git a/libraries/EnableInterrupt/examples/HiSpeedTest/Makefile b/libraries/EnableInterrupt/examples/HiSpeedTest/Makefile new file mode 100644 index 0000000..09c1bd6 --- /dev/null +++ b/libraries/EnableInterrupt/examples/HiSpeedTest/Makefile @@ -0,0 +1,13 @@ +# Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +BOARD_TAG = atmega328 +ARDUINO_PORT = /dev/ttyUSB0 +#BOARD_TAG = 2560 +#ARDUINO_PORT = /dev/ttyACM0 +ARDUINO_LIBS = +AVR_TOOLS_DIR = /usr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +include /usr/share/arduino/Arduino.mk + diff --git a/libraries/EnableInterrupt/examples/InterruptedPin2560/InterruptedPin2560.ino b/libraries/EnableInterrupt/examples/InterruptedPin2560/InterruptedPin2560.ino new file mode 100644 index 0000000..519f4bf --- /dev/null +++ b/libraries/EnableInterrupt/examples/InterruptedPin2560/InterruptedPin2560.ino @@ -0,0 +1,214 @@ +// EnableInterrupt example sketch +// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information. + +// This example demonstrates the use of the EnableInterrupt library on all pins. +// It tests the EI_ARDUINO_INTERRUPTED_PIN facility. +// The library has only been tested on an Arduino Duemilanove and Mega ADK. + +#define EI_ARDUINO_INTERRUPTED_PIN +#include + +volatile uint8_t externalInterruptFlag=0; +volatile uint8_t pinChangeInterruptFlag=0; +volatile uint8_t pin70Flag=0; + +#ifdef ARDUINO_MEGA + +void interruptFunctionPin70 () { + pinChangeInterruptFlag=arduinoInterruptedPin; + pin70Flag++; +} + +void interruptFunction () { + pinChangeInterruptFlag=arduinoInterruptedPin; +} + +void interruptExFunction () { + externalInterruptFlag=arduinoInterruptedPin; +} + +#define disablePCInterrupt(x) \ + disableInterrupt( x | PINCHANGEINTERRUPT) + +#define setupPCInterrupt(x) \ + EI_printPSTR("Add PinChange pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x | PINCHANGEINTERRUPT, interruptFunction, CHANGE) + +#define setupInterrupt(x) \ + EI_printPSTR("Add pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x, interruptFunction, CHANGE) + +#define setupExInterrupt(x) \ + EI_printPSTR("Add External pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x , interruptExFunction, CHANGE) +#else +#error This sketch supports 328-based Arduinos only. +#endif + +void printIt(char *pinNumber, uint8_t count) { + EI_printPSTR(" Pin "); + Serial.print(pinNumber); + EI_printPSTR(" was interrupted: "); + Serial.println(count, DEC); +} + +#define PIN70_PORTBITMAP 0b00000100 +#define PIN71_PORTBITMAP 0b00001000 +#define PIN72_PORTBITMAP 0b00010000 +#define PIN73_PORTBITMAP 0b00100000 +#define PIN74_PORTBITMAP 0b01000000 + +#define PIN75_PORTBITMAP 0b01000000 +#define PIN76_PORTBITMAP 0b10000000 +// Attach the interrupt in setup() +// NOTE: PORTJ2-6 (aka, "Pin '70', '71', '72', '73', '74'" are turned on as OUTPUT. +// These are not true pins on the Arduino Mega series! +void setup() { + Serial.begin(115200); + EI_printPSTR("--- START ------------------------------------\r\n"); + setupInterrupt(SS); + setupInterrupt(SCK); + setupInterrupt(MOSI); + setupInterrupt(MISO); + setupInterrupt(10); + setupInterrupt(11); + setupInterrupt(12); + setupInterrupt(13); + setupInterrupt(14); + setupInterrupt(15); + setupInterrupt(A8); + setupInterrupt(A9); + setupInterrupt(A10); + setupInterrupt(A11); + setupInterrupt(A12); + setupInterrupt(A13); + setupInterrupt(A14); + setupInterrupt(A15); + //// 0b01111100 + // MIKE- Why turn them all high? I think they should be 0! + DDRJ |= PIN70_PORTBITMAP | PIN71_PORTBITMAP | PIN72_PORTBITMAP + | PIN73_PORTBITMAP | PIN74_PORTBITMAP ; // Non-Arduino Port J pins all become output. + PORTJ &= ~(PIN70_PORTBITMAP | PIN71_PORTBITMAP | PIN72_PORTBITMAP + | PIN73_PORTBITMAP | PIN74_PORTBITMAP) ; // Turn them all low. + //// 0b11000000 + DDRE |= PIN75_PORTBITMAP | PIN76_PORTBITMAP; // Non-Arduino Port E pins all become output. + PORTE &= ~(PIN75_PORTBITMAP | PIN76_PORTBITMAP); // Turn them all low. + // MIKE- replace this if necessary: enableInterrupt(70, interruptFunctionPin70, CHANGE); + enableInterrupt(70, interruptFunction, CHANGE); + enableInterrupt(71, interruptFunction, CHANGE); + enableInterrupt(72, interruptFunction, CHANGE); + enableInterrupt(73, interruptFunction, CHANGE); + enableInterrupt(74, interruptFunction, CHANGE); + // External Interrupts + setupExInterrupt(21); + setupExInterrupt(20); + setupExInterrupt(19); + setupExInterrupt(18); + setupExInterrupt(2); + setupExInterrupt(3); + enableInterrupt(75, interruptExFunction, CHANGE); + enableInterrupt(76, interruptExFunction, CHANGE); +} + +#define IS_PINCHANGE 0 +#define IS_EXTERNAL 1 +#define FLIP 0 +#define FLOP 1 +uint8_t pin3state=IS_PINCHANGE; +uint8_t enabledToggle=FLOP; +uint8_t toggleCounter=0; +uint16_t loopCounter=0; +uint8_t portj_follower = PIN70_PORTBITMAP; +uint8_t porte_follower = PIN75_PORTBITMAP; +uint8_t current_pin_state = 0; +// In the loop, we just check to see where the interrupt count is at. The value gets updated by +// the interrupt routine. +void loop() { + + /* + if (toggleCounter & 0x80) { + EI_printPSTR("Toggle 20, 71, 75, A8, 15, MISO..."); + delay(200); + if (enabledToggle==FLOP) { + disableInterrupt(20); + disableInterrupt(71); + disableInterrupt(75); + disableInterrupt(15); + disableInterrupt(A8); + disableInterrupt(MISO); + enabledToggle=FLIP; + } + else { + EI_printPSTR("***ON***"); + setupExInterrupt(20); + setupInterrupt(71); + setupExInterrupt(75); + setupInterrupt(15); + setupInterrupt(A8); + setupInterrupt(MISO); + enabledToggle=FLOP; + } + toggleCounter=0; + }*/ + loopCounter++; + // Starting positions: + // portjfollower 00000100 PORTJ 00000000 // Keep track of port j + // portefollower 00000000 PORTE 00000000 // Keep track of port e + // current_pin_state 0 // track the state of the current pin + if (loopCounter == 0x3FFF) { + if (portj_follower <= PIN74_PORTBITMAP) { + EI_printPSTR("Interrupt fake pins..."); + // If the pin is on, turn it off, and go to the next pin + if (current_pin_state) { + PORTJ ^= portj_follower; // turn it off + portj_follower <<= 1; + current_pin_state=0; + } else { + // if the pin is off, turn it on + PORTJ ^= portj_follower; // turn it on + current_pin_state=1; + } + delay(1); // run a few instructions after triggering the interrupt. + } else if (porte_follower >= PIN75_PORTBITMAP) { + EI_printPSTR("Interrupt fake pins..."); + if (current_pin_state) { + PORTE ^= porte_follower; // turn it off + porte_follower <<= 1; + current_pin_state=0; + } else { + PORTE ^= porte_follower; // turn it on + current_pin_state=1; + } + delay(1); // run a few instructions after triggering the interrupt. + } else { + portj_follower=PIN70_PORTBITMAP; + porte_follower=PIN75_PORTBITMAP; + } + loopCounter=0; + } + if (pinChangeInterruptFlag) { + //EI_printPSTR("Pin Change interrupt, pin "); Serial.println(arduinoInterruptedPin); + EI_printPSTR("pci: "); Serial.println(pinChangeInterruptFlag); + EI_printPSTR(", state: "); Serial.println(arduinoPinState); + arduinoInterruptedPin=0; + pinChangeInterruptFlag=0; + toggleCounter++; + } + if (externalInterruptFlag) { + //EI_printPSTR("External interrupt, pin "); Serial.println(arduinoInterruptedPin); + EI_printPSTR("ext: "); Serial.println(externalInterruptFlag); + EI_printPSTR(", state: "); Serial.println(arduinoPinState); + arduinoInterruptedPin=0; + externalInterruptFlag=0; + toggleCounter++; + } +} diff --git a/libraries/EnableInterrupt/examples/InterruptedPin2560/Makefile b/libraries/EnableInterrupt/examples/InterruptedPin2560/Makefile new file mode 100644 index 0000000..62911ca --- /dev/null +++ b/libraries/EnableInterrupt/examples/InterruptedPin2560/Makefile @@ -0,0 +1,14 @@ +# Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +#BOARD_TAG = atmega328 +#ARDUINO_PORT = /dev/ttyUSB0 +BOARD_TAG = mega +BOARD_SUB = atmega2560 +ARDUINO_PORT = /dev/ttyACM0 +ARDUINO_LIBS = +AVR_TOOLS_DIR = /usr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +include /usr/share/arduino/Arduino.mk + diff --git a/libraries/EnableInterrupt/examples/InterruptedPin328/InterruptedPin328.ino b/libraries/EnableInterrupt/examples/InterruptedPin328/InterruptedPin328.ino new file mode 100644 index 0000000..996bf46 --- /dev/null +++ b/libraries/EnableInterrupt/examples/InterruptedPin328/InterruptedPin328.ino @@ -0,0 +1,154 @@ +// EnableInterrupt example sketch +// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information. + +// This example demonstrates the use of the EnableInterrupt library on all pins. +// It tests the EI_ARDUINO_INTERRUPTED_PIN facility. +// The library has only been tested on an Arduino Duemilanove and Mega ADK. + +#define EI_ARDUINO_INTERRUPTED_PIN +#include + +volatile uint8_t externalInterruptFlag=0; +volatile uint8_t pinChangeInterruptFlag=0; +volatile uint8_t pinState=0; + +#ifdef ARDUINO_328 +#define PINCOUNT(x) pin ##x ##Count + +void interruptFunction () { + pinChangeInterruptFlag=arduinoInterruptedPin; + pinState=arduinoPinState; +} + +void interruptExFunction () { + externalInterruptFlag=arduinoInterruptedPin; + pinState=arduinoPinState; +} + +#define disablePCInterrupt(x) \ + disableInterrupt( x | PINCHANGEINTERRUPT) + +#define setupPCInterrupt(x) \ + EI_printPSTR("Add PinChange pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x | PINCHANGEINTERRUPT, interruptFunction, CHANGE) + +#define setupInterrupt(x) \ + EI_printPSTR("Add pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x, interruptFunction, CHANGE) + +#define setupExInterrupt(x) \ + EI_printPSTR("Add External pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x , interruptExFunction, CHANGE) +#else +#error This sketch supports 328-based Arduinos only. +#endif + +void printIt(char *pinNumber, uint8_t count) { + EI_printPSTR(" Pin "); + Serial.print(pinNumber); + EI_printPSTR(" was interrupted: "); + Serial.println(count, DEC); +} + +// Attach the interrupt in setup() +// NOTE: PORTJ2-6 (aka, "Pin '70', '71', '72', '73', '74'" are turned on as OUTPUT. +// These are not true pins on the Arduino Mega series! +void setup() { + Serial.begin(115200); + EI_printPSTR("--- START ------------------------------------\r\n"); +#ifdef DEBUG + pinMode(PINSIGNAL, OUTPUT); +#endif + // PINS 0 and 1 NOT USED BECAUSE OF Serial.print() + setupPCInterrupt(2); // by default, would be External Interrupt + setupExInterrupt(3); + setupInterrupt(4); + setupInterrupt(5); + setupInterrupt(6); + setupInterrupt(7); + setupInterrupt(8); + setupInterrupt(9); + setupInterrupt(10); + setupInterrupt(11); + setupInterrupt(12); +#ifndef DEBUG + // NOTE: Because the Arduino Duemilanove has an LED to ground and a 1k resistor in series with + // it to the pin, Voltage at the pin should be hovering between 1-3 volts. 'nearly' ground. So + // a wire to ground will not trip an interrupt, even though we have INPUT_PULLUP. A wire to PWR + // will trigger an interrupt. The Uno has an op-amp buffer/driver to the LED, so will not have + // this problem; it will behave like the other pins. + setupInterrupt(13); +#endif + setupInterrupt(A0); + setupInterrupt(A1); + setupInterrupt(A2); + setupInterrupt(A3); + setupInterrupt(A4); + setupInterrupt(A5); +} + +#define IS_PINCHANGE 0 +#define IS_EXTERNAL 1 +#define FLIP 0 +#define FLOP 1 +uint8_t pin3state=IS_PINCHANGE; +uint8_t enabledToggle=FLOP; +uint8_t toggleCounter=0; +// In the loop, we just check to see where the interrupt count is at. The value gets updated by +// the interrupt routine. +void loop() { + if (toggleCounter & 0x10) { + EI_printPSTR("Toggle 2, 3, 8, A0..."); + delay(200); + if (enabledToggle==FLOP) { + if (pin3state==IS_PINCHANGE) + disablePCInterrupt(3); + else + disableInterrupt(3); + disablePCInterrupt(2); + disableInterrupt(8); + disableInterrupt(A0); + enabledToggle=FLIP; + } + else { + EI_printPSTR("3 is now a"); + if (pin3state == IS_PINCHANGE) { + setupExInterrupt(3); + EI_printPSTR("n external interrupt.\r\n"); + pin3state=IS_EXTERNAL; + } else { + setupExInterrupt(3); + EI_printPSTR(" pin change interrupt.\r\n"); + pin3state=IS_PINCHANGE; + } + setupPCInterrupt(2); + setupInterrupt(8); + setupInterrupt(A0); + enabledToggle=FLOP; + } + toggleCounter=0; + } + // Bug: 0 is not (technically) a proper test because (technically) we have Arduino pin 0. + // But we don't support pin 0 in this sketch (it's used for Serial print). + if (pinChangeInterruptFlag) { + EI_printPSTR("Pin Change interrupt, pin "); Serial.println(pinChangeInterruptFlag); + pinChangeInterruptFlag=0; + EI_printPSTR(", pin state: "); Serial.println(pinState); + toggleCounter++; + } + if (externalInterruptFlag) { + EI_printPSTR("External interrupt, pin "); Serial.println(externalInterruptFlag); + externalInterruptFlag=0; + EI_printPSTR(", pin state: "); Serial.println(pinState); + toggleCounter++; + } +} diff --git a/libraries/EnableInterrupt/examples/InterruptedPin328/Makefile b/libraries/EnableInterrupt/examples/InterruptedPin328/Makefile new file mode 100644 index 0000000..b10e505 --- /dev/null +++ b/libraries/EnableInterrupt/examples/InterruptedPin328/Makefile @@ -0,0 +1,14 @@ +# Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +BOARD_TAG = pro +BOARD_SUB = 16MHzatmega328 +ARDUINO_PORT = /dev/ttyUSB0 +#BOARD_TAG = 2560 +#ARDUINO_PORT = /dev/ttyACM0 +ARDUINO_LIBS = +AVR_TOOLS_DIR = /usr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +include /usr/share/arduino/Arduino.mk + diff --git a/libraries/EnableInterrupt/examples/Mighty1284p/Mighty1284p.ino b/libraries/EnableInterrupt/examples/Mighty1284p/Mighty1284p.ino new file mode 100644 index 0000000..92fe156 --- /dev/null +++ b/libraries/EnableInterrupt/examples/Mighty1284p/Mighty1284p.ino @@ -0,0 +1,204 @@ +// EnableInterrupt Simple example sketch for the ATmega 644/1284 series of chips. +// Note that this sketch is kind of silly, because it uses printf's which depend on +// Arduino's USB-serial converters that don't come with a naked 1284, naturally. +// This sketch is merely to ensure a proper compile. + +// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information. + +// This example demonstrates the use of the EnableInterrupt library on all pins. +// The library has only been tested on an Arduino Duemilanove and Mega ADK. + +#include + +volatile uint8_t externalInterruptCounter=0; +volatile uint8_t anyInterruptCounter=0; + +#ifdef MIGHTY1284 +#define PINCOUNT(x) pin ##x ##Count + +// Do not use any Serial.print() in interrupt subroutines. Serial.print() uses interrupts, +// and by default interrupts are off in interrupt subroutines. Interrupt routines should also +// be as fast as possible. Here we just increment counters. +#define interruptFunction(x) \ + volatile uint8_t PINCOUNT(x); \ + void interruptFunction ##x () { \ + anyInterruptCounter++; \ + PINCOUNT(x)++; \ + } + +#define interruptExFunction(x) \ + volatile uint8_t PINCOUNT(x); \ + void interruptExFunction ##x () { \ + externalInterruptCounter++; \ + anyInterruptCounter++; \ + PINCOUNT(x)++; \ + } + +#define updateOn(x) \ + if (PINCOUNT(x) != 0) { \ + printIt((char *) #x, PINCOUNT(x)); \ + if (externalInterruptCounter > 0) { \ + EI_printPSTR(" ext: "); Serial.println(externalInterruptCounter); \ + externalInterruptCounter=0; \ + }; \ + PINCOUNT(x)=0; \ + } + +#define disablePCInterrupt(x) \ + disableInterrupt( x | PINCHANGEINTERRUPT) + +#define setupPCInterrupt(x) \ + EI_printPSTR("Add PinChange pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x | PINCHANGEINTERRUPT, interruptFunction##x, CHANGE) + +#define setupInterrupt(x) \ + EI_printPSTR("Add pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x, interruptFunction##x, CHANGE) + +#define setupExInterrupt(x) \ + EI_printPSTR("Add External pin: "); \ + EI_printPSTR(#x); \ + EI_printPSTR("\r\n"); \ + pinMode( x, INPUT_PULLUP); \ + enableInterrupt( x , interruptExFunction##x, CHANGE) + +interruptFunction(2); +interruptExFunction(3); +interruptFunction(4); +interruptFunction(5); +interruptFunction(6); +interruptFunction(7); +interruptFunction(8); +interruptFunction(9); +interruptFunction(10); +interruptFunction(11); +interruptFunction(12); +interruptFunction(13); +interruptFunction(A0); +interruptFunction(A1); +interruptFunction(A2); +interruptFunction(A3); +interruptFunction(A4); +interruptFunction(A5); + +volatile uint8_t otherCounter=0; +void otherInterrupt3Function(void) { // Must appear after interruptFunction(3) + pin3Count++; + otherCounter++; +} +#else +#error This sketch supports 1284p-based Arduino-likes only. +#endif + +void printIt(char *pinNumber, uint8_t count) { + EI_printPSTR(" Pin "); + Serial.print(pinNumber); + EI_printPSTR(" was interrupted: "); + Serial.println(count, DEC); +} + +// Attach the interrupt in setup() +// NOTE: PORTJ2-6 (aka, "Pin '70', '71', '72', '73', '74'" are turned on as OUTPUT. +// These are not true pins on the Arduino Mega series! +void setup() { + Serial.begin(115200); + EI_printPSTR("--- START ------------------------------------\r\n"); +#ifdef DEBUG + pinMode(PINSIGNAL, OUTPUT); +#endif + // PINS 0 and 1 NOT USED BECAUSE OF Serial.print() + setupPCInterrupt(2); // by default, will be External Interrupt + setupExInterrupt(3); + setupInterrupt(4); + setupInterrupt(5); + setupInterrupt(6); + setupInterrupt(7); + setupInterrupt(8); + setupInterrupt(9); + setupInterrupt(10); + setupInterrupt(11); + setupInterrupt(12); +#ifndef DEBUG + // NOTE: Because the Arduino Duemilanove has an LED to ground and a 1k resistor in series with + // it to the pin, Voltage at the pin should be hovering between 1-3 volts. 'nearly' ground. So + // a wire to ground will not trip an interrupt, even though we have INPUT_PULLUP. A wire to PWR + // will trigger an interrupt. The Uno has a op-amp buffer/driver to the LED, so will not have + // this problem; it will behave like the other pins. + setupInterrupt(13); +#endif + setupInterrupt(A0); + setupInterrupt(A1); + setupInterrupt(A2); + setupInterrupt(A3); + setupInterrupt(A4); + setupInterrupt(A5); +} + +uint8_t otherToggle=1; +uint8_t enabledToggle=1; +uint8_t disableCounter=0; +// In the loop, we just check to see where the interrupt count is at. The value gets updated by +// the interrupt routine. +void loop() { + EI_printPSTR("------\r\n"); + delay(1000); // Perform the loop every second. + if (disableCounter & 0x08) { + EI_printPSTR("Toggle 2, 3, 8, A0..."); + delay(1000); + if (enabledToggle==1) { + disablePCInterrupt(2); + disableInterrupt(3); + disableInterrupt(8); + disableInterrupt(A0); + enabledToggle=0; + } + else { + if (otherToggle == 1) { + EI_printPSTR("3 is now a Pin Change Interrupt.\r\n"); + enableInterrupt(3, otherInterrupt3Function, CHANGE); // make sure we can switch functions. + otherToggle=0; + } else { + EI_printPSTR("3 is now an External Interrupt.\r\n"); + otherToggle=1; + setupExInterrupt(3); + } + setupPCInterrupt(2); + setupInterrupt(8); + setupInterrupt(A0); + enabledToggle=1; + } + disableCounter=0; + } + updateOn(2); + updateOn(3); + updateOn(4); + updateOn(5); + updateOn(6); + updateOn(7); + updateOn(8); + updateOn(9); + updateOn(10); + updateOn(11); + updateOn(12); + updateOn(13); + updateOn(A0); + updateOn(A1); + updateOn(A2); + updateOn(A3); + updateOn(A4); + updateOn(A5); + EI_printPSTR("Consolidated interrupt count: "); Serial.println(anyInterruptCounter); + if (otherCounter) { + printIt((char *) "OTHER3", otherCounter); + otherCounter=0; + } + externalInterruptCounter=0; + disableCounter++; +} + diff --git a/libraries/EnableInterrupt/examples/OOSimple/Makefile b/libraries/EnableInterrupt/examples/OOSimple/Makefile new file mode 100644 index 0000000..b10e505 --- /dev/null +++ b/libraries/EnableInterrupt/examples/OOSimple/Makefile @@ -0,0 +1,14 @@ +# Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +BOARD_TAG = pro +BOARD_SUB = 16MHzatmega328 +ARDUINO_PORT = /dev/ttyUSB0 +#BOARD_TAG = 2560 +#ARDUINO_PORT = /dev/ttyACM0 +ARDUINO_LIBS = +AVR_TOOLS_DIR = /usr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +include /usr/share/arduino/Arduino.mk + diff --git a/libraries/EnableInterrupt/examples/OOSimple/OOSimple.ino b/libraries/EnableInterrupt/examples/OOSimple/OOSimple.ino new file mode 100644 index 0000000..3d7e4d7 --- /dev/null +++ b/libraries/EnableInterrupt/examples/OOSimple/OOSimple.ino @@ -0,0 +1,129 @@ +// EnableInterrupt OOSimple object-oriented example sketch. +// See https://github.com/GreyGnome/EnableInterrupt and the README.md for more information. + +#include + +// Modify this at your leisure. See https://github.com/GreyGnome/EnableInterrupt/wiki/Usage#Summary +#define ARDUINOPIN 8 + +class Simple { + + public: + Simple() { + init(); + } + void updateSimpleVariable(); + uint8_t getSimpleVariable(); + + private: + volatile uint8_t _sv; // a simple variable. Notice that it is volatile. + void init(); +}; + +void Simple::init() { + _sv=0; +} +void Simple::updateSimpleVariable() { + _sv++; +} + +uint8_t Simple::getSimpleVariable() { + return _sv; +} + +#ifdef __cplusplus +extern "C" { +#endif +void *createSimple() { + return new Simple(); +} +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +extern "C" { +#endif +uint8_t getSimpleVariable(void *anObject) { + return static_cast(anObject)->getSimpleVariable(); +} +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +extern "C" { +#endif +void updateSimpleVariable(void *anObject) { + static_cast(anObject)->updateSimpleVariable(); +} +#ifdef __cplusplus +} +#endif + +void *simpleObject0; // this is numbered 0. You can create more, for example void *simpleObject1 + +#ifdef __cplusplus +extern "C" { +#endif +// If you create more objects, you need to create more interruptFunctionN()'s +// that update their simple variables, for example interruptFunction1() . +void interruptFunction0() { + updateSimpleVariable(simpleObject0); +} +#ifdef __cplusplus +} +#endif + +// Attach the interrupt in setup() +void setup() { + Serial.begin(115200); + Serial.println("---------------------------------------"); + + // If you want to enable more pins, you will need to recreate these 3 lines for + // your new pin, object, and function. + pinMode(ARDUINOPIN, INPUT_PULLUP); // See http://arduino.cc/en/Tutorial/DigitalPins + simpleObject0 = createSimple(); + enableInterrupt(ARDUINOPIN, interruptFunction0, CHANGE); +} + +// In the loop, we just print our object's simple variable. It is updated by the interrupt routine. +void loop() { + Serial.println("---------------------------------------"); + delay(1000); // Every second, + Serial.print("Pin was interrupted: "); + Serial.print(getSimpleVariable(simpleObject0), DEC); // print the interrupt count. + Serial.println(" times so far."); +} + +////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////// GORY DETAILS ////////////////////////////////////// +// This example demonstrates the use of the EnableInterrupt library on a single pin of your choice. +// It demonstrates calling an object's method from an interrupt. Other objects can be created and called +// by simply and creating more simpleObjectN's adding more interruptFunctionN()'s. +// +// This has only been tested on an Arduino Duemilanove and Mega ADK. +// It is designed to work with the Arduino Duemilanove/Uno, Arduino Mega2560/ADK, the Arduino +// Leonardo, and the Arduino Due. Please let me know how you fare on the Leonardo or Due. + +// To use: + +// 1. You must be using a fairly recent version of the Arduino IDE software on your PC/Mac, +// that is, version 1.0.1 or later. Check Help->About Arduino in the IDE. + +// 2. Wire a simple switch to any Analog or Digital pin (known as ARDUINOPIN, defined below) +// that supports interrupts. See https://github.com/GreyGnome/EnableInterrupt/wiki/Usage#Summary +// Attach the other end to a GND pin. A "single pole single throw momentary contact normally +// open" // pushbutton switch is best for the most interrupting fun. +// See https://www.sparkfun.com/products/97 and https://octopart.com/b3f-1000-omron-3117 + +// 3. When pressed, the switch will connect the pin to ground ("low", or "0") voltage, and interrupt the +// processor. See http://arduino.cc/en/Tutorial/DigitalPins + +// 4. The interrupt is serviced immediately, and the ISR (Interrupt SubRoutine) sets the value of a global +// variable. Open Tools->Serial Monitor in the IDE to see the results of your interrupts. + +// 5. Peruse the Examples directory for more elaborate examples. + +// 6. Create your own sketch using the EnableInterrupt library! + diff --git a/libraries/EnableInterrupt/examples/Simple/Makefile b/libraries/EnableInterrupt/examples/Simple/Makefile new file mode 100644 index 0000000..2b52e18 --- /dev/null +++ b/libraries/EnableInterrupt/examples/Simple/Makefile @@ -0,0 +1,39 @@ +## Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +#ARDUINO_DIR = /home/schwager/bin/arduino-1.6.8 +ARDUINO_DIR = /home/schwager/bin/arduino-1.8.5 +#ARDMK_DIR = /home/schwager/Projects/Arduino/libraries/EnableInterrupt/examples/Simple +ARDMK_DIR = /usr/share/arduino +#AVR_TOOLS_DIR = /home/schwager/bin/arduino-1.6.8/hardware/tools/avr +AVR_TOOLS_DIR = /home/schwager/bin/arduino-1.8.5/hardware/tools/avr + +BOARD_TAG = pro +BOARD_SUB = 16MHzatmega328 +ARDUINO_PORT = /dev/ttyUSB0 +##BOARD_TAG = 2560 +##ARDUINO_PORT = /dev/ttyACM0 +#ARDUINO_LIBS = +#AVR_TOOLS_DIR = /usr +# +#CFLAGS_STD = -g +#CXXFLAGS_STD = -g +# +#include /usr/share/arduino/Arduino.mk + +######################################################################## +## Arduino Make file. Refer to https://github.com/sudar/Arduino-Makefile +# + +#ARDUINO_DIR = /home/schwager/bin/arduino-1.6.4 +#BOARD_SUB = atmega1284p +#CFLAGS_STD = -g -I /home/schwager/sketchbook/hardware/mighty-1284p-master/variants/standard +#CXXFLAGS_STD = -g -I /home/schwager/sketchbook/hardware/mighty-1284p-master/variants/standard +# + +#ISP_PROG = usbasp +# from boards.txt +#BOARD_TAG = mighty_opt +#ALTERNATE_CORE = mighty-1284p-master +# This is set in the boards.txt file. +#F_CPU = 16000000L + +include /usr/share/arduino/Arduino.mk diff --git a/libraries/EnableInterrupt/examples/Simple/Makefile-usbasp b/libraries/EnableInterrupt/examples/Simple/Makefile-usbasp new file mode 100644 index 0000000..4e964eb --- /dev/null +++ b/libraries/EnableInterrupt/examples/Simple/Makefile-usbasp @@ -0,0 +1,31 @@ +## Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +#BOARD_TAG = atmega328 +#ARDUINO_PORT = /dev/ttyUSB0 +##BOARD_TAG = 2560 +##ARDUINO_PORT = /dev/ttyACM0 +#ARDUINO_LIBS = +#AVR_TOOLS_DIR = /usr +# +#CFLAGS_STD = -g +#CXXFLAGS_STD = -g +# +#include /usr/share/arduino/Arduino.mk + +######################################################################## +## Arduino Make file. Refer to https://github.com/sudar/Arduino-Makefile +# + +ARDUINO_DIR = /home/schwager/bin/arduino-1.8.4 +BOARD_SUB = atmega1284p +CFLAGS_STD = -g -I /home/schwager/sketchbook/hardware/mighty-1284p-master/variants/standard +CXXFLAGS_STD = -g -I /home/schwager/sketchbook/hardware/mighty-1284p-master/variants/standard +# + +ISP_PROG = usbasp +# from boards.txt +BOARD_TAG = mighty_opt +ALTERNATE_CORE = mighty-1284p-master +# This is set in the boards.txt file. +#F_CPU = 16000000L + +include /usr/share/arduino/Arduino.mk diff --git a/libraries/EnableInterrupt/examples/Simple/Simple.ino b/libraries/EnableInterrupt/examples/Simple/Simple.ino new file mode 100644 index 0000000..f818e5d --- /dev/null +++ b/libraries/EnableInterrupt/examples/Simple/Simple.ino @@ -0,0 +1,67 @@ +// EnableInterrupt Simple example sketch. Demonstrates operation on a single pin of your choice. +// See https://github.com/GreyGnome/EnableInterrupt and the README.md for more information. +#include + +// Modify this at your leisure. Refer to https://github.com/GreyGnome/EnableInterrupt/wiki/Usage#Summary +#if defined __AVR_ATmega640__ || defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ || \ + defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ +#define ARDUINOPIN 10 +#else +// Pin 7 is useful on Arduino Uno, Leonardo, Mighty1284, ATtiny84... +#define ARDUINOPIN 7 +#endif + +volatile uint16_t interruptCount=0; // The count will go back to 0 after hitting 65535. + +void interruptFunction() { + interruptCount++; +} + +void setup() { + Serial.begin(115200); +#ifdef MIGHTY1284 + DDRA=0x0; DDRB=0x0; DDRC=0x0; DDRD=0x0; // set all pins as inputs + PORTA=0xFF; PORTB=0xFF; PORTC=0xFF; PORTD=0xFF; // turn on all pullup resistors. +#else + pinMode(ARDUINOPIN, INPUT_PULLUP); // See http://arduino.cc/en/Tutorial/DigitalPins +#endif + enableInterrupt(ARDUINOPIN, interruptFunction, CHANGE); +} + +// In the loop we just display interruptCount. The value is updated by the interrupt routine. +void loop() { + Serial.println("---------------------------------------"); + delay(1000); + Serial.print("Pin was interrupted: "); + Serial.print(interruptCount, DEC); + Serial.println(" times so far."); +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////// GORY DETAILS ////////////////////////////////////// +// This has only been tested on an Arduino Duemilanove and Mega ADK. +// It is designed to work with the Arduino Duemilanove/Uno, Arduino Mega2560/ADK, the Arduino +// Leonardo, and the Arduino Due. Please let me know how you fare on the Leonardo or Due. + +// To use: + +// 1. You must be using a fairly recent version of the Arduino IDE software on your PC/Mac, +// that is, version 1.0.1 or later. Check Help->About Arduino in the IDE. + +// 2. Wire a simple switch to any Analog or Digital pin (known as ARDUINOPIN, defined below) +// that supports interrupts. See https://github.com/GreyGnome/EnableInterrupt/wiki/Usage#Summary +// Attach the other end to a GND pin. A "single pole single throw momentary contact normally +// open" // pushbutton switch is best for the most interrupting fun. +// See https://www.sparkfun.com/products/97 and https://octopart.com/b3f-1000-omron-3117 + +// 3. When pressed, the switch will connect the pin to ground ("low", or "0") voltage, and interrupt the +// processor. See http://arduino.cc/en/Tutorial/DigitalPins + +// 4. The interrupt is serviced immediately, and the ISR (Interrupt SubRoutine) modifies the value of +// the global variable interruptCount. Open Tools->Serial Monitor in the IDE to see the results of your +// interrupts. + +// 5. Peruse the Examples directory for more elaborate examples. + +// 6. Create your own sketch using the EnableInterrupt library! + diff --git a/libraries/EnableInterrupt/examples/SimpleDueZero/SimpleDueZero.ino b/libraries/EnableInterrupt/examples/SimpleDueZero/SimpleDueZero.ino new file mode 100644 index 0000000..c9db0a0 --- /dev/null +++ b/libraries/EnableInterrupt/examples/SimpleDueZero/SimpleDueZero.ino @@ -0,0 +1,47 @@ +// EnableInterrupt Simple example sketch. Demonstrates operation on a single pin of your choice. +// See https://github.com/GreyGnome/EnableInterrupt and the README.md for more information. +#include + +// Modify this at your leisure. Refer to https://github.com/GreyGnome/EnableInterrupt/wiki/Usage#Summary +#define ARDUINOPIN 10 + +volatile uint16_t interruptCount=0; // The count will go back to 0 after hitting 65535. + +void interruptFunction() { + interruptCount++; +} + +void setup() { + Serial.begin(115200); + pinMode(ARDUINOPIN, INPUT_PULLUP); // See http://arduino.cc/en/Tutorial/DigitalPins + enableInterrupt(ARDUINOPIN, interruptFunction, CHANGE); +} + +// In the loop we just display interruptCount. The value is updated by the interrupt routine. +void loop() { + Serial.println("---------------------------------------"); + delay(1000); + Serial.print("Pin was interrupted: "); + Serial.print(interruptCount, DEC); + Serial.println(" times so far."); +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////// GORY DETAILS ////////////////////////////////////// + +/* The EnableInterrupt library was designed to present a single API for interrupts to all + * the Arduino processors. The problems have traditionally been caused by the varying and + * complicated pin interrupt schemes of the ATmega line of processors. The SAM processors + * present a more straightforward interrupt design. They already do what the EnableInterrupt + * library is trying to present: To enable an interrupt on a pin, simply set up that pin + * with the type of interrupt you want, no conversion to an "Interrupt Number" [see the + * attachInterrupt() docs]. + * + * This means that the EnableInterrupt library's work on the Due and Zero is trivial: if + * called on those platforms, we simply create a macro that converts enableInterrupt() and + * disableInterrupt() to attachInterrupt()/detachInterrupt(). + * + * Since that's all it does, the ONLY advantage the EnableInterrupt library offers is as + * a consistent API across the chip families. If you are not interested in this then don't use + * the EnableInterrupt library. + */ diff --git a/libraries/EnableInterrupt/examples/SimpleWithLibrary/Makefile b/libraries/EnableInterrupt/examples/SimpleWithLibrary/Makefile new file mode 100644 index 0000000..b10e505 --- /dev/null +++ b/libraries/EnableInterrupt/examples/SimpleWithLibrary/Makefile @@ -0,0 +1,14 @@ +# Arduino Makefile, see https://github.com/sudar/Arduino-Makefile (it's awesome!) +BOARD_TAG = pro +BOARD_SUB = 16MHzatmega328 +ARDUINO_PORT = /dev/ttyUSB0 +#BOARD_TAG = 2560 +#ARDUINO_PORT = /dev/ttyACM0 +ARDUINO_LIBS = +AVR_TOOLS_DIR = /usr + +CFLAGS_STD = -g +CXXFLAGS_STD = -g + +include /usr/share/arduino/Arduino.mk + diff --git a/libraries/EnableInterrupt/examples/SimpleWithLibrary/SimpleWithLibrary.ino b/libraries/EnableInterrupt/examples/SimpleWithLibrary/SimpleWithLibrary.ino new file mode 100644 index 0000000..0bf7eef --- /dev/null +++ b/libraries/EnableInterrupt/examples/SimpleWithLibrary/SimpleWithLibrary.ino @@ -0,0 +1,39 @@ +// SimpleWithLibrary example sketch for the EnableInterrupt library. Demonstrates how to use +// the EnableInterrupt library with a sketch that services an interrupt pin, and uses a library +// that also requires the EnableInterrupt library. + +// This sketch has only been compiled to the Arduino Uno (ATmega328). +// This sketch is only known to compile. It has not been tested functionally. + +// See https://github.com/GreyGnome/EnableInterrupt and the README.md for more information. +#define EI_ARDUINO_INTERRUPTED_PIN +#include +#define USELESSPIN 10 +#include "Useless.h" + +#define ARDUINOPIN 9 + +volatile uint16_t interruptCount=0; + +void interruptFunction() { + interruptCount++; +} + +// UselessClass uses the EnableInterrupt library. +UselessClass uselessObject=UselessClass(USELESSPIN, CHANGE); + +void setup() { + Serial.begin(115200); + pinMode(ARDUINOPIN, INPUT_PULLUP); // See http://arduino.cc/en/Tutorial/DigitalPins + enableInterrupt(ARDUINOPIN, interruptFunction, CHANGE); +} + +void loop() { + Serial.println("---------------------------------------"); + delay(1000); + Serial.print("Pin was interrupted: "); + Serial.print(interruptCount, DEC); + Serial.println(" times so far."); + Serial.print("Useless interrupt count: "); + Serial.print(uselessObject.getUselessVariable(), DEC); +} diff --git a/libraries/EnableInterrupt/examples/SimpleWithLibrary/Useless.cpp b/libraries/EnableInterrupt/examples/SimpleWithLibrary/Useless.cpp new file mode 100644 index 0000000..e48a1e4 --- /dev/null +++ b/libraries/EnableInterrupt/examples/SimpleWithLibrary/Useless.cpp @@ -0,0 +1,26 @@ +// FOR TESTING, TO DEMONSTRATE HOW TO USE ENABLEINTERRUPT IN A LIBRARY. +// See Useless.h for more information. +#include "Useless.h" + +volatile uint8_t uselessVariable=0; + +void uselessFunction() { + uselessVariable++; +} + +void UselessClass::init(uint8_t pin, uint8_t mode) { + pinMode(pin, INPUT_PULLUP); + enableInterrupt(pin, uselessFunction, mode); +} + +uint8_t UselessClass::getUselessVariable() { + return uselessVariable; +} + +void UselessClass::reset() { + uselessVariable=0; +} + +void UselessClass::disable(uint8_t pin) { + disableInterrupt(pin); +} diff --git a/libraries/EnableInterrupt/examples/SimpleWithLibrary/Useless.h b/libraries/EnableInterrupt/examples/SimpleWithLibrary/Useless.h new file mode 100644 index 0000000..8593dc1 --- /dev/null +++ b/libraries/EnableInterrupt/examples/SimpleWithLibrary/Useless.h @@ -0,0 +1,28 @@ +// This is a useless library. To use such a useless thing, with the EnableInterrupt library, +// you need to #define LIBCALL_ENABLEINTERRUPT in your library, like so: +#define LIBCALL_ENABLEINTERRUPT +// Thus, none of the functions or ISRs will get compiled but their prototypes are declared +// so you can use them as illustrated in the Useless.cpp. + +// You also need to #include the EnableInterrupt.h file in your sketch. After you #include the +// EnableInterrupt.h file, #include the library's .h file (ie, this one in this example). This +// will compile the requisite components. See the SimpleWithLibrary.ino sketch. + +#include +#include + +#define EI_ARDUINO_INTERRUPTED_PIN +#include + +class UselessClass { + public: + UselessClass(uint8_t pin, uint8_t mode) { + init(pin, mode); + } + uint8_t getUselessVariable(); + void reset(); + void disable(uint8_t pin); + private: + void init(uint8_t pin, uint8_t mode); +}; + diff --git a/libraries/EnableInterrupt/examples/Testing/Testing.ino b/libraries/EnableInterrupt/examples/Testing/Testing.ino new file mode 100644 index 0000000..cca4875 --- /dev/null +++ b/libraries/EnableInterrupt/examples/Testing/Testing.ino @@ -0,0 +1,100 @@ + + +// include the EnableInterrupt library - see the links in the related topics section above for details + #define EI_ARDUINO_INTERRUPTED_PIN // to enable pin states functionality +#include + + +//DEBUG settings +#define DEBUG 1 // 0 - no debug + + +// Assign your channel in pins +#define CHANNEL1_IN_PIN 2 +#define CHANNEL2_IN_PIN 3 +#define CHANNEL3_IN_PIN 4 +#define CHANNEL4_IN_PIN 5 +#define CHANNEL5_IN_PIN 6 +#define CHANNEL6_IN_PIN 7 +#define CHANNEL7_IN_PIN 8 +#define CHANNEL8_IN_PIN 9 + + + + +volatile uint16_t interruptCountA=0; // The count will go back to 0 after hitting 65535. +volatile uint16_t PinStateSumB=0; // The count will go back to 0 after hitting 65535. + +// shared variables are updated by the ISR and read by loop. +// In loop we immediatley take local copies so that the ISR can keep ownership of the +// shared ones. To access these in loop +// we first turn interrupts off with noInterrupts +// we take a copy to use in loop and the turn interrupts back on +// as quickly as possible, this ensures that we are always able to receive new signals +volatile uint8_t InterruptedPinShared; +volatile uint8_t PinStateShared; + + +void setup() +{ + + + if (DEBUG !=0) { + Serial.begin(9600); + Serial.println("setup started "); + } + + enableInterrupt(CHANNEL1_IN_PIN, interruptFunction,CHANGE); + enableInterrupt(CHANNEL2_IN_PIN, interruptFunction,CHANGE); + + if (DEBUG !=0) { + Serial.println(" setup completed "); + } +} + +void loop() +{ + + static uint8_t InterruptedPin; + static uint8_t PinState; + noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables + InterruptedPin = InterruptedPinShared; + PinState = PinStateShared; + interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on + // as soon as interrupts are back on, we can no longer use the shared variables here + + //Printing + if (DEBUG !=0) { + Serial.print("interruptCountA:"); + Serial.print(interruptCountA); + Serial.println(""); + Serial.print("PinStateSumB:"); + Serial.print(PinStateSumB); + Serial.println(""); + Serial.print("InterruptedPin:"); + Serial.print(InterruptedPin); + Serial.println(""); + Serial.print("PinState:"); + Serial.print(PinState); + Serial.println(""); + + } + + +}// end of loop + + +void interruptFunction() { + //interruptCountA increased each time interrupt called + interruptCountA++; + //save values to use them outside the interrupt function + InterruptedPinShared=arduinoInterruptedPin; + PinStateShared=arduinoPinState; + //PinStateSumB increased each time arduinoPinState=1 detected + PinStateSumB=PinStateSumB + arduinoPinState ; + } + + + + + diff --git a/libraries/EnableInterrupt/examples/test.sh b/libraries/EnableInterrupt/examples/test.sh new file mode 100644 index 0000000..4cd1770 --- /dev/null +++ b/libraries/EnableInterrupt/examples/test.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +examples=" +AllPins2560 +AllPins328 +ATtinyBlink +HiSpeed +HiSpeedAllPins2560 +HiSpeedAllPins328 +InterruptedPin2560 +InterruptedPin328 +Mighty1284p +OOSimple +Simple +SimpleWithLibrary +" + +for example in $examples; do + echo $example + sleep 2 + ( cd $example; rm -rf build-*; make) + echo $example done + sleep 2 +done diff --git a/libraries/EnableInterrupt/extras/LICENSE b/libraries/EnableInterrupt/extras/LICENSE new file mode 100644 index 0000000..e06d208 --- /dev/null +++ b/libraries/EnableInterrupt/extras/LICENSE @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/libraries/EnableInterrupt/extras/NOTICE b/libraries/EnableInterrupt/extras/NOTICE new file mode 100644 index 0000000..a3779b6 --- /dev/null +++ b/libraries/EnableInterrupt/extras/NOTICE @@ -0,0 +1,19 @@ + NOTICE + EnableInterrupt Arduino Library + Copyright 2014-2015 Michael Schwager (aka Mike Schwager aka "GreyGnome") + + This product includes software developed by Mike Schwager. + + This library was inspired and replaces the PinChangeInt library. + + GreyGnome is the current maintainer, and would like to thank all those + Open Source coders, the Arduino makers and community, and especially Chris + and Lex for lighting the flame and showing the way! And a big thank you to + the users who have contributed comments and bug fixes along the way. + Without you this project would not have overcome some significant hurdles. + + A HUGE thanks to Jan Baeyens ("jantje"), who has graciously DONATED an + Arduino Mega ADK board to the PinChangeInt project!!! Wow, thanks Jan! + This makes the 2560-based Arduino Mega a first class supported platform- + I am able to test it and verify that it works. + diff --git a/libraries/EnableInterrupt/extras/RELEASE_NOTES b/libraries/EnableInterrupt/extras/RELEASE_NOTES new file mode 100644 index 0000000..72dcb19 --- /dev/null +++ b/libraries/EnableInterrupt/extras/RELEASE_NOTES @@ -0,0 +1,92 @@ +Wed Sep 4 19:30:45 CDT 2019 +Version 1.1.0 +We add support for the ATmega2561 and 1281 chips, with pinouts defined from the MCUdude/MegaCore project. Code donations by Kizmit99. Plus, a documentation bugfix from Greg Bowler. Thanks, folks! + +Fri Jun 22 06:47:13 CDT 2018 +Version 1.0.0 +Alex Reinert contributed Bobuino support. Thanks, Alex! And at this point, I think it's long past due that we stick a non-beta sticker on this thing. Congratulations, EnableInterrupt- you are all grown up. Version 1.0.0 it is. + +Tue Sep 19 18:02:21 CDT 2017 +Version 0.9.8. +There were a number of outstanding pull requests that were merged into the library. Thanks +to Loranzo Cafaro for his switch debounce example, to Jevon Wild for his changes to make the +library more functional with PlatformIO (http://docs.platformio.org/en/latest/what-is-platformio.html), +Ricardo JL Rufino for some PlatformIO fixes to the library.json file, and Sara Damiano for +adding support for the Sodaq Mbili and EnviroDIY Mayfly. + +Wed Apr 27 18:07:02 CDT 2016 +Version 0.9.5 Added the arduinoPinState variable, which is available when EI_INTERRUPTED_PIN is defined. Added support for platformio http://platformio.org/ (thanks dorkusprime!). + +Fri Nov 6 19:13:20 CST 2015 +Version 0.9.4. Thanks again to RobertClemenzi, who discovered 2 bugs: 1. A spurious comma in some array definitions caused a compiler warning, and more importantly, 2. it was impossible to use arduinoInterruptedPin if this library was used to support other libraries. Fixed them both. + +Mon Oct 19 07:45:08 CDT 2015 +Version 0.9.3. Thanks to RobertClemenzi, who pointed out that "Useless.cpp" is not included with the distribution zip file. The only change is to add that file to the distribution zip file. + +Sat Oct 17 12:03:03 CDT 2015 +Version 0.9.2. I discovered a rather pernicious bug, wherein the library was setting the global interrupt enable bit. This could cause a serious and difficult-to-debug race condition, as it is not the job of the library to manage that bit. The chips come with interrupts enabled so exi +sting code should not be affected. My thanks to http://gammon.com.au/interrupts (the 'How are interrupts queued?' section). + +Fri Oct 16 07:58:45 CDT 2015 +Version 0.9.1. Bug fixes to examples/OOSimple (thanks RobertClemenzi!). Arduino Zero support added (this is a trivial preprocessor macro check; see the Usage wiki page). Wiki pages updated, especially the FAQ. + +Tue Sep 29 06:34:58 CDT 2015 +Version 0.9.0. ATtiny support has been added! Support files come from https://github.com/damellis/attiny . +Chips supported include ATtiny44/84 and ATtiny 45/85 (including Gemma). As always, bug reports are +welcome at https://github.com/GreyGnome/EnableInterrupt/issues . NOTE: I don't have an ATtiny (yet), +so the only work I could do was to make sure a sample sketch compiled. + +Thu Aug 27 22:24:39 CDT 2015 +Version 0.8.2. Includes bugfixes for issues raised by engwan, MakkyB, and juanricos; HiSpeed mode was not working but now it is. I also received some nice bug reports and testing from TomWS1. Finally, the library.properties file was out of date. + +Sat Aug 8 12:03:24 CDT 2015 +Version 0.8.1. I forgot to include some fixes for an issue on the website; https://github.com/GreyGnome/EnableInterrupt/issues/13 (having to do with the 1284 chip). These are now included. + +Fri Aug 7 06:44:55 CDT 2015 +Version 0.8.0. This release includes the function to set a variable that can be queried by the programmer's +ISR, to determine which pin was interrupted. Define EI_ARDUINO_INTERRUPTED_PIN in the main sketch. + +Also: +My Mega2560 failed right in the middle of testing this release. So that platform is not fully tested. +The InterruptedPin2560.ino sketch was giving me some inconsistent results: I saw pin 71 interrupted twice, +and pin 70 not at all. I think there is a bug in utility/ei_PinChange2560.h, but I will release before I resolve +this. If there is anyone who could test on the 2560 platform- run the InterruptedPin2560.ino sketch and send me +the output- I would appreciate it. + +Mon Jul 6 17:41:05 CDT 2015 +This release includes compiler directives that allow you to eliminate unneeded ports and memory allocations, to more efficiently utilize code and static RAM. See https://github.com/GreyGnome/EnableInterrupt/wiki/SaveMemory for the new features. + +Tue Jun 23 06:47:10 CDT 2015 +Version 0.6.3 of the library has been released. This release includes an Object Oriented example, OOSimple, in the examples/ directory. There are no other changes since version 0.6.2. + +Fri Jun 19 09:38:43 CDT 2015 +Version 0.6.2. Forgot to update README.md. + +Fri Jun 12 06:33:20 CDT 2015 +Version 0.6.1 of the library has been released. This version is designed to meet the requirements of the 1.5.x Arduino library spec. No code logic was modified; only files were moved and library.properties and keywords.txt files added. + +Version 0.6.0 did not include an update to these release notes. + +Fri Jun 12 06:33:20 CDT 2015 +Version 0.5 (Alpha) of the library has been released. This release includes support for the ATmega1284p line of processors (includes ATmega644). The Mighty 1284 is used as the basis. As I don't have a 1284-based processor, this code compiles but has not been tested (see examples/Might1284p). Bug reports encouraged and welcomed! It would be great if a 644/1284 owner could upload the Might1284p.ino sketch and interrupt every pin and let me know the results. + +Code was refactored so that a lot of utility routines were moved into individual .h files. Now there's a lot of files, which appears ugly, but the old way was a lot uglier to my mind and looked like a big bowl of spaghetti with so many #ifdefs strewn about to handle the different chips. It was getting hard to wade through the code. + +Fri May 8 07:33:26 CDT 2015 +Version 0.4 - New high speed ("HiSpeed") mode. In this mode, the interrupt routine is predefined: +it ONLY updates a variable. This knocks a couple of microseconds off of the interrupt +routine times; it greatly reduces the number of registers needed to be pushed/popped, and +of course does not require a function call. See the wiki for details, including speed measurements. + +Mon Apr 13 07:49:05 CDT 2015 +Version 0.3 - Arjun reported a bug on the Uno platform: + +In file included from Interrupt.ino:1: +/Users/arjunmehta94/Documents/Arduino/libraries/EnableInterrupt-master/EnableInterrupt.h: In function 'void __vector_3()': +/Users/arjunmehta94/Documents/Arduino/libraries/EnableInterrupt-master/EnableInterrupt.h:976: error: 'struct functionPointersPortB' has no member named 'pinSix' +/Users/arjunmehta94/Documents/Arduino/libraries/EnableInterrupt-master/EnableInterrupt.h:977: error: 'struct functionPointersPortB' has no member named 'pinSeven' + +I have a Duemilanove; I don't know why I never saw that error. Regardless, I have included some +#ifndef lines in to protect that code from getting compiled. + +Also added RELEASE_NOTES to the zip file, and to Git. diff --git a/libraries/EnableInterrupt/findInH b/libraries/EnableInterrupt/findInH new file mode 100644 index 0000000..2017ac6 --- /dev/null +++ b/libraries/EnableInterrupt/findInH @@ -0,0 +1,13 @@ +#!/bin/bash +# A utility program for looking for stuff in the #include directories on my system. +# Tracked so I have a backup of it. + +arduinoToo=false + +[ "$1" = "-a" ] && arduinoToo=true && shift +find /usr/avr/include /usr/lib/gcc/avr/*/include /usr/lib/gcc/avr/*/include-fixed \ + /usr/lib/gcc/avr/*/plugin/include \ + -type f -exec grep "$1" {} \; -print + +$arduinoToo && find /usr/share/arduino \ + -type f -exec grep "$1" {} \; -print diff --git a/libraries/EnableInterrupt/keywords.txt b/libraries/EnableInterrupt/keywords.txt new file mode 100644 index 0000000..4b4bb17 --- /dev/null +++ b/libraries/EnableInterrupt/keywords.txt @@ -0,0 +1,20 @@ +####################################### +# Syntax Coloring Map For EnableInterrupt +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +enableInterrupt KEYWORD2 +disableInterrupt KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +PINCHANGEINTERRUPT LITERAL1 diff --git a/libraries/EnableInterrupt/library.json b/libraries/EnableInterrupt/library.json new file mode 100644 index 0000000..3e89413 --- /dev/null +++ b/libraries/EnableInterrupt/library.json @@ -0,0 +1,20 @@ +{ + "name": "EnableInterrupt", + "version": "1.1.0", + "frameworks": "arduino", + "platforms" : "atmelavr", + "keywords": "interrupt, interrupts, pin, pins", + "description": "Assign an interrupt to any supported pin on all Arduinos, plus ATtiny 84/85 and ATmega 644/1284.", + "authors": [ + { + "name": "Mike 'GreyGnome' Schwager", + "email": "mschwage@gmail.com", + "url": "https://github.com/GreyGnome", + "maintainer": true + } + ], + "repository": { + "type": "git", + "url": "https://github.com/GreyGnome/EnableInterrupt" + } +} diff --git a/libraries/EnableInterrupt/library.properties b/libraries/EnableInterrupt/library.properties new file mode 100644 index 0000000..0e43849 --- /dev/null +++ b/libraries/EnableInterrupt/library.properties @@ -0,0 +1,9 @@ +name=EnableInterrupt +version=1.1.0 +author=Mike "GreyGnome" Schwager +maintainer=Mike "GreyGnome" Schwager +sentence=Assign an interrupt to any supported pin on all Arduinos, plus ATtiny 84/85 and ATmega 644/1284. +paragraph=Provides a consistent API across chips, architectures, and interrupt types. Makes External and Pin Change on the ATmega series, and Due and Zero pin interrupts operate similarly. Code optimized for speed; includes an extra-high-speed mode for speed critical code. +category=Signal Input/Output +url=https://github.com/GreyGnome/EnableInterrupt +architectures=* diff --git a/libraries/EnableInterrupt/utility/ei_External1284.h b/libraries/EnableInterrupt/utility/ei_External1284.h new file mode 100644 index 0000000..05f8b16 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_External1284.h @@ -0,0 +1,66 @@ +#if ! defined(EI_NOTINT0) && ! defined (EI_NOTINT1) && ! defined (EI_NOTINT2) +#ifdef EI_SECTION_ENABLEEXTERNAL +switch (arduinoPin) { +#ifndef EI_NOTINT0 + case ARDUINO_PIN_D2 : // INT0 (Either 2 or 10) + EIMSK &= ~_BV(0); +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[0] = userFunction; +#endif + EICRA &= (~_BV(0) & ~_BV(1)); // reset the flags prior to + EICRA |= mode; // set them the way we want + EIFR |= _BV(0); + EIMSK |= _BV(0); + break; +#endif +#ifndef EI_NOTINT1 + case ARDUINO_PIN_D3 : // INT1 (Either 3 or 11) + EIMSK &= ~_BV(1); +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[1] = userFunction; +#endif + EICRA &= (~_BV(2) & ~_BV(3)); + EICRA |= (mode << 2); + EIFR |= _BV(1); + EIMSK |= _BV(1); + break; +#endif +#ifndef EI_NOTINT2 + case ARDUINO_PIN_B2 : // INT2 (Either 10 or 2) + EIMSK &= ~_BV(2); +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[2] = userFunction; +#endif + EICRA &= (~_BV(4) & ~_BV(5)); + EICRA |= (mode << 4); + EIFR |= _BV(2); + EIMSK |= _BV(2); + break; +#endif +} +#endif // EI_SECTION_ENABLEEXTERNAL + +#ifdef EI_SECTION_DISABLEEXTERNAL +#ifndef EI_NOTINT0 +if (arduinoPin == ARDUINO_PIN_D2) { // INT0 (Either 2 or 10) + EIMSK &= ~_BV(0); + EICRA &= (~_BV(0) & ~_BV(1)); + EIFR |= _BV(0); // using a clue from the ATmega2560 datasheet. +} +#endif +#ifndef EI_NOTINT1 +if (arduinoPin == ARDUINO_PIN_D3) { // INT1 (Either 3 or 11) + EIMSK &= ~_BV(1); + EICRA &= (~_BV(2) & ~_BV(3)); + EIFR |= _BV(1); // using a clue from the ATmega2560 datasheet. +} +#endif +#ifndef EI_NOTINT2 +if (arduinoPin == ARDUINO_PIN_B2) { // INT2 (Either 10 or 2) + EIMSK &= ~_BV(2); + EICRA &= (~_BV(4) & ~_BV(5)); + EIFR |= _BV(2); // using a clue from the ATmega2560 datasheet. +} +#endif +#endif // EI_SECTION_DISABLEEXTERNAL +#endif // ! defined(EI_NOTINT0) && ! defined (EI_NOTINT1) && ! defined (EI_NOTINT2) diff --git a/libraries/EnableInterrupt/utility/ei_External2560.h b/libraries/EnableInterrupt/utility/ei_External2560.h new file mode 100644 index 0000000..5d84e76 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_External2560.h @@ -0,0 +1,228 @@ +#if ! defined(EI_NOTINT0) && ! defined(EI_NOTINT1) && ! defined(EI_NOTINT2) && ! defined(EI_NOTINT3) && ! defined(EI_NOTINT4) && ! defined(EI_NOTINT5) && ! defined(EI_NOTINT6) && ! defined(EI_NOTINT7) +#ifdef EI_SECTION_ENABLEEXTERNAL +switch (arduinoPin) { +#ifndef EI_NOTINT0 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 18 : // INT0 (xxx1 - MegaCore pinout) +#else + case 21 : // INT0 +#endif +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[0] = userFunction; +#endif + EIMSK &= ~_BV(0); + EICRA &= (~_BV(0) & ~_BV(1)); + EICRA |= mode; + EIFR |= _BV(0); + EIMSK |= _BV(0); + break; +#endif +#ifndef EI_NOTINT1 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 19 : // INT1 +#else + case 20 : // INT1 +#endif +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[1] = userFunction; +#endif + EIMSK &= ~_BV(1); + EICRA &= (~_BV(2) & ~_BV(3)); + EICRA |= (mode << 2); + EIFR |= _BV(1); + EIMSK |= _BV(1); + break; +#endif +#ifndef EI_NOTINT2 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 20 : // INT2 +#else + case 19 : // INT2 +#endif +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[2] = userFunction; +#endif + EIMSK &= ~_BV(2); + EICRA &= (~_BV(4) & ~_BV(5)); + EICRA |= (mode << 4); + EIFR |= _BV(2); + EIMSK |= _BV(2); + break; +#endif +#ifndef EI_NOTINT3 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 21 : // INT3 +#else + case 18 : // INT3 +#endif +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[3] = userFunction; +#endif + EIMSK &= ~_BV(3); + EICRA &= (~_BV(6) & ~_BV(7)); + EICRA |= (mode << 6); + EIFR |= _BV(3); + EIMSK |= _BV(3); + break; +#endif +#ifndef EI_NOTINT4 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 4 : // INT4 +#else + case 2 : // INT4 +#endif +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[4] = userFunction; +#endif + EIMSK &= ~_BV(4); + EICRB &= (~_BV(0) & ~_BV(1)); + EICRB |= mode; + EIFR |= _BV(4); + EIMSK |= _BV(4); + break; +#endif +#ifndef EI_NOTINT5 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 5 : // INT5 +#else + case 3 : // INT5 +#endif +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[5] = userFunction; +#endif + EIMSK &= ~_BV(5); + EICRB &= (~_BV(2) & ~_BV(3)); + EICRB |= (mode << 2); + EIFR |= _BV(5); + EIMSK |= _BV(5); + break; +#endif +#ifndef EI_NOTINT6 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 6 : // INT6 +#else + case 75 : // INT6- Fake Arduino Pin +#endif +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[6] = userFunction; +#endif + EIMSK &= ~_BV(6); + EICRB &= (~_BV(4) & ~_BV(5)); + EICRB |= (mode << 4); + EIFR |= _BV(6); + EIMSK |= _BV(6); + break; +#endif +#ifndef EI_NOTINT7 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 7 : // INT7 +#else + case 76 : // INT7- Fake Arduino Pin +#endif +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[7] = userFunction; +#endif + EIMSK &= ~_BV(7); + EICRB &= (~_BV(6) & ~_BV(7)); + EICRB |= (mode << 6); + EIFR |= _BV(7); + EIMSK |= _BV(7); + break; +#endif +} +#endif // EI_SECTION_ENABLEEXTERNAL + +#ifdef EI_SECTION_DISABLEEXTERNAL +switch (arduinoPin) { +#ifndef EI_NOTINT0 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 18 : // INT0 +#else + case 21 : // INT0 +#endif + EIMSK &= ~_BV(0); + EICRA &= (~_BV(0) & ~_BV(1)); + EIFR |= _BV(0); + break; +#endif +#ifndef EI_NOTINT1 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 19 : // INT1 +#else + case 20 : // INT1 +#endif + EIMSK &= ~_BV(1); + EICRA &= (~_BV(2) & ~_BV(3)); + EIFR |= _BV(1); + break; +#endif +#ifndef EI_NOTINT2 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 20 : // INT2 +#else + case 19 : // INT2 +#endif + EIMSK &= ~_BV(2); + EICRA &= (~_BV(4) & ~_BV(5)); + EIFR |= _BV(2); + break; +#endif +#ifndef EI_NOTINT3 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 21 : // INT3 +#else + case 18 : // INT3 +#endif + EIMSK &= ~_BV(3); + EICRA &= (~_BV(6) & ~_BV(7)); + EIFR |= _BV(3); + break; +#endif +#ifndef EI_NOTINT4 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 4 : // INT4 +#else + case 2 : // INT4 +#endif + EIMSK &= ~_BV(4); + EICRB &= (~_BV(0) & ~_BV(1)); + EIFR |= _BV(4); + break; +#endif +#ifndef EI_NOTINT5 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 5 : // INT5 +#else + case 3 : // INT5 +#endif + EIMSK &= ~_BV(5); + EICRB &= (~_BV(2) & ~_BV(3)); + EIFR |= _BV(5); + break; +#endif +#ifndef EI_NOTINT6 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 6 : // INT6 +#else + case 75 : // INT6- Fake Arduino Pin +#endif + EIMSK &= ~_BV(6); + EICRB &= (~_BV(4) & ~_BV(5)); + EIFR |= _BV(6); + break; +#endif +#ifndef EI_NOTINT7 +#if defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ + case 7 : // INT7 +#else + case 76 : // INT7- Fake Arduino Pin +#endif + EIMSK &= ~_BV(7); + EICRB &= (~_BV(6) & ~_BV(7)); + EIFR |= _BV(7); + break; +#endif +} +#endif // EI_SECTION_DISABLEEXTERNAL +#endif // ! defined(EI_NOTINT0) && ! defined(EI_NOTINT1) && ! defined(EI_NOTINT2) && ! defined(EI_NOTINT3) && ! defined(EI_NOTINT4) && ! defined(EI_NOTINT5) && ! defined(EI_NOTINT6) && ! defined(EI_NOTINT7) + diff --git a/libraries/EnableInterrupt/utility/ei_External328.h b/libraries/EnableInterrupt/utility/ei_External328.h new file mode 100644 index 0000000..85902d1 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_External328.h @@ -0,0 +1,45 @@ +#if ! defined(EI_NOTINT0) && ! defined(EI_NOTINT1) +#ifdef EI_SECTION_ENABLEEXTERNAL +#ifndef EI_NOTINT0 +if (arduinoPin == 2) { +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[0] = userFunction; +#endif + EIMSK &= ~_BV(0); + EICRA &= (~_BV(0) & ~_BV(1)); + EICRA |= mode; + EIFR |= _BV(0); // using a clue from the ATmega2560 datasheet. + EIMSK |= _BV(0); +} +#endif +#ifndef EI_NOTINT1 +if (arduinoPin == 3) { +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[1] = userFunction; +#endif + EIMSK &= ~_BV(1); + EICRA &= (~_BV(2) & ~_BV(3)); + EICRA |= mode << 2; + EIFR |= _BV(1); // using a clue from the ATmega2560 datasheet. + EIMSK |= _BV(1); +} +#endif +#endif // EI_SECTION_ENABLEEXTERNAL + +#ifdef EI_SECTION_DISABLEEXTERNAL +#ifndef EI_NOTINT0 +if (arduinoPin == 2) { + EIMSK &= ~_BV(0); + EICRA &= (~_BV(0) & ~_BV(1)); + EIFR |= _BV(0); // using a clue from the ATmega2560 datasheet. +} +#endif +#ifndef EI_NOTINT1 +if (arduinoPin == 3) { + EIMSK &= ~_BV(1); + EICRA &= (~_BV(2) & ~_BV(3)); + EIFR |= _BV(1); // using a clue from the ATmega2560 datasheet. +} +#endif +#endif // EI_SECTION_DISABLEEXTERNAL +#endif // ! defined(EI_NOTINT0) && ! defined(EI_NOTINT1) diff --git a/libraries/EnableInterrupt/utility/ei_ExternalLeonardo.h b/libraries/EnableInterrupt/utility/ei_ExternalLeonardo.h new file mode 100644 index 0000000..9b6b1a4 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_ExternalLeonardo.h @@ -0,0 +1,106 @@ +#if ! defined(EI_NOTINT0) && ! defined(EI_NOTINT1) && ! defined(EI_NOTINT2) && ! defined(EI_NOTINT3) && ! defined(EI_NOTINT6) +#ifdef EI_SECTION_ENABLEEXTERNAL +switch (arduinoPin) { +#ifndef EI_NOTINT0 + case 3 : // INT0 +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[0] = userFunction; +#endif + EIMSK &= ~_BV(0); + EICRA &= (~_BV(0) & ~_BV(1)); + EICRA |= mode; + EIFR |= _BV(0); + EIMSK |= _BV(0); + break; +#endif +#ifndef EI_NOTINT1 + case 2 : // INT1 +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[1] = userFunction; +#endif + EIMSK &= ~_BV(1); + EICRA &= (~_BV(2) & ~_BV(3)); + EICRA |= (mode << 2); + EIFR |= _BV(1); + EIMSK |= _BV(1); + break; +#endif +#ifndef EI_NOTINT2 + case 0 : // INT2 +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[2] = userFunction; +#endif + EIMSK &= ~_BV(2); + EICRA &= (~_BV(4) & ~_BV(5)); + EICRA |= (mode << 4); + EIFR |= _BV(2); + EIMSK |= _BV(2); + break; +#endif +#ifndef EI_NOTINT3 + case 1 : // INT3 +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[3] = userFunction; +#endif + EIMSK &= ~_BV(3); + EICRA &= (~_BV(6) & ~_BV(7)); + EICRA |= (mode << 6); + EIFR |= _BV(3); + EIMSK |= _BV(3); + break; +#endif +#ifndef EI_NOTINT6 + case 7 : // INT6 +#ifndef NEEDFORSPEED + functionPointerArrayEXTERNAL[4] = userFunction; +#endif + EIMSK &= ~_BV(6); + EICRB &= (~_BV(4) & ~_BV(5)); + EICRB |= (mode << 4); + EIFR |= _BV(6); + EIMSK |= _BV(6); + break; +#endif +} +#endif // EI_SECTION_ENABLEEXTERNAL + +#ifdef EI_SECTION_DISABLEEXTERNAL +switch (arduinoPin) { +#ifndef EI_NOTINT0 + case 3 : // INT0 + EIMSK &= ~_BV(0); + EICRA &= (~_BV(0) & ~_BV(1)); + EIFR |= _BV(0); + break; +#endif +#ifndef EI_NOTINT1 + case 2 : // INT1 + EIMSK &= ~_BV(1); + EICRA &= (~_BV(2) & ~_BV(3)); + EIFR |= _BV(1); + break; +#endif +#ifndef EI_NOTINT2 + case 0 : // INT2 + EIMSK &= ~_BV(2); + EICRA &= (~_BV(4) & ~_BV(5)); + EIFR |= _BV(2); + break; +#endif +#ifndef EI_NOTINT3 + case 1 : // INT3 + EIMSK &= ~_BV(3); + EICRA &= (~_BV(6) & ~_BV(7)); + EIFR |= _BV(3); + break; +#endif +#ifndef EI_NOTINT6 + case 7 : // INT6 + EIMSK &= ~_BV(6); + EICRB &= (~_BV(4) & ~_BV(5)); + EIFR |= _BV(6); + break; +#endif +} +#endif // EI_SECTION_DISABLEEXTERNAL +#endif // ! defined(EI_NOTINT0) && ! defined(EI_NOTINT1) && ! defined(EI_NOTINT2) && ! defined(EI_NOTINT3) && ! defined(EI_NOTINT6) diff --git a/libraries/EnableInterrupt/utility/ei_ExternalTiny24.h b/libraries/EnableInterrupt/utility/ei_ExternalTiny24.h new file mode 100644 index 0000000..6feca99 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_ExternalTiny24.h @@ -0,0 +1,24 @@ +// Support for the 14-pin ATtiny24/24A/44/44A/84/84A +#if ! defined(EI_NOTINT0) +#ifdef EI_SECTION_ENABLEEXTERNAL +// NO switch (arduinoPin) { // ONLY 1 External Interrupt pin. +#ifndef EI_NOTINT0 + GIMSK &= ~_BV(6); // Disable interrupts since we are (possibly) changing interrupt settings +#ifndef NEEDFORSPEED + externalFunctionPointer = userFunction; +#endif + MCUCR &= (~_BV(0) & ~_BV(1)); // reset the flags prior to + MCUCR |= mode; // set them the way we want + GIFR |= _BV(6); + GIMSK |= _BV(6); +#endif +#endif // EI_SECTION_ENABLEEXTERNAL + +#ifdef EI_SECTION_DISABLEEXTERNAL +#ifndef EI_NOTINT0 + GIMSK &= ~_BV(6); + MCUCR &= (~_BV(0) & ~_BV(1)); // reset the flags + GIFR |= _BV(6); // using a clue from the ATmega2560 datasheet. +#endif +#endif // EI_SECTION_DISABLEEXTERNAL +#endif // ! defined(EI_NOTINT0) && ! defined (EI_NOTINT1) && ! defined (EI_NOTINT2) diff --git a/libraries/EnableInterrupt/utility/ei_ExternalTiny25.h b/libraries/EnableInterrupt/utility/ei_ExternalTiny25.h new file mode 100644 index 0000000..85699da --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_ExternalTiny25.h @@ -0,0 +1,22 @@ +// Support for the 8-pin ATtiny25/45/85 +#ifdef EI_SECTION_ENABLEEXTERNAL +// NO switch (arduinoPin) { // ONLY 1 External Interrupt pin. +#ifndef EI_NOTINT0 + GIMSK &= ~_BV(6); +#ifndef NEEDFORSPEED + externalFunctionPointer = userFunction; +#endif + MCUCR &= (~_BV(0) & ~_BV(1)); // reset the flags prior to + MCUCR |= mode; // set them the way we want + GIFR |= _BV(6); + GIMSK |= _BV(6); +#endif // ! defined (EI_NOTINT0) +#endif // EI_SECTION_ENABLEEXTERNAL + +#ifdef EI_SECTION_DISABLEEXTERNAL +#ifndef EI_NOTINT0 + GIMSK &= ~_BV(6); + GIFR |= _BV(6); // using a clue from the ATmega2560 datasheet. + MCUCR &= (~_BV(0) & ~_BV(1)); +#endif +#endif // EI_SECTION_DISABLEEXTERNAL diff --git a/libraries/EnableInterrupt/utility/ei_PinChange1284.h b/libraries/EnableInterrupt/utility/ei_PinChange1284.h new file mode 100644 index 0000000..f236863 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_PinChange1284.h @@ -0,0 +1,127 @@ +#ifdef EI_SECTION_RISING +#ifndef EI_NOTPORTA +if (portNumber==PA) { + risingPinsPORTA |= portMask; +} +#endif +#ifndef EI_NOTPORTB +if (portNumber==PB) { + risingPinsPORTB |= portMask; +} +#endif +#ifndef EI_NOTPORTC +if (portNumber==PC) { + risingPinsPORTC |= portMask; +} +#endif +#ifndef EI_NOTPORTD +if (portNumber==PD) { + risingPinsPORTD |= portMask; +} +#endif +#endif // EI_SECTION_RISING + +#ifdef EI_SECTION_FALLING +#ifndef EI_NOTPORTA +if (portNumber==PA) { + fallingPinsPORTA |= portMask; +} +#endif +#ifndef EI_NOTPORTB +if (portNumber==PB) { + fallingPinsPORTB |= portMask; +} +#endif +#ifndef EI_NOTPORTC +if (portNumber==PC) { + fallingPinsPORTC |= portMask; +} +#endif +#ifndef EI_NOTPORTD +if (portNumber==PD) { + fallingPinsPORTD |= portMask; +} +#endif +#endif // EI_SECTION_FALLING + +#if defined EI_SECTION_ASSIGNFUNCTIONSREGISTERS +#ifndef EI_NOTPORTA +if (portNumber==PA) { +#ifndef NEEDFORSPEED + calculatedPointer=&portAFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotA=*portInputRegister(portNumber); + pcmsk=&PCMSK0; + PCICR |= _BV(0); +} +#endif +#ifndef EI_NOTPORTB +if (portNumber==PB) { +#ifndef NEEDFORSPEED + calculatedPointer=&portBFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotB=*portInputRegister(portNumber); + pcmsk=&PCMSK1; + PCICR |= _BV(1); +} +#endif +#ifndef EI_NOTPORTC +if (portNumber==PC) { +#ifndef NEEDFORSPEED + calculatedPointer=&portCFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotC=*portInputRegister(portNumber); + pcmsk=&PCMSK2; + PCICR |= _BV(2); +} +#endif +#ifndef EI_NOTPORTD +if (portNumber==PD) { +#ifndef NEEDFORSPEED + calculatedPointer=&portDFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotD=*portInputRegister(portNumber); + pcmsk=&PCMSK3; + PCICR |= _BV(3); +} +#endif +#endif // EI_SECTION_ASSIGNFUNCTIONSREGISTERS + +#ifdef EI_SECTION_DISABLEPINCHANGE +#ifndef EI_NOTPORTA +if (portNumber == PA) { + PCMSK0 &= ~portMask; + if (PCMSK0 == 0) { PCICR &= ~_BV(0); }; + risingPinsPORTA &= ~portMask; + fallingPinsPORTA &= ~portMask; +} +#endif +#ifndef EI_NOTPORTB +if (portNumber == PB) { + PCMSK1 &= ~portMask; + if (PCMSK1 == 0) { PCICR &= ~_BV(1); }; + risingPinsPORTB &= ~portMask; + fallingPinsPORTB &= ~portMask; +} +#endif +#ifndef EI_NOTPORTC +if (portNumber == PC) { + PCMSK2 &= ~portMask; + if (PCMSK2 == 0) { PCICR &= ~_BV(2); }; + risingPinsPORTC &= ~portMask; + fallingPinsPORTC &= ~portMask; +} +#endif +#ifndef EI_NOTPORTD +if (portNumber == PD) { + PCMSK3 &= ~portMask; + if (PCMSK3 == 0) { PCICR &= ~_BV(3); }; + risingPinsPORTB &= ~portMask; + fallingPinsPORTB &= ~portMask; +} +#endif +#endif // EI_SECTION_DISABLEPINCHANGE diff --git a/libraries/EnableInterrupt/utility/ei_PinChange2560.h b/libraries/EnableInterrupt/utility/ei_PinChange2560.h new file mode 100644 index 0000000..b0cdd15 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_PinChange2560.h @@ -0,0 +1,103 @@ +#ifdef EI_SECTION_RISING +#ifndef EI_NOTPORTB +if (portNumber==PB) { + risingPinsPORTB |= portMask; +} +#endif +#ifndef EI_NOTPORTJ +if (portNumber==PJ) { + risingPinsPORTJ |= portMask; +} +#endif +#ifndef EI_NOTPORTK +if (portNumber==PK) { + risingPinsPORTK |= portMask; +} +#endif +#endif + +#ifdef EI_SECTION_FALLING +#ifndef EI_NOTPORTB +if (portNumber==PB) { + fallingPinsPORTB |= portMask; +} +#endif +#ifndef EI_NOTPORTJ +if (portNumber==PJ) { + fallingPinsPORTJ |= portMask; +} +#endif +#ifndef EI_NOTPORTK +if (portNumber==PK) { + fallingPinsPORTK |= portMask; +} +#endif +#endif // EI_SECTION_FALLING + +#ifdef EI_SECTION_ASSIGNFUNCTIONSREGISTERS +#ifndef EI_NOTPORTB +if (portNumber==PB) { +#ifndef NEEDFORSPEED + calculatedPointer=&portBFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotB=*portInputRegister(portNumber); + pcmsk=&PCMSK0; + PCICR |= _BV(0); +} +#endif +#ifndef EI_NOTPORTJ +if (portNumber==PJ) { +#ifndef NEEDFORSPEED + calculatedPointer=&portJFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotJ=*portInputRegister(portNumber); + pcmsk=&PCMSK1; + PCICR |= _BV(1); + // TODO: I think the order of these is flipped. Test. BUG??? -Mike + portJPCMSK|=portMask; // because PCMSK1 is shifted wrt. PortJ. + portMask <<= 1; // Handle port J's oddness. PJ0 is actually 1 on PCMSK1. +} +#endif +#ifndef EI_NOTPORTK +if (portNumber==PK) { +#ifndef NEEDFORSPEED + calculatedPointer=&portKFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotK=*portInputRegister(portNumber); + pcmsk=&PCMSK2; + PCICR |= _BV(2); +} +#endif +#endif // EI_SECTION_ASSIGNFUNCTIONSREGISTERS + +#ifdef EI_SECTION_DISABLEPINCHANGE +#ifndef EI_NOTPORTB +if (portNumber == PB) { + PCMSK0 &= ~portMask; + if (PCMSK0 == 0) { PCICR &= ~_BV(0); }; + risingPinsPORTB &= ~portMask; + fallingPinsPORTB &= ~portMask; +} +#endif +#ifndef EI_NOTPORTJ +if (portNumber == PJ) { + // Handle port J's oddness. PJ0 is actually 1 on PCMSK1. + PCMSK1 &= ((~portMask << 1) | 0x01); // or with 1 to not touch PE0. + if (PCMSK1 == 0) { PCICR &= ~_BV(1); }; + risingPinsPORTJ &= ~portMask; + fallingPinsPORTJ &= ~portMask; +} +#endif +#ifndef EI_NOTPORTK +if (portNumber == PK) { + PCMSK2 &= ~portMask; + if (PCMSK2 == 0) { PCICR &= ~_BV(2); }; + risingPinsPORTK &= ~portMask; + fallingPinsPORTK &= ~portMask; +} +#endif +#endif // EI_SECTION_DISABLEPINCHANGE + diff --git a/libraries/EnableInterrupt/utility/ei_PinChange328.h b/libraries/EnableInterrupt/utility/ei_PinChange328.h new file mode 100644 index 0000000..7bece4b --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_PinChange328.h @@ -0,0 +1,98 @@ +#ifdef EI_SECTION_RISING +#ifndef EI_NOTPORTB +if (portNumber==PB) { + risingPinsPORTB |= portMask; +} +#endif +#ifndef EI_NOTPORTC +if (portNumber==PC) { + risingPinsPORTC |= portMask; +} +#endif +#ifndef EI_NOTPORTD +if (portNumber==PD) { + risingPinsPORTD |= portMask; +} +#endif +#endif // EI_SECTION_RISING + +#ifdef EI_SECTION_FALLING +#ifndef EI_NOTPORTB +if (portNumber==PB) { + fallingPinsPORTB |= portMask; +} +#endif +#ifndef EI_NOTPORTC +if (portNumber==PC) { + fallingPinsPORTC |= portMask; +} +#endif +#ifndef EI_NOTPORTD +if (portNumber==PD) { + fallingPinsPORTD |= portMask; +} +#endif +#endif // EI_SECTION_FALLING + +#if defined EI_SECTION_ASSIGNFUNCTIONSREGISTERS +#ifndef EI_NOTPORTB +if (portNumber==PB) { +#ifndef NEEDFORSPEED + calculatedPointer=&portBFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotB=*portInputRegister(portNumber); + pcmsk=&PCMSK0; + PCICR |= _BV(0); +} +#endif +#ifndef EI_NOTPORTC +if (portNumber==PC) { +#ifndef NEEDFORSPEED + calculatedPointer=&portCFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotC=*portInputRegister(portNumber); + pcmsk=&PCMSK1; + PCICR |= _BV(1); +} +#endif +#ifndef EI_NOTPORTD +if (portNumber==PD) { +#ifndef NEEDFORSPEED + calculatedPointer=&portDFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotD=*portInputRegister(portNumber); + pcmsk=&PCMSK2; + PCICR |= _BV(2); +} +#endif +#endif // EI_SECTION_ASSIGNFUNCTIONSREGISTERS + +#ifdef EI_SECTION_DISABLEPINCHANGE +#ifndef EI_NOTPORTB +if (portNumber == PB) { + PCMSK0 &= ~portMask; + if (PCMSK0 == 0) { PCICR &= ~_BV(0); }; + risingPinsPORTB &= ~portMask; + fallingPinsPORTB &= ~portMask; +} +#endif +#ifndef EI_NOTPORTC +if (portNumber == PC) { + PCMSK1 &= ~portMask; + if (PCMSK1 == 0) { PCICR &= ~_BV(1); }; + risingPinsPORTC &= ~portMask; + fallingPinsPORTC &= ~portMask; +} +#endif +#ifndef EI_NOTPORTD +if (portNumber == PD) { + PCMSK2 &= ~portMask; + if (PCMSK2 == 0) { PCICR &= ~_BV(2); }; + risingPinsPORTD &= ~portMask; + fallingPinsPORTD &= ~portMask; +} +#endif +#endif // EI_SECTION_DISABLEPINCHANGE diff --git a/libraries/EnableInterrupt/utility/ei_PinChangeLeonardo.h b/libraries/EnableInterrupt/utility/ei_PinChangeLeonardo.h new file mode 100644 index 0000000..b5af1ed --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_PinChangeLeonardo.h @@ -0,0 +1,33 @@ +// ALL pin change interrupts are on Port B on Leonardo. +#ifdef EI_SECTION_RISING +#ifndef EI_NOTPORTB +risingPinsPORTB |= portMask; +#endif +#endif // EI_SECTION_RISING + +#ifdef EI_SECTION_FALLING +#ifndef EI_NOTPORTB +fallingPinsPORTB |= portMask; +#endif +#endif // EI_SECTION_FALLING + +#if defined EI_SECTION_ASSIGNFUNCTIONSREGISTERS +#ifndef EI_NOTPORTB +#ifndef NEEDFORSPEED +calculatedPointer=&portBFunctions.pinZero + portBitNumber; +*calculatedPointer = userFunction; +#endif +portSnapshotB=*portInputRegister(portNumber); +pcmsk=&PCMSK0; +PCICR |= _BV(0); +#endif +#endif // EI_SECTION_ASSIGNFUNCTIONSREGISTERS + +#ifdef EI_SECTION_DISABLEPINCHANGE +#ifndef EI_NOTPORTB +PCMSK0 &= ~portMask; +if (PCMSK0 == 0) { PCICR &= ~_BV(0); }; +risingPinsPORTB &= ~portMask; +fallingPinsPORTB &= ~portMask; +#endif +#endif // EI_SECTION_DISABLEPINCHANGE diff --git a/libraries/EnableInterrupt/utility/ei_PinChangeTiny24.h b/libraries/EnableInterrupt/utility/ei_PinChangeTiny24.h new file mode 100644 index 0000000..51f55e7 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_PinChangeTiny24.h @@ -0,0 +1,69 @@ +#ifdef EI_SECTION_RISING +#ifndef EI_NOTPORTA +if (portNumber==PA) { + risingPinsPORTA |= portMask; +} +#endif +#ifndef EI_NOTPORTB +if (portNumber==PB) { + risingPinsPORTB |= portMask; +} +#endif +#endif // EI_SECTION_RISING + +#ifdef EI_SECTION_FALLING +#ifndef EI_NOTPORTA +if (portNumber==PA) { + fallingPinsPORTA |= portMask; +} +#endif +#ifndef EI_NOTPORTB +if (portNumber==PB) { + fallingPinsPORTB |= portMask; +} +#endif +#endif // EI_SECTION_FALLING + +#if defined EI_SECTION_ASSIGNFUNCTIONSREGISTERS +#ifndef EI_NOTPORTA +if (portNumber==PA) { +#ifndef NEEDFORSPEED + calculatedPointer=&portAFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotA=*portInputRegister(portNumber); + pcmsk=&PCMSK0; + GIMSK |= _BV(4); +} +#endif +#ifndef EI_NOTPORTB +if (portNumber==PB) { +#ifndef NEEDFORSPEED + calculatedPointer=&portBFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotB=*portInputRegister(portNumber); + pcmsk=&PCMSK1; + GIMSK |= _BV(5); +} +#endif +#endif // EI_SECTION_ASSIGNFUNCTIONSREGISTERS + +#ifdef EI_SECTION_DISABLEPINCHANGE +#ifndef EI_NOTPORTA +if (portNumber == PA) { + PCMSK0 &= ~portMask; + if (PCMSK0 == 0) { GIMSK &= ~_BV(4); }; + risingPinsPORTA &= ~portMask; + fallingPinsPORTA &= ~portMask; +} +#endif +#ifndef EI_NOTPORTB +if (portNumber == PB) { + PCMSK1 &= ~portMask; + if (PCMSK1 == 0) { GIMSK &= ~_BV(5); }; + risingPinsPORTB &= ~portMask; + fallingPinsPORTB &= ~portMask; +} +#endif +#endif // EI_SECTION_DISABLEPINCHANGE diff --git a/libraries/EnableInterrupt/utility/ei_PinChangeTiny25.h b/libraries/EnableInterrupt/utility/ei_PinChangeTiny25.h new file mode 100644 index 0000000..818ad37 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_PinChangeTiny25.h @@ -0,0 +1,32 @@ +#ifdef EI_SECTION_RISING +#ifndef EI_NOTPORTB + risingPinsPORTB |= portMask; +#endif +#endif // EI_SECTION_RISING + +#ifdef EI_SECTION_FALLING +#ifndef EI_NOTPORTB + fallingPinsPORTB |= portMask; +#endif +#endif // EI_SECTION_FALLING + +#if defined EI_SECTION_ASSIGNFUNCTIONSREGISTERS +#ifndef EI_NOTPORTB +#ifndef NEEDFORSPEED + calculatedPointer=&portBFunctions.pinZero + portBitNumber; + *calculatedPointer = userFunction; +#endif + portSnapshotB=*portInputRegister(portNumber); + pcmsk=&PCMSK; + GIMSK |= _BV(5); +#endif +#endif // EI_SECTION_ASSIGNFUNCTIONSREGISTERS + +#ifdef EI_SECTION_DISABLEPINCHANGE +#ifndef EI_NOTPORTB + PCMSK &= ~portMask; + if (PCMSK == 0) { GIMSK &= ~_BV(5); }; + risingPinsPORTB &= ~portMask; + fallingPinsPORTB &= ~portMask; +#endif +#endif // EI_SECTION_DISABLEPINCHANGE diff --git a/libraries/EnableInterrupt/utility/ei_pindefs_speed.h b/libraries/EnableInterrupt/utility/ei_pindefs_speed.h new file mode 100644 index 0000000..93e9ef8 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_pindefs_speed.h @@ -0,0 +1,137 @@ +#ifdef INTERRUPT_FLAG_PIN0 +volatile uint8_t INTERRUPT_FLAG_PIN0 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN1 +volatile uint8_t INTERRUPT_FLAG_PIN1 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN2 +volatile uint8_t INTERRUPT_FLAG_PIN2 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN3 +volatile uint8_t INTERRUPT_FLAG_PIN3 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN4 +volatile uint8_t INTERRUPT_FLAG_PIN4 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN5 +volatile uint8_t INTERRUPT_FLAG_PIN5 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN6 +volatile uint8_t INTERRUPT_FLAG_PIN6 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN7 +volatile uint8_t INTERRUPT_FLAG_PIN7 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN8 +volatile uint8_t INTERRUPT_FLAG_PIN8 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN9 +volatile uint8_t INTERRUPT_FLAG_PIN9 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN10 +volatile uint8_t INTERRUPT_FLAG_PIN10 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN11 +volatile uint8_t INTERRUPT_FLAG_PIN11 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN12 +volatile uint8_t INTERRUPT_FLAG_PIN12 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN13 +volatile uint8_t INTERRUPT_FLAG_PIN13 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN14 +volatile uint8_t INTERRUPT_FLAG_PIN14 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN15 +volatile uint8_t INTERRUPT_FLAG_PIN15 = 0; +#endif + +#ifdef INTERRUPT_FLAG_PIN18 +volatile uint8_t INTERRUPT_FLAG_PIN18 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN19 +volatile uint8_t INTERRUPT_FLAG_PIN19 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN20 +volatile uint8_t INTERRUPT_FLAG_PIN20 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN21 +volatile uint8_t INTERRUPT_FLAG_PIN21 = 0; +#endif + +#ifdef INTERRUPT_FLAG_PINA0 +volatile uint8_t INTERRUPT_FLAG_PINA0 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA1 +volatile uint8_t INTERRUPT_FLAG_PINA1 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA2 +volatile uint8_t INTERRUPT_FLAG_PINA2 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA3 +volatile uint8_t INTERRUPT_FLAG_PINA3 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA4 +volatile uint8_t INTERRUPT_FLAG_PINA4 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA5 +volatile uint8_t INTERRUPT_FLAG_PINA5 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA8 +volatile uint8_t INTERRUPT_FLAG_PINA8 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA9 +volatile uint8_t INTERRUPT_FLAG_PINA9 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA10 +volatile uint8_t INTERRUPT_FLAG_PINA10 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA11 +volatile uint8_t INTERRUPT_FLAG_PINA11 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA12 +volatile uint8_t INTERRUPT_FLAG_PINA12 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA13 +volatile uint8_t INTERRUPT_FLAG_PINA13 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA14 +volatile uint8_t INTERRUPT_FLAG_PINA14 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINA15 +volatile uint8_t INTERRUPT_FLAG_PINA15 = 0; +#endif +#ifdef INTERRUPT_FLAG_PINSS +volatile uint8_t INTERRUPT_FLAG_PINSS = 0; +#endif +#ifdef INTERRUPT_FLAG_PINSCK +volatile uint8_t INTERRUPT_FLAG_PINSCK = 0; +#endif +#ifdef INTERRUPT_FLAG_PINMOSI +volatile uint8_t INTERRUPT_FLAG_PINMOSI = 0; +#endif +#ifdef INTERRUPT_FLAG_PINMISO +volatile uint8_t INTERRUPT_FLAG_PINMISO = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN70 +volatile uint8_t INTERRUPT_FLAG_PIN70 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN71 +volatile uint8_t INTERRUPT_FLAG_PIN71 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN72 +volatile uint8_t INTERRUPT_FLAG_PIN72 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN73 +volatile uint8_t INTERRUPT_FLAG_PIN73 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN74 +volatile uint8_t INTERRUPT_FLAG_PIN74 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN75 +volatile uint8_t INTERRUPT_FLAG_PIN75 = 0; +#endif +#ifdef INTERRUPT_FLAG_PIN76 +volatile uint8_t INTERRUPT_FLAG_PIN76 = 0; +#endif diff --git a/libraries/EnableInterrupt/utility/ei_porta_speed.h b/libraries/EnableInterrupt/utility/ei_porta_speed.h new file mode 100644 index 0000000..43d6e64 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_porta_speed.h @@ -0,0 +1,26 @@ +#if defined MIGHTY1284 +#ifdef INTERRUPT_FLAG_PIN24 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PIN24++; +#endif +#ifdef INTERRUPT_FLAG_PIN25 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PIN25++; +#endif +#ifdef INTERRUPT_FLAG_PIN26 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PIN26++; +#endif +#ifdef INTERRUPT_FLAG_PIN27 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PIN27++; +#endif +#ifdef INTERRUPT_FLAG_PIN28 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN28++; +#endif +#ifdef INTERRUPT_FLAG_PIN29 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN29++; +#endif +#ifdef INTERRUPT_FLAG_PIN30 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PIN30++; +#endif +#ifdef INTERRUPT_FLAG_PIN31 + if (interruptMask & _BV(7)) INTERRUPT_FLAG_PIN31++; +#endif +#endif diff --git a/libraries/EnableInterrupt/utility/ei_portb_speed.h b/libraries/EnableInterrupt/utility/ei_portb_speed.h new file mode 100644 index 0000000..334ab13 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_portb_speed.h @@ -0,0 +1,126 @@ +#if defined ARDUINO_AVR_ENVIRODIY_MAYFLY || defined ARDUINO_AVR_SODAQ_MBILI +#if defined INTERRUPT_FLAG_PIN8 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PIN8++; +#endif +#if defined INTERRUPT_FLAG_PIN9 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PIN9++; +#endif +#if defined INTERRUPT_FLAG_PIN10 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PIN10++; +#endif +#if defined INTERRUPT_FLAG_PIN11 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PIN11++; +#endif +#if defined INTERRUPT_FLAG_PIN12 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN12++; +#endif +#if defined INTERRUPT_FLAG_PIN13 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN13++; +#endif +#if defined INTERRUPT_FLAG_PIN14 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PIN14++; +#endif +#if defined INTERRUPT_FLAG_PIN15 + if (interruptMask & _BV(7)) INTERRUPT_FLAG_PIN15++; +#endif +#elif defined MIGHTY1284 +#ifdef INTERRUPT_FLAG_PIN0 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PIN0++; +#endif +#ifdef INTERRUPT_FLAG_PIN1 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PIN1++; +#endif +#ifdef INTERRUPT_FLAG_PIN2 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PIN2++; +#endif +#ifdef INTERRUPT_FLAG_PIN3 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PIN3++; +#endif +#ifdef INTERRUPT_FLAG_PIN4 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN4++; +#endif +#ifdef INTERRUPT_FLAG_PIN5 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN5++; +#endif +#ifdef INTERRUPT_FLAG_PIN6 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PIN6++; +#endif +#ifdef INTERRUPT_FLAG_PIN7 + if (interruptMask & _BV(7)) INTERRUPT_FLAG_PIN7++; +#endif +#endif + +#if defined LEONARDO +#ifdef INTERRUPT_FLAG_PINSS + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PINSS++; +#endif +#ifdef INTERRUPT_FLAG_PINSCK + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PINSCK++; +#endif +#ifdef INTERRUPT_FLAG_PINMOSI + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PINMOSI++; +#endif +#ifdef INTERRUPT_FLAG_PINMISO + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PINMISO++; +#endif +#ifdef INTERRUPT_FLAG_PIN8 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN8++; +#endif +#ifdef INTERRUPT_FLAG_PIN9 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN9++; +#endif +#ifdef INTERRUPT_FLAG_PIN10 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PIN10++; +#endif +#ifdef INTERRUPT_FLAG_PIN11 + if (interruptMask & _BV(7)) INTERRUPT_FLAG_PIN11++; +#endif +#endif + +#if defined ARDUINO_328 +#ifdef INTERRUPT_FLAG_PIN8 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PIN8++; +#endif +#ifdef INTERRUPT_FLAG_PIN9 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PIN9++; +#endif +#ifdef INTERRUPT_FLAG_PIN10 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PIN10++; +#endif +#ifdef INTERRUPT_FLAG_PIN11 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PIN11++; +#endif +#ifdef INTERRUPT_FLAG_PIN12 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN12++; +#endif +#ifdef INTERRUPT_FLAG_PIN13 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN13++; +#endif +#endif + +#if defined ARDUINO_MEGA +#ifdef INTERRUPT_FLAG_PINSS + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PINSS++; +#endif +#ifdef INTERRUPT_FLAG_PINSCK + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PINSCK++; +#endif +#ifdef INTERRUPT_FLAG_PINMOSI + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PINMOSI++; +#endif +#ifdef INTERRUPT_FLAG_PINMISO + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PINMISO++; +#endif +#ifdef INTERRUPT_FLAG_PIN10 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN10++; +#endif +#ifdef INTERRUPT_FLAG_PIN11 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN11++; +#endif +#ifdef INTERRUPT_FLAG_PIN12 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PIN12++; +#endif +#ifdef INTERRUPT_FLAG_PIN13 + if (interruptMask & _BV(7)) INTERRUPT_FLAG_PIN13++; +#endif +#endif diff --git a/libraries/EnableInterrupt/utility/ei_portc_speed.h b/libraries/EnableInterrupt/utility/ei_portc_speed.h new file mode 100644 index 0000000..33a1d8b --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_portc_speed.h @@ -0,0 +1,47 @@ +#if defined MIGHTY1284 +#if defined INTERRUPT_FLAG_PIN16 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PIN16++; +#endif +#if defined INTERRUPT_FLAG_PIN17 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PIN17++; +#endif +#if defined INTERRUPT_FLAG_PIN18 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PIN18++; +#endif +#if defined INTERRUPT_FLAG_PIN19 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PIN19++; +#endif +#if defined INTERRUPT_FLAG_PIN20 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN20++; +#endif +#if defined INTERRUPT_FLAG_PIN21 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN21++; +#endif +#if defined INTERRUPT_FLAG_PIN22 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PIN22++; +#endif +#if defined INTERRUPT_FLAG_PIN23 + if (interruptMask & _BV(7)) INTERRUPT_FLAG_PIN23++; +#endif +#endif + +#if defined ARDUINO_328 +#if defined INTERRUPT_FLAG_PINA0 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PINA0++; +#endif +#if defined INTERRUPT_FLAG_PINA1 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PINA1++; +#endif +#if defined INTERRUPT_FLAG_PINA2 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PINA2++; +#endif +#if defined INTERRUPT_FLAG_PINA3 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PINA3++; +#endif +#if defined INTERRUPT_FLAG_PINA4 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PINA4++; +#endif +#if defined INTERRUPT_FLAG_PINA5 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PINA5++; +#endif +#endif diff --git a/libraries/EnableInterrupt/utility/ei_portd_speed.h b/libraries/EnableInterrupt/utility/ei_portd_speed.h new file mode 100644 index 0000000..40595ae --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_portd_speed.h @@ -0,0 +1,78 @@ +#if defined ARDUINO_AVR_ENVIRODIY_MAYFLY || defined ARDUINO_AVR_SODAQ_MBILI +#ifdef INTERRUPT_FLAG_PIN0 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PIN0++; +#endif +#ifdef INTERRUPT_FLAG_PIN1 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PIN1++; +#endif +#ifdef INTERRUPT_FLAG_PIN2 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PIN2++; +#endif +#ifdef INTERRUPT_FLAG_PIN3 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PIN3++; +#endif +#ifdef INTERRUPT_FLAG_PIN4 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN4++; +#endif +#ifdef INTERRUPT_FLAG_PIN5 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN5++; +#endif +#ifdef INTERRUPT_FLAG_PIN6 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PIN6++; +#endif +#ifdef INTERRUPT_FLAG_PIN7 + if (interruptMask & _BV(7)) INTERRUPT_FLAG_PIN7++; +#endif +#elif defined MIGHTY1284 +#if defined INTERRUPT_FLAG_PIN8 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PIN8++; +#endif +#if defined INTERRUPT_FLAG_PIN9 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PIN9++; +#endif +#if defined INTERRUPT_FLAG_PIN10 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PIN10++; +#endif +#if defined INTERRUPT_FLAG_PIN11 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PIN11++; +#endif +#if defined INTERRUPT_FLAG_PIN12 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN12++; +#endif +#if defined INTERRUPT_FLAG_PIN13 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN13++; +#endif +#if defined INTERRUPT_FLAG_PIN14 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PIN14++; +#endif +#if defined INTERRUPT_FLAG_PIN15 + if (interruptMask & _BV(7)) INTERRUPT_FLAG_PIN15++; +#endif +#endif + +#if defined ARDUINO_328 +#if defined INTERRUPT_FLAG_PIN0 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PIN0++; +#endif +#if defined INTERRUPT_FLAG_PIN1 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PIN1++; +#endif +#if defined INTERRUPT_FLAG_PIN2 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PIN2++; +#endif +#if defined INTERRUPT_FLAG_PIN3 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PIN3++; +#endif +#if defined INTERRUPT_FLAG_PIN4 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN4++; +#endif +#if defined INTERRUPT_FLAG_PIN5 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN5++; +#endif +#if defined INTERRUPT_FLAG_PIN6 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PIN6++; +#endif +#if defined INTERRUPT_FLAG_PIN7 + if (interruptMask & _BV(7)) INTERRUPT_FLAG_PIN7++; +#endif +#endif diff --git a/libraries/EnableInterrupt/utility/ei_portj_speed.h b/libraries/EnableInterrupt/utility/ei_portj_speed.h new file mode 100644 index 0000000..c68ff09 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_portj_speed.h @@ -0,0 +1,24 @@ +#if defined ARDUINO_MEGA +#if defined INTERRUPT_FLAG_PIN15 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PIN15++; +#endif +#if defined INTERRUPT_FLAG_PIN14 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PIN14++; +#endif +#if defined INTERRUPT_FLAG_PIN70 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PIN70++; +#endif +#if defined INTERRUPT_FLAG_PIN71 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PIN71++; +#endif +#if defined INTERRUPT_FLAG_PIN72 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PIN72++; +#endif +#if defined INTERRUPT_FLAG_PIN73 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PIN73++; +#endif +#if defined INTERRUPT_FLAG_PIN74 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PIN74++; +#endif +#endif +// NOTE: 75 and 76 are "fake" External interrupt pins. diff --git a/libraries/EnableInterrupt/utility/ei_portk_speed.h b/libraries/EnableInterrupt/utility/ei_portk_speed.h new file mode 100644 index 0000000..f47d680 --- /dev/null +++ b/libraries/EnableInterrupt/utility/ei_portk_speed.h @@ -0,0 +1,26 @@ +#if defined ARDUINO_MEGA +#if defined INTERRUPT_FLAG_PINA8 + if (interruptMask & _BV(0)) INTERRUPT_FLAG_PINA8++; +#endif +#if defined INTERRUPT_FLAG_PINA9 + if (interruptMask & _BV(1)) INTERRUPT_FLAG_PINA9++; +#endif +#if defined INTERRUPT_FLAG_PINA10 + if (interruptMask & _BV(2)) INTERRUPT_FLAG_PINA10++; +#endif +#if defined INTERRUPT_FLAG_PINA11 + if (interruptMask & _BV(3)) INTERRUPT_FLAG_PINA11++; +#endif +#if defined INTERRUPT_FLAG_PINA12 + if (interruptMask & _BV(4)) INTERRUPT_FLAG_PINA12++; +#endif +#if defined INTERRUPT_FLAG_PINA13 + if (interruptMask & _BV(5)) INTERRUPT_FLAG_PINA13++; +#endif +#if defined INTERRUPT_FLAG_PINA14 + if (interruptMask & _BV(6)) INTERRUPT_FLAG_PINA14++; +#endif +#if defined INTERRUPT_FLAG_PINA15 + if (interruptMask & _BV(7)) INTERRUPT_FLAG_PINA15++; +#endif +#endif diff --git a/libraries/PID/PID_v1.cpp b/libraries/PID/PID_v1.cpp new file mode 100644 index 0000000..285de13 --- /dev/null +++ b/libraries/PID/PID_v1.cpp @@ -0,0 +1,224 @@ +/********************************************************************************************** + * Arduino PID Library - Version 1.1.1 + * by Brett Beauregard brettbeauregard.com + * + * This Library is licensed under a GPLv3 License + **********************************************************************************************/ + +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include + +/*Constructor (...)********************************************************* + * The parameters specified here are those for for which we can't set up + * reliable defaults, so we need to have the user set them. + ***************************************************************************/ +PID::PID(double* Input, double* Output, double* Setpoint, + double Kp, double Ki, double Kd, int POn, int ControllerDirection) +{ + myOutput = Output; + myInput = Input; + mySetpoint = Setpoint; + inAuto = false; + + PID::SetOutputLimits(0, 255); //default output limit corresponds to + //the arduino pwm limits + + SampleTime = 100; //default Controller Sample Time is 0.1 seconds + + PID::SetControllerDirection(ControllerDirection); + PID::SetTunings(Kp, Ki, Kd, POn); + + lastTime = millis()-SampleTime; +} + +/*Constructor (...)********************************************************* + * To allow backwards compatability for v1.1, or for people that just want + * to use Proportional on Error without explicitly saying so + ***************************************************************************/ + +PID::PID(double* Input, double* Output, double* Setpoint, + double Kp, double Ki, double Kd, int ControllerDirection) + :PID::PID(Input, Output, Setpoint, Kp, Ki, Kd, P_ON_E, ControllerDirection) +{ + +} + + +/* Compute() ********************************************************************** + * This, as they say, is where the magic happens. this function should be called + * every time "void loop()" executes. the function will decide for itself whether a new + * pid Output needs to be computed. returns true when the output is computed, + * false when nothing has been done. + **********************************************************************************/ +bool PID::Compute() +{ + if(!inAuto) return false; + unsigned long now = millis(); + unsigned long timeChange = (now - lastTime); + if(timeChange>=SampleTime) + { + /*Compute all the working error variables*/ + double input = *myInput; + double error = *mySetpoint - input; + double dInput = (input - lastInput); + outputSum+= (ki * error); + + /*Add Proportional on Measurement, if P_ON_M is specified*/ + if(!pOnE) outputSum-= kp * dInput; + + if(outputSum > outMax) outputSum= outMax; + else if(outputSum < outMin) outputSum= outMin; + + /*Add Proportional on Error, if P_ON_E is specified*/ + double output; + if(pOnE) output = kp * error; + else output = 0; + + /*Compute Rest of PID Output*/ + output += outputSum - kd * dInput; + + if(output > outMax) output = outMax; + else if(output < outMin) output = outMin; + *myOutput = output; + + /*Remember some variables for next time*/ + lastInput = input; + lastTime = now; + return true; + } + else return false; +} + +/* SetTunings(...)************************************************************* + * This function allows the controller's dynamic performance to be adjusted. + * it's called automatically from the constructor, but tunings can also + * be adjusted on the fly during normal operation + ******************************************************************************/ +void PID::SetTunings(double Kp, double Ki, double Kd, int POn) +{ + if (Kp<0 || Ki<0 || Kd<0) return; + + pOn = POn; + pOnE = POn == P_ON_E; + + dispKp = Kp; dispKi = Ki; dispKd = Kd; + + double SampleTimeInSec = ((double)SampleTime)/1000; + kp = Kp; + ki = Ki * SampleTimeInSec; + kd = Kd / SampleTimeInSec; + + if(controllerDirection ==REVERSE) + { + kp = (0 - kp); + ki = (0 - ki); + kd = (0 - kd); + } +} + +/* SetTunings(...)************************************************************* + * Set Tunings using the last-rembered POn setting + ******************************************************************************/ +void PID::SetTunings(double Kp, double Ki, double Kd){ + SetTunings(Kp, Ki, Kd, pOn); +} + +/* SetSampleTime(...) ********************************************************* + * sets the period, in Milliseconds, at which the calculation is performed + ******************************************************************************/ +void PID::SetSampleTime(int NewSampleTime) +{ + if (NewSampleTime > 0) + { + double ratio = (double)NewSampleTime + / (double)SampleTime; + ki *= ratio; + kd /= ratio; + SampleTime = (unsigned long)NewSampleTime; + } +} + +/* SetOutputLimits(...)**************************************************** + * This function will be used far more often than SetInputLimits. while + * the input to the controller will generally be in the 0-1023 range (which is + * the default already,) the output will be a little different. maybe they'll + * be doing a time window and will need 0-8000 or something. or maybe they'll + * want to clamp it from 0-125. who knows. at any rate, that can all be done + * here. + **************************************************************************/ +void PID::SetOutputLimits(double Min, double Max) +{ + if(Min >= Max) return; + outMin = Min; + outMax = Max; + + if(inAuto) + { + if(*myOutput > outMax) *myOutput = outMax; + else if(*myOutput < outMin) *myOutput = outMin; + + if(outputSum > outMax) outputSum= outMax; + else if(outputSum < outMin) outputSum= outMin; + } +} + +/* SetMode(...)**************************************************************** + * Allows the controller Mode to be set to manual (0) or Automatic (non-zero) + * when the transition from manual to auto occurs, the controller is + * automatically initialized + ******************************************************************************/ +void PID::SetMode(int Mode) +{ + bool newAuto = (Mode == AUTOMATIC); + if(newAuto && !inAuto) + { /*we just went from manual to auto*/ + PID::Initialize(); + } + inAuto = newAuto; +} + +/* Initialize()**************************************************************** + * does all the things that need to happen to ensure a bumpless transfer + * from manual to automatic mode. + ******************************************************************************/ +void PID::Initialize() +{ + outputSum = *myOutput; + lastInput = *myInput; + if(outputSum > outMax) outputSum = outMax; + else if(outputSum < outMin) outputSum = outMin; +} + +/* SetControllerDirection(...)************************************************* + * The PID will either be connected to a DIRECT acting process (+Output leads + * to +Input) or a REVERSE acting process(+Output leads to -Input.) we need to + * know which one, because otherwise we may increase the output when we should + * be decreasing. This is called from the constructor. + ******************************************************************************/ +void PID::SetControllerDirection(int Direction) +{ + if(inAuto && Direction !=controllerDirection) + { + kp = (0 - kp); + ki = (0 - ki); + kd = (0 - kd); + } + controllerDirection = Direction; +} + +/* Status Funcions************************************************************* + * Just because you set the Kp=-1 doesn't mean it actually happened. these + * functions query the internal state of the PID. they're here for display + * purposes. this are the functions the PID Front-end uses for example + ******************************************************************************/ +double PID::GetKp(){ return dispKp; } +double PID::GetKi(){ return dispKi;} +double PID::GetKd(){ return dispKd;} +int PID::GetMode(){ return inAuto ? AUTOMATIC : MANUAL;} +int PID::GetDirection(){ return controllerDirection;} + diff --git a/libraries/PID/PID_v1.h b/libraries/PID/PID_v1.h new file mode 100644 index 0000000..db710bf --- /dev/null +++ b/libraries/PID/PID_v1.h @@ -0,0 +1,90 @@ +#ifndef PID_v1_h +#define PID_v1_h +#define LIBRARY_VERSION 1.1.1 + +class PID +{ + + + public: + + //Constants used in some of the functions below + #define AUTOMATIC 1 + #define MANUAL 0 + #define DIRECT 0 + #define REVERSE 1 + #define P_ON_M 0 + #define P_ON_E 1 + + //commonly used functions ************************************************************************** + PID(double*, double*, double*, // * constructor. links the PID to the Input, Output, and + double, double, double, int, int);// Setpoint. Initial tuning parameters are also set here. + // (overload for specifying proportional mode) + + PID(double*, double*, double*, // * constructor. links the PID to the Input, Output, and + double, double, double, int); // Setpoint. Initial tuning parameters are also set here + + void SetMode(int Mode); // * sets PID to either Manual (0) or Auto (non-0) + + bool Compute(); // * performs the PID calculation. it should be + // called every time loop() cycles. ON/OFF and + // calculation frequency can be set using SetMode + // SetSampleTime respectively + + void SetOutputLimits(double, double); // * clamps the output to a specific range. 0-255 by default, but + // it's likely the user will want to change this depending on + // the application + + + + //available but not commonly used functions ******************************************************** + void SetTunings(double, double, // * While most users will set the tunings once in the + double); // constructor, this function gives the user the option + // of changing tunings during runtime for Adaptive control + void SetTunings(double, double, // * overload for specifying proportional mode + double, int); + + void SetControllerDirection(int); // * Sets the Direction, or "Action" of the controller. DIRECT + // means the output will increase when error is positive. REVERSE + // means the opposite. it's very unlikely that this will be needed + // once it is set in the constructor. + void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which + // the PID calculation is performed. default is 100 + + + + //Display functions **************************************************************** + double GetKp(); // These functions query the pid for interal values. + double GetKi(); // they were created mainly for the pid front-end, + double GetKd(); // where it's important to know what is actually + int GetMode(); // inside the PID. + int GetDirection(); // + + private: + void Initialize(); + + double dispKp; // * we'll hold on to the tuning parameters in user-entered + double dispKi; // format for display purposes + double dispKd; // + + double kp; // * (P)roportional Tuning Parameter + double ki; // * (I)ntegral Tuning Parameter + double kd; // * (D)erivative Tuning Parameter + + int controllerDirection; + int pOn; + + double *myInput; // * Pointers to the Input, Output, and Setpoint variables + double *myOutput; // This creates a hard link between the variables and the + double *mySetpoint; // PID, freeing the user from having to constantly tell us + // what these values are. with pointers we'll just know. + + unsigned long lastTime; + double outputSum, lastInput; + + unsigned long SampleTime; + double outMin, outMax; + bool inAuto, pOnE; +}; +#endif + diff --git a/libraries/PID/README.txt b/libraries/PID/README.txt new file mode 100644 index 0000000..9b9cb83 --- /dev/null +++ b/libraries/PID/README.txt @@ -0,0 +1,11 @@ +*************************************************************** +* Arduino PID Library - Version 1.2.0 +* by Brett Beauregard brettbeauregard.com +* +* This Library is licensed under the MIT License +*************************************************************** + + - For an ultra-detailed explanation of why the code is the way it is, please visit: + http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/ + + - For function documentation see: http://playground.arduino.cc/Code/PIDLibrary diff --git a/libraries/PID/examples/PID_AdaptiveTunings/PID_AdaptiveTunings.ino b/libraries/PID/examples/PID_AdaptiveTunings/PID_AdaptiveTunings.ino new file mode 100644 index 0000000..94f3faf --- /dev/null +++ b/libraries/PID/examples/PID_AdaptiveTunings/PID_AdaptiveTunings.ino @@ -0,0 +1,56 @@ +/******************************************************** + * PID Adaptive Tuning Example + * One of the benefits of the PID library is that you can + * change the tuning parameters at any time. this can be + * helpful if we want the controller to be agressive at some + * times, and conservative at others. in the example below + * we set the controller to use Conservative Tuning Parameters + * when we're near setpoint and more agressive Tuning + * Parameters when we're farther away. + ********************************************************/ + +#include + +#define PIN_INPUT 0 +#define PIN_OUTPUT 3 + +//Define Variables we'll be connecting to +double Setpoint, Input, Output; + +//Define the aggressive and conservative Tuning Parameters +double aggKp=4, aggKi=0.2, aggKd=1; +double consKp=1, consKi=0.05, consKd=0.25; + +//Specify the links and initial tuning parameters +PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT); + +void setup() +{ + //initialize the variables we're linked to + Input = analogRead(PIN_INPUT); + Setpoint = 100; + + //turn the PID on + myPID.SetMode(AUTOMATIC); +} + +void loop() +{ + Input = analogRead(PIN_INPUT); + + double gap = abs(Setpoint-Input); //distance away from setpoint + if (gap < 10) + { //we're close to setpoint, use conservative tuning parameters + myPID.SetTunings(consKp, consKi, consKd); + } + else + { + //we're far from setpoint, use aggressive tuning parameters + myPID.SetTunings(aggKp, aggKi, aggKd); + } + + myPID.Compute(); + analogWrite(PIN_OUTPUT, Output); +} + + diff --git a/libraries/PID/examples/PID_Basic/PID_Basic.ino b/libraries/PID/examples/PID_Basic/PID_Basic.ino new file mode 100644 index 0000000..8028b58 --- /dev/null +++ b/libraries/PID/examples/PID_Basic/PID_Basic.ino @@ -0,0 +1,35 @@ +/******************************************************** + * PID Basic Example + * Reading analog input 0 to control analog PWM output 3 + ********************************************************/ + +#include + +#define PIN_INPUT 0 +#define PIN_OUTPUT 3 + +//Define Variables we'll be connecting to +double Setpoint, Input, Output; + +//Specify the links and initial tuning parameters +double Kp=2, Ki=5, Kd=1; +PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); + +void setup() +{ + //initialize the variables we're linked to + Input = analogRead(PIN_INPUT); + Setpoint = 100; + + //turn the PID on + myPID.SetMode(AUTOMATIC); +} + +void loop() +{ + Input = analogRead(PIN_INPUT); + myPID.Compute(); + analogWrite(PIN_OUTPUT, Output); +} + + diff --git a/libraries/PID/examples/PID_PonM/PID_PonM.ino b/libraries/PID/examples/PID_PonM/PID_PonM.ino new file mode 100644 index 0000000..121c161 --- /dev/null +++ b/libraries/PID/examples/PID_PonM/PID_PonM.ino @@ -0,0 +1,36 @@ +/******************************************************** + * PID Proportional on measurement Example + * Setting the PID to use Proportional on measurement will + * make the output move more smoothly when the setpoint + * is changed. In addition, it can eliminate overshoot + * in certain processes like sous-vides. + ********************************************************/ + +#include + +//Define Variables we'll be connecting to +double Setpoint, Input, Output; + +//Specify the links and initial tuning parameters +PID myPID(&Input, &Output, &Setpoint,2,5,1,P_ON_M, DIRECT); //P_ON_M specifies that Proportional on Measurement be used + //P_ON_E (Proportional on Error) is the default behavior + +void setup() +{ + //initialize the variables we're linked to + Input = analogRead(0); + Setpoint = 100; + + //turn the PID on + myPID.SetMode(AUTOMATIC); +} + +void loop() +{ + Input = analogRead(0); + myPID.Compute(); + analogWrite(3,Output); +} + + + diff --git a/libraries/PID/examples/PID_RelayOutput/PID_RelayOutput.ino b/libraries/PID/examples/PID_RelayOutput/PID_RelayOutput.ino new file mode 100644 index 0000000..17fbe1a --- /dev/null +++ b/libraries/PID/examples/PID_RelayOutput/PID_RelayOutput.ino @@ -0,0 +1,64 @@ +/******************************************************** + * PID RelayOutput Example + * Same as basic example, except that this time, the output + * is going to a digital pin which (we presume) is controlling + * a relay. the pid is designed to Output an analog value, + * but the relay can only be On/Off. + * + * to connect them together we use "time proportioning + * control" it's essentially a really slow version of PWM. + * first we decide on a window size (5000mS say.) we then + * set the pid to adjust its output between 0 and that window + * size. lastly, we add some logic that translates the PID + * output into "Relay On Time" with the remainder of the + * window being "Relay Off Time" + ********************************************************/ + +#include + +#define PIN_INPUT 0 +#define RELAY_PIN 6 + +//Define Variables we'll be connecting to +double Setpoint, Input, Output; + +//Specify the links and initial tuning parameters +double Kp=2, Ki=5, Kd=1; +PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); + +int WindowSize = 5000; +unsigned long windowStartTime; + +void setup() +{ + windowStartTime = millis(); + + //initialize the variables we're linked to + Setpoint = 100; + + //tell the PID to range between 0 and the full window size + myPID.SetOutputLimits(0, WindowSize); + + //turn the PID on + myPID.SetMode(AUTOMATIC); +} + +void loop() +{ + Input = analogRead(PIN_INPUT); + myPID.Compute(); + + /************************************************ + * turn the output pin on/off based on pid output + ************************************************/ + if (millis() - windowStartTime > WindowSize) + { //time to shift the Relay Window + windowStartTime += WindowSize; + } + if (Output < millis() - windowStartTime) digitalWrite(RELAY_PIN, HIGH); + else digitalWrite(RELAY_PIN, LOW); + +} + + + diff --git a/libraries/PID/keywords.txt b/libraries/PID/keywords.txt new file mode 100644 index 0000000..330d7fc --- /dev/null +++ b/libraries/PID/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map For PID Library +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +PID KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +SetMode KEYWORD2 +Compute KEYWORD2 +SetOutputLimits KEYWORD2 +SetTunings KEYWORD2 +SetControllerDirection KEYWORD2 +SetSampleTime KEYWORD2 +GetKp KEYWORD2 +GetKi KEYWORD2 +GetKd KEYWORD2 +GetMode KEYWORD2 +GetDirection KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +AUTOMATIC LITERAL1 +MANUAL LITERAL1 +DIRECT LITERAL1 +REVERSE LITERAL1 +P_ON_E LITERAL1 +P_ON_M LITERAL1 diff --git a/libraries/PID/library.json b/libraries/PID/library.json new file mode 100644 index 0000000..cf2510c --- /dev/null +++ b/libraries/PID/library.json @@ -0,0 +1,19 @@ +{ + "name": "PID", + "keywords": "PID, controller, signal", + "description": "A PID controller seeks to keep some input variable close to a desired setpoint by adjusting an output. The way in which it does this can be 'tuned' by adjusting three parameters (P,I,D).", + "url": "http://playground.arduino.cc/Code/PIDLibrary", + "include": "PID_v1", + "authors": + [ + { + "name": "Brett Beauregard" + } + ], + "repository": + { + "type": "git", + "url": "https://github.com/br3ttb/Arduino-PID-Library.git" + }, + "frameworks": "arduino" +} diff --git a/libraries/PID/library.properties b/libraries/PID/library.properties new file mode 100644 index 0000000..baf51b6 --- /dev/null +++ b/libraries/PID/library.properties @@ -0,0 +1,9 @@ +name=PID +version=1.2.0 +author=Brett Beauregard +maintainer=Brett Beauregard +sentence=PID controller +paragraph=A PID controller seeks to keep some input variable close to a desired setpoint by adjusting an output. The way in which it does this can be 'tuned' by adjusting three parameters (P,I,D). +category=Signal Input/Output +url=http://playground.arduino.cc/Code/PIDLibrary +architectures=* diff --git a/libraries/SimplePID-master/LICENSE b/libraries/SimplePID-master/LICENSE new file mode 100644 index 0000000..4d54ce6 --- /dev/null +++ b/libraries/SimplePID-master/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2015, Mark Rose +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of bsd-license nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/libraries/SimplePID-master/README.asciidoc b/libraries/SimplePID-master/README.asciidoc new file mode 100644 index 0000000..d07321c --- /dev/null +++ b/libraries/SimplePID-master/README.asciidoc @@ -0,0 +1,93 @@ += SimplePID + +A PID controller library independent of run environment, but one which works well with Arduino. + +== Installation + +To install the library into your Arduino installation, go to the _Releases_ tab and download +the latest release. This will be a ZIP file called `SimplePID-__version__.zip`, for some +version number. Unzip this into your `__sketchbook__/libraries` folder, where _sketchbook_ +is the root of your Arduino sketches. On OS X and Windows it is usually `~/Documents/Arduino`. +This will create a directory called `SimplePID-__version__`. Rename that directory to +`SimplePID`. + +You should then have a directory under your _sketchbook_ directory containing the library files at: + + libraries/SimplePID/ + +== Usage + +To use the SimplePID library, add `#include ` to the includes in your sketch. +Then create an instance of the PID controller by defining a global variable: + +---- +SimplePID myPID(pConstant, iConstant, dConstant); +---- + +(Replace `pConstant`, `iConstant`, and `dConstant` with the proportional, integral, and differential +constants you desire.) For a P-controller, set the integral and differential constants to zero, +for example. + +=== Setting the Target + +The target value you want to track is usually called the _setpoint_. At any time you can change +the setpoint by calling `SimplePID.setSetPoint(someValue)`. For example, using the PID controller +defined in the example above, we could set the target at 3.4 as follows: + +---- +myPID.setSetPoint(3.4); +---- + +=== Getting the Control Value + +Your code needs to have some way of keeping track of time in order to determine the delta +time from the last control value. A recommended way of doing that is farther down. You also +need to have a way of sensing the actual error value, +the difference in speed of the motor versus the desired value, or the process error. +Once you have the actual error value and the delta time, in seconds, you get the control value +to use like this: + +---- +float controlValue = myPID.getControlValue(actualError, dt); +---- + +For a motor, you will usually add the control value to the current control value and change +the motor speed. + +=== Keeping Track of Delta Time + +One way of doing that is as follows: + +---- +#include + +SimplePID myPID(...); +unsigned long lastLoopTime; + +void setup() { + ... + lastLoopTime = micros(); +} + +void loop() { + delay(howeverLongYouLike); + + float error = ... some way of getting the actual error value ... + + unsigned long curLoopTime = micros(); + float dt = (curLoopTime - lastLoopTime) / 1E6; + + float controlValue = myPID.getControlValue(error, dt); + ... code to control the motor or other process ... + + lastLoopTime = curLoopTime; +} +---- + +In this case `dt` is set to the delta time since the last control, in seconds. + +== An Example + +There is an example of using the library to investigate PID tunings for a motor. It is specific +to the DFRobot Romeo v2 Arduino board and motor driver, but should give a reasonable impression +of how to use `SimplePID`. Open that sketch by going to Files > Examples > SimplePID > RomeoPIDTest. diff --git a/libraries/SimplePID-master/SimplePID.cpp b/libraries/SimplePID-master/SimplePID.cpp new file mode 100644 index 0000000..2b94075 --- /dev/null +++ b/libraries/SimplePID-master/SimplePID.cpp @@ -0,0 +1,61 @@ +#include +#include "SimplePID.h" + +SimplePID::SimplePID(float Kp, float Ki, float Kd) { + this->Kp = Kp; + this->Ki = Ki; + this->Kd = Kd; + + minOutput = -FLT_MAX; + maxOutput = FLT_MAX; + + sumError = 0.0; + lastActual = 0.0; +} + +void SimplePID::setConstants(float Kp, float Ki, float Kd) { + this->Kp = Kp; + this->Ki = Ki; + this->Kd = Kd; +} + +void SimplePID::setOutputRange(float minOutput, float maxOutput) { + this->minOutput = minOutput; + this->maxOutput = maxOutput; +} + +void SimplePID::setSetPoint(float setPoint) { + this->setPoint = setPoint; + sumError = 0.0; +} + +float SimplePID::getCumulativeError() { + return sumError; +} + +void SimplePID::clearCumulativeError() { + sumError = 0.0; +} + +float SimplePID::getControlValue(float actual, float dt) { + float error = setPoint - actual; + + float newSum = sumError + error*dt; + + // The derivative is calculated by assuming the two setpoints are + // equal. This works better when changing the setpoint because the + // derivative error does not suddenly increase. + float dErrorDt = (lastActual - actual) / dt; + lastActual = actual; + + float output = Kp*error + Ki*sumError + Kd*dErrorDt; + + if (output >= maxOutput) { + return maxOutput; + } else if (output <= minOutput) { + return minOutput; + } else { + sumError = newSum; + return output; + } +} diff --git a/libraries/SimplePID-master/SimplePID.h b/libraries/SimplePID-master/SimplePID.h new file mode 100644 index 0000000..b6756a2 --- /dev/null +++ b/libraries/SimplePID-master/SimplePID.h @@ -0,0 +1,36 @@ +// SimplePID.h - Definitions for the simple PID library. + +#ifndef SIMPLE_PID_H +#define SIMPLE_PID_H + +class SimplePID { + public: + + SimplePID(float Kp, float Ki, float Kd); + + void setConstants(float Kp, float Ki, float Kd); + + void setOutputRange(float minOutput, float maxOutput); + + void setSetPoint(float setPoint); + + float getCumulativeError(); + + void clearCumulativeError(); + + float getControlValue(float actual, float dt); + + private: + + float Kp; + float Ki; + float Kd; + float setPoint; + float minOutput; + float maxOutput; + float lastActual; + float sumError; + +}; + +#endif SIMPLE_PID_H diff --git a/libraries/SimplePID-master/examples/AStarPIDTest/AStarPIDTest.ino b/libraries/SimplePID-master/examples/AStarPIDTest/AStarPIDTest.ino new file mode 100644 index 0000000..1589ca7 --- /dev/null +++ b/libraries/SimplePID-master/examples/AStarPIDTest/AStarPIDTest.ino @@ -0,0 +1,296 @@ +// AStarPIDTest - Test the PID control for an AStar-based robot. +// +// To gather PID tuning data for graphing, put the robot on blocks, then +// start this program and open a Serial Monitor. Press S4 to start both +// motors, let them come to a steady speed, then press S4 to stop the +// motors. Copy the Serial output to a spreadsheet and plot target speed and +// current speed versus time. You should see a classic PID controller graph +// with some overshoot. + +#include +#include +#include + +// Motor parameters. These are based on a Pololu #2285 motor with 48cpr +// encoder. +const float GEAR_RATIO = 210.59; +const float ENCODER_CPR = 12; + +// Number of encoder ticks per revolution of the wheel. +const float TICKS_PER_REV = GEAR_RATIO * ENCODER_CPR; + +// Maximum desired motor speed. Pololu #2285 are rated for 130rpm, but we +// don't drive them with enough voltage to achieve that. +const float MAX_REVS_PER_SEC = 100.0 / 60.0; + +// Use 60% of maximum speed for PID tuning. +const int PID_TUNING_TICKS_PER_SEC = 0.6 * MAX_REVS_PER_SEC * TICKS_PER_REV; + +// DFRobot Romeo v2 and BLE PIN assignments. + +const int ONBOARD_SWITCH_PIN = A7; + +// Pins for the Pololu motor encoder outputs. +const int M1_A = 7; +const int M1_B = 11; +const int M2_A = 15; +const int M2_B = 16; + +// Minimum motor control value. Motor output below this will stall. +const int MIN_MOTOR_CMD = 10; + +// Maximum motor control value. +const int MAX_MOTOR_CMD = 400; + +AStar32U4Motors motors; + +// These objects provide access to the A-Star's on-board +// buttons. We will only use buttonA. +AStar32U4ButtonA buttonA; +AStar32U4ButtonB buttonB; +AStar32U4ButtonC buttonC; + +enum { NO_BUTTON, BUTTON_A, BUTTON_B, BUTTON_C }; + +int leftSpeedTarget = 0; +int rightSpeedTarget = 0; + +volatile long leftTicks; +volatile long rightTicks; + +long lastLeftTicks = 0; +long lastRightTicks = 0; + +int leftMotorCmd = 0; +int rightMotorCmd = 0; + +unsigned long lastLoopTime; + +unsigned long lastSwitchTime; + +float loopTime = 0.0; + +// Ziegler-Nichols tuning. See this Wikipedia article for details: +// https://en.wikipedia.org/wiki/PID_controller#Loop_tuning +// To tune the controller, set USE_KU_ONLY to 1 and increase Ku +// until oscillation occurs, and set Tu to the oscillation period +// in seconds. Then set USE_KU_ONLY to zero to use the +// Ziegler-Nichols tune. To get a less agressive tune, set LESS_AGGRESSIVE +// to 1. + +// Set to 1 to use Ku only, to determine oscillation point. +#define USE_KU_ONLY 0 + +const float Ku = .15; +const float Tu = .1142857143; + +#define MANUAL_TUNE 1 +#define LESS_AGGRESSIVE 0 + +#if MANUAL_TUNE +// Found empirically to rapidly converge with little overshoot. +// There is no integral constant, but not needed when driving +// on flat ground, and when the heading is otherwise controlled +// by higher-level software. (I.e., there's no need to catch up +// for past errors.) +const float Kp = 0.07; +const float Ki = 0.0; +const float Kd = 0.001; +#elif !LESS_AGGRESSIVE +const float Kp = 0.6*Ku; +const float Ki = 2*Kp/Tu; +const float Kd = Kp*Tu/8; +#else +const float Kp = 0.2*Ku; +const float Ki = 2*Kp/Tu; +const float Kd = Kp*Tu/3; +#endif + +#if USE_KU_ONLY +SimplePID leftController = SimplePID(Ku, 0, 0); +SimplePID rightController = SimplePID(Ku, 0, 0); +#else +SimplePID leftController = SimplePID(Kp, Ki, Kd); +SimplePID rightController = SimplePID(Kp, Ki, Kd); +#endif + +// Sets up the serial output and the motor control pins, and attaches +// interrupt handlers to the pins on which we will read the encoder +// phototransistor values. +void setup() { + Serial.begin(115200); + delay(3000); + + enableInterrupt(M1_A, leftAChange, CHANGE); + enableInterrupt(M1_B, leftBChange, CHANGE); + enableInterrupt(M2_A, rightAChange, CHANGE); + enableInterrupt(M2_B, rightBChange, CHANGE); + +// Serial.print("Time (s)\t"); + Serial.print("Left Target\tLeft Speed"); +// Serial.print("\tLeft Cum Error\tLeft Motor\t"); + Serial.print("\tRight Target\tRight Speed"); +// Serial.print("\tRight Cum Error\tRight Motor"); + Serial.println(); + + lastLoopTime = micros(); + lastSwitchTime = millis(); + + leftTicks = rightTicks = 0; +} + +// Loops forever showing the motor speeds and errors since the last loop, +// and adjusts the target speeds depending on whether the user is pressing +// switches S2 through S5, as indicated in the code below. +void loop() { + delay(15); + + unsigned long curLoopTime = micros(); + noInterrupts(); + long curLeftTicks = leftTicks; + long curRightTicks = rightTicks; + interrupts(); + + float dt = (curLoopTime - lastLoopTime) / 1E6; + + float leftSpeed = (curLeftTicks - lastLeftTicks) / dt; + float rightSpeed = (curRightTicks - lastRightTicks) / dt; + + int leftControl = leftController.getControlValue(leftSpeed, dt); + leftMotorCmd += min(MAX_MOTOR_CMD, leftControl); + leftMotorCmd = constrain(leftMotorCmd, -MAX_MOTOR_CMD, MAX_MOTOR_CMD); + if (leftMotorCmd > 0) { + leftMotorCmd = max(leftMotorCmd, MIN_MOTOR_CMD); + } + + int rightControl = rightController.getControlValue(rightSpeed, dt); + rightMotorCmd += min(MAX_MOTOR_CMD, rightControl); + rightMotorCmd = constrain(rightMotorCmd, -MAX_MOTOR_CMD, MAX_MOTOR_CMD); + if (rightMotorCmd > 0) { + rightMotorCmd = max(rightMotorCmd, MIN_MOTOR_CMD); + } + + // Coast to a stop if target is zero. + if (leftSpeedTarget == 0) { + leftMotorCmd = 0; + } + if (rightSpeedTarget == 0) { + rightMotorCmd = 0; + } + + setSpeed(leftMotorCmd, rightMotorCmd); + + if (leftSpeedTarget > 0 || leftSpeed > 0 || rightSpeedTarget > 0 || rightSpeed > 0) { +// Serial.print(loopTime, 3); +// Serial.print("\t"); + Serial.print(leftSpeedTarget); + Serial.print("\t"); + Serial.print(leftSpeed); + Serial.print("\t"); +// Serial.print(leftController.getCumulativeError()); +// Serial.print("\t"); +// Serial.print(leftMotorCmd); +// Serial.print("\t"); + + Serial.print(rightSpeedTarget); + Serial.print("\t"); + Serial.print(rightSpeed); + Serial.print("\t"); +// Serial.print(rightController.getCumulativeError()); +// Serial.print("\t"); +// Serial.print(rightMotorCmd); +// Serial.print("\t"); + + Serial.println(); + + loopTime += dt; +} + + // Ignore switches for a short time after pressing, to avoid bounce. + if (curLoopTime - lastSwitchTime > 0.5*1E6) { + int switchValue = readSwitch(); + if (switchValue > 0) { + lastSwitchTime = curLoopTime; + + switch (switchValue) { + case BUTTON_A: + // Left motor on/off. + leftSpeedTarget = (leftSpeedTarget==0 ? PID_TUNING_TICKS_PER_SEC : 0); + break; + case BUTTON_B: + // Right motor on/off. + rightSpeedTarget = (rightSpeedTarget==0 ? PID_TUNING_TICKS_PER_SEC : 0); + break; + case BUTTON_C: + // Both motors on/off. + leftSpeedTarget = (leftSpeedTarget==0 ? PID_TUNING_TICKS_PER_SEC : 0); + rightSpeedTarget = (rightSpeedTarget==0 ? PID_TUNING_TICKS_PER_SEC : 0); + break; + default: + // no change in speed + break; + } + + leftController.setSetPoint(leftSpeedTarget); + rightController.setSetPoint(rightSpeedTarget); + } + } + + lastLeftTicks = curLeftTicks; + lastRightTicks = curRightTicks; + lastLoopTime = curLoopTime; +} + +void waitForSwitch1() { + while (readSwitch() != 1) { + // do nothing + } +} + +void setSpeed(int leftSpeed, int rightSpeed) { + motors.setSpeeds(leftSpeed, rightSpeed); +} + +void leftAChange() { + if (digitalRead(M1_A) == digitalRead(M1_B)) { + ++leftTicks; + } else { + --leftTicks; + } +} + +void leftBChange() { + if (digitalRead(M1_A) != digitalRead(M1_B)) { + ++leftTicks; + } else { + --leftTicks; + } +} + +void rightAChange() { + if (digitalRead(M2_A) != digitalRead(M2_B)) { + ++rightTicks; + } else { + --rightTicks; + } +} + +void rightBChange() { + if (digitalRead(M2_A) == digitalRead(M2_B)) { + ++rightTicks; + } else { + --rightTicks; + } +} + +int readSwitch() { + if (buttonA.getSingleDebouncedRelease()) { + return BUTTON_A; + } else if (buttonB.getSingleDebouncedRelease()) { + return BUTTON_B; + } else if (buttonC.getSingleDebouncedRelease()) { + return BUTTON_C; + } else { + return 0; + } +} diff --git a/libraries/SimplePID-master/examples/RomeoPIDTest/RomeoPIDTest.ino b/libraries/SimplePID-master/examples/RomeoPIDTest/RomeoPIDTest.ino new file mode 100644 index 0000000..5c4336c --- /dev/null +++ b/libraries/SimplePID-master/examples/RomeoPIDTest/RomeoPIDTest.ino @@ -0,0 +1,294 @@ +// RomeoPIDTest - Test the PID control for a DFRobot Romeo-based robot. +// +// To gather PID tuning data for graphing, put the robot on blocks, then +// start this program and open a Serial Monitor. Press S4 to start both +// motors, let them come to a steady speed, then press S4 to stop the +// motors. Copy the Serial output to a spreadsheet and plot target speed and +// current speed versus time. You should see a classic PID controller graph +// with some overshoot. + +#include +#include + +// Motor parameters. These are based on a Pololu #2285 motor with 48cpr +// encoder. +const float GEAR_RATIO = 46.85; +const float ENCODER_CPR = 48; + +// Number of encoder ticks per revolution of the wheel. +const float TICKS_PER_REV = GEAR_RATIO * ENCODER_CPR; + +// Maximum desired motor speed. Pololu #2285 are rated for 130rpm, but we +// don't drive them with enough voltage to achieve that. +const float MAX_REVS_PER_SEC = 100.0 / 60.0; + +// Use 60% of maximum speed for PID tuning. +const int PID_TUNING_TICKS_PER_SEC = 0.6 * MAX_REVS_PER_SEC * TICKS_PER_REV; + +// DFRobot Romeo v2 and BLE PIN assignments. + +const int ONBOARD_SWITCH_PIN = A0; + +const int LEFT_DIRECTION = 4; +const int LEFT_SPEED = 5; +const int RIGHT_SPEED = 6; +const int RIGHT_DIRECTION = 7; + +// Pins for the Pololu motor encoder outputs. +const int M1_A = 10; +const int M1_B = 11; +const int M2_A = 14; +const int M2_B = 15; + +// Minimum motor control value. Motor output below this will stall. +const int MIN_MOTOR_CMD = 60; + +int leftSpeedTarget = 0; +int rightSpeedTarget = 0; + +volatile unsigned long leftTicks = 0; +volatile unsigned long lastLeftTickTime = 0; +volatile unsigned long rightTicks = 0; +volatile unsigned long lastRightTickTime = 0; + +int lastLeftTicks = 0; +int lastRightTicks = 0; + +int leftMotorCmd = 0; +int rightMotorCmd = 0; + +unsigned long lastLoopTime; + +unsigned long lastSwitchTime; + +float loopTime = 0.0; + +// Ziegler-Nichols tuning. See this Wikipedia article for details: +// https://en.wikipedia.org/wiki/PID_controller#Loop_tuning +// To tune the controller, set USE_KU_ONLY to 1 and increase Ku +// until oscillation occurs, and set Tu to the oscillation period +// in seconds. Then set USE_KU_ONLY to zero to use the +// Ziegler-Nichols tune. To get a less agressive tune, set LESS_AGGRESSIVE +// to 1. + +// Set to 1 to use Ku only, to determine oscillation point. +#define USE_KU_ONLY 0 + +const float Ku = .11; +const float Tu = .20; + +#define LESS_AGGRESSIVE 0 + +#if !LESS_AGGRESSIVE +const float Kp = 0.6*Ku; +const float Ki = 2*Kp/Tu; +const float Kd = Kp*Tu/8; +#else +const float Kp = 0.2*Ku; +const float Ki = 2*Kp/Tu; +const float Kd = Kp*Tu/3; +#endif + +#if USE_KU_ONLY +SimplePID leftController = SimplePID(Ku, 0, 0); +SimplePID rightController = SimplePID(Ku, 0, 0); +#else +SimplePID leftController = SimplePID(Kp, Ki, Kd); +SimplePID rightController = SimplePID(Kp, Ki, Kd); +#endif + +// Sets up the serial output and the motor control pins, and attaches +// interrupt handlers to the pins on which we will read the encoder +// phototransistor values. +void setup() { + Serial.begin(115200); + delay(3000); + + pinMode(LEFT_DIRECTION, OUTPUT); + pinMode(LEFT_SPEED, OUTPUT); + pinMode(RIGHT_DIRECTION, OUTPUT); + pinMode(RIGHT_SPEED, OUTPUT); + + enableInterrupt(M1_A, leftAChange, CHANGE); + enableInterrupt(M1_B, leftBChange, CHANGE); + enableInterrupt(M2_A, rightAChange, CHANGE); + enableInterrupt(M2_B, rightBChange, CHANGE); + + Serial.print("Time (s)\tLeft Target\tLeft Speed\tLeft Cum Error\tLeft Motor"); + Serial.print("\tRight Target\tRight Speed\tRight Cum Error\tRight Motor"); + Serial.println(); + + lastLoopTime = micros(); + lastSwitchTime = millis(); +} + +// Loops forever showing the motor speeds and errors since the last loop, +// and adjusts the target speeds depending on whether the user is pressing +// switches S2 through S5, as indicated in the code below. +void loop() { + delay(15); + + unsigned long curLoopTime = micros(); + noInterrupts(); + int curLeftTicks = leftTicks; + int curRightTicks = rightTicks; + interrupts(); + + float dt = (curLoopTime - lastLoopTime) / 1E6; + + float leftSpeed = (curLeftTicks - lastLeftTicks) / dt; + float rightSpeed = (curRightTicks - lastRightTicks) / dt; + + int leftControl = leftController.getControlValue(leftSpeed, dt); + leftMotorCmd += min(255, leftControl); + leftMotorCmd = constrain(leftMotorCmd, -255, 255); + if (leftMotorCmd > 0) { + leftMotorCmd = max(leftMotorCmd, MIN_MOTOR_CMD); + } + + int rightControl = rightController.getControlValue(rightSpeed, dt); + rightMotorCmd += min(255, rightControl); + rightMotorCmd = constrain(rightMotorCmd, -255, 255); + if (rightMotorCmd > 0) { + rightMotorCmd = max(rightMotorCmd, MIN_MOTOR_CMD); + } + + // Coast to a stop if target is zero. + if (leftSpeedTarget == 0) { + leftMotorCmd = 0; + } + if (rightSpeedTarget == 0) { + rightMotorCmd = 0; + } + + setSpeed(leftMotorCmd, rightMotorCmd); + + if (leftSpeedTarget > 0 || leftSpeed > 0 || rightSpeedTarget > 0 || rightSpeed > 0) { + Serial.print(loopTime, 3); + Serial.print("\t"); + Serial.print(leftSpeedTarget); + Serial.print("\t"); + Serial.print(leftSpeed); + Serial.print("\t"); + Serial.print(leftController.getCumulativeError()); + Serial.print("\t"); + Serial.print(leftMotorCmd); + Serial.print("\t"); + + Serial.print(rightSpeedTarget); + Serial.print("\t"); + Serial.print(rightSpeed); + Serial.print("\t"); + Serial.print(rightController.getCumulativeError()); + Serial.print("\t"); + Serial.print(rightMotorCmd); + Serial.print("\t"); + + Serial.println(); + + loopTime += dt; +} + + // Ignore switches for a short time after pressing, to avoid bounce. + if (curLoopTime - lastSwitchTime > 0.5*1E6) { + int switchValue = readSwitch(); + if (switchValue > 0) { + lastSwitchTime = curLoopTime; + + switch (switchValue) { + case 2: + // Left motor on/off. + leftSpeedTarget = (leftSpeedTarget==0 ? PID_TUNING_TICKS_PER_SEC : 0); + break; + case 3: + // Right motor on/off. + rightSpeedTarget = (rightSpeedTarget==0 ? PID_TUNING_TICKS_PER_SEC : 0); + break; + case 4: + // Both motors on/off. + leftSpeedTarget = (leftSpeedTarget==0 ? PID_TUNING_TICKS_PER_SEC : 0); + rightSpeedTarget = (rightSpeedTarget==0 ? PID_TUNING_TICKS_PER_SEC : 0); + break; + case 5: + break; + default: + // no change in speed + break; + } + + leftController.setSetPoint(leftSpeedTarget); + rightController.setSetPoint(rightSpeedTarget); + } + } + + lastLeftTicks = curLeftTicks; + lastRightTicks = curRightTicks; + lastLoopTime = curLoopTime; +} + +void waitForSwitch1() { + while (readSwitch() != 1) { + // do nothing + } +} + +void setSpeed(int leftSpeed, int rightSpeed) { + digitalWrite(LEFT_DIRECTION, (leftSpeed >= 0 ? HIGH : LOW)); + analogWrite(LEFT_SPEED, abs(leftSpeed)); + digitalWrite(RIGHT_DIRECTION, (rightSpeed >= 0 ? HIGH : LOW)); + analogWrite(RIGHT_SPEED, abs(rightSpeed)); +} + +void leftAChange() { + if (digitalRead(M1_A) == digitalRead(M1_B)) { + ++leftTicks; + } else { + --leftTicks; + } +} + +void leftBChange() { + if (digitalRead(M1_A) != digitalRead(M1_B)) { + ++leftTicks; + } else { + --leftTicks; + } +} + +void rightAChange() { + if (digitalRead(M2_A) != digitalRead(M2_B)) { + ++rightTicks; + } else { + --rightTicks; + } +} + +void rightBChange() { + if (digitalRead(M2_A) == digitalRead(M2_B)) { + ++rightTicks; + } else { + --rightTicks; + } +} + +// Reads the value of the built-in switches S1 through S5. The switches +// are connected in parallel with resistors of five different sizes to +// analog pin A0. The difference in voltage at A0 allows us to determine +// which switch is pressed. +int readSwitch() { + int value = analogRead(ONBOARD_SWITCH_PIN); + + if (value > 800) { + return 0; + } else if (value > 600) { + return 5; + } else if (value > 400) { + return 4; + } else if (value > 250) { + return 3; + } else if (value > 75) { + return 2; + } else { + return 1; + } +}