├── .editorconfig ├── .github └── FUNDING.yml ├── LICENSE ├── Readme.md ├── examples ├── PinChangeInterrupt_HowItWorks │ └── PinChangeInterrupt_HowItWorks.ino ├── PinChangeInterrupt_Led │ └── PinChangeInterrupt_Led.ino ├── PinChangeInterrupt_LowLevel │ └── PinChangeInterrupt_LowLevel.ino └── PinChangeInterrupt_TickTock │ └── PinChangeInterrupt_TickTock.ino ├── header.png ├── keywords.txt ├── library.properties └── src ├── PinChangeInterrupt.cpp ├── PinChangeInterrupt.h ├── PinChangeInterrupt0.cpp ├── PinChangeInterrupt1.cpp ├── PinChangeInterrupt2.cpp ├── PinChangeInterrupt3.cpp ├── PinChangeInterruptBoards.h ├── PinChangeInterruptPins.h └── PinChangeInterruptSettings.h /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | insert_final_newline = true 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: nicohood # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: nicohood # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://www.buymeacoffee.com/nicohood # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2021 NicoHood 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 19 | OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | PinChangeInterrupt Library 1.2.9 2 | ================================ 3 | 4 | ![Header Picture](header.png) 5 | 6 | PinChangeInterrupt library with a resource friendly implementation (API and LowLevel). 7 | PinChangeInterrupts are different than normal Interrupts. See detail below. 8 | 9 | ##### Features: 10 | * PinChangeInterrupt for a lot of pins 11 | * Rising, Falling or Change detection for every pin separately 12 | * Usable on a lot Arduino compatible boards 13 | * Implementation is fast, compact and resource friendly 14 | * Ports/Pins can be manually deactivated in the Settings file 15 | * API and LowLevel option 16 | * Full Port0-3 support 17 | * .a linkage optimization (Arduino IDE) 18 | 19 | Buy Me A Coffee 20 | 21 | #### Supported pins for PinChangeInterrupt: 22 | See [PCINT pin table](https://github.com/NicoHood/PinChangeInterrupt/#pinchangeinterrupt-table) at the bottom for more details. 23 | 24 | ``` 25 | Arduino Uno/Nano/Mini: All pins are usable 26 | Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), 27 | A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) 28 | Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 29 | HoodLoader2: All (broken out 1-7) pins are usable 30 | Attiny24/44/84: All pins are usable 31 | Attiny25/45/85: All pins are usable 32 | Attiny13: All pins are usable 33 | Attiny441/841: All pins are usable 34 | Attiny261/461/861: All pins are usable 35 | Attiny2313/2313A/4313: PORTB is usable 36 | ATmega644/ATmega644P/ATmega1284P: All pins are usable 37 | ATmega162: PORTA and PORTC usable 38 | ATmega48/88/168/328/328PB: All pins are usable 39 | ``` 40 | 41 | Contact information can be found here: 42 | 43 | www.nicohood.de 44 | 45 | Installation 46 | ============ 47 | 48 | Download the zip, extract and remove the "-master" of the folder. 49 | Install the library [as described here](http://arduino.cc/en/pmwiki.php?n=Guide/Libraries). 50 | 51 | This library can also be used with the [DMBS AVR Library Collection](https://github.com/NicoHood/avr) and a pure makefile. 52 | 53 | How to use 54 | ========== 55 | 56 | It is important that you know at least the basic difference between **PinInterrupts** and **PinChangeInterrupts**. 57 | I will explain the basics of **PinChangeInterrupts** (PCINTs) based on an Arduino Uno. 58 | 59 | On a standard Arduino Uno Pin 2 and 3 have **PinInterrupts**. Those are exclusively for a single pin and can detect RISING, FALLING and CHANGE. 60 | 61 | **PinChangeInterrupts** instead are used for a whole port (they should have better named them PortChangeInterrupts) and can only detect CHANGE for a whole port. 62 | Each pin row (0-7, 8-13, A0-A5) represents a port. If an interrupt (ISR) occurs on one pin of a port 63 | it is still unclear what pin of the port caused this interrupt. Therefore this library saves the state of the whole port and compares with the last state. 64 | This way we can also see if it was a RISING or FALLING edge instead of only knowing the CHANGE. 65 | 66 | A **PinChangeInterrupt** will only be triggered for the attached pins per port. 67 | Meaning if you set PCINT for a pin and another pin on the same port is changing a lot 68 | it will not interrupt your code. 69 | 70 | **PinChangeInterrupts** might be a tiny bit slower and not that reliable because of that detection overhead (talking about micro seconds). 71 | Make sure to not use longer function calls inside the ISR or Serial print. 72 | You have the same issues on normal **PinInterrupts** and interrupts in general. 73 | 74 | The library is coded to get maximum speed and minimum code size. The LowLevel example without the API takes 4uS to enter the interrupt function in the worst case 75 | which is pretty good and might be even better than the **PinInterrupt** code from the official Arduino core due to high optimization. 76 | If you need very precise interrupts you better use **PinInterrupts** without the Arduino IDE at all. 77 | 78 | ### Examples 79 | To see how the code works just check the Led and TickTock example. 80 | The LowLevel example is for advanced users with more optimization and more direct access. 81 | The HowItWorks example shows the basic PinChangeInterrupt setup and decoding routine, similar to the library. 82 | See the notes in the examples about more details. 83 | 84 | An useful "real use" example of the PinChangeInterrupt library can be found here: 85 | https://github.com/NicoHood/IRLremote 86 | 87 | ### API Reference 88 | 89 | ##### Attach a PinChangeInterrupt 90 | ```cpp 91 | // The pin has to be a PCINT number. Use the makro to convert a pin to a PCINT number. 92 | // Enables event functions which need to be defined in the sketch. 93 | // Valid interrupt modes are: RISING, FALLING or CHANGE 94 | attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick), tick, RISING); 95 | 96 | // You can also input the PCINT number (see table below) 97 | attachPinChangeInterrupt(5, tock, FALLING); 98 | 99 | // PinChangeInterrupt can always be abbreviated with PCINT 100 | attachPCINT(digitalPinToPCINT(pinBlink), blinkLed, CHANGE); 101 | ``` 102 | 103 | ##### Detach a PinChangeInterrupt 104 | ```cpp 105 | // Similar usage as the attachPCINT function. 106 | // Interrupts will no longer occur. 107 | detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); 108 | detachPinChangeInterrupt(5); 109 | detachPCINT(digitalPinToPCINT(pinTock)); 110 | ``` 111 | 112 | ##### Enable/Disable a PinChangeInterrupt 113 | ```cpp 114 | // Similar usage as the attachPCINT function. 115 | // Use this to temporary enable/disable the Interrupt 116 | disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); 117 | disablePinChangeInterrupt(5); 118 | disablePCINT(digitalPinToPCINT(pinBlink)); 119 | 120 | // Enable the PCINT with the old settings again (function + mode) 121 | enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); 122 | enablePinChangeInterrupt(5); 123 | enablePCINT(digitalPinToPCINT(pinBlink)); 124 | ``` 125 | 126 | ##### Get Trigger on mode CHANGE 127 | ```cpp 128 | // Differenciate between RISING and FALLING on mode CHANGE. 129 | // Only use this in the attached interrupt function. 130 | uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(pinTick)); 131 | if(trigger == RISING) 132 | // Do something 133 | else if(trigger == FALLING) 134 | // Do something 135 | else 136 | // Wrong usage (trigger == CHANGE) 137 | ``` 138 | 139 | ##### LowLevel API 140 | See [LowLevel example](examples/PinChangeInterrupt_LowLevel/PinChangeInterrupt_LowLevel.ino) for more details. 141 | ```cpp 142 | // Use the attach function as you are used to, just leave out the function name 143 | attachPinChangeInterrupt(interruptBlink, CHANGE); 144 | 145 | // LowLevel function that is called when an interrupt occurs for a specific PCINT. 146 | // It is required to know the exact PCINT number, no Arduino pin number will work here. 147 | void PinChangeInterruptEvent(5)(void) { 148 | // Do something 149 | } 150 | ``` 151 | 152 | PinchangeInterrupt Table 153 | ======================== 154 | Pins with * are not broken out/deactivated by default. 155 | You may activate them in the [setting file](https://github.com/NicoHood/PinChangeInterrupt/blob/master/src/PinChangeInterruptSettings.h#L98) (advanced). 156 | 157 | Each row section represents a port(0-3). 158 | Not all MCUs have all Ports/Pins physically available. 159 | 160 | **Note: Not all supported AVRs are listed here. There are way more supported, please refer to the shorter list above.** 161 | 162 | #### Official Arduinos 163 | ``` 164 | | PCINT | Uno/Nano/Mini | Mega/2560 | Leonardo/Micro | HL2 (8/16/32u2) | 165 | | ----- | --------------- | -------------- | -------------- | --------------- | 166 | | 0 | 8 (PB0) | 53 SS (PB0) | SS (PB0)* | 0 SS (PB0)* | 167 | | 1 | 9 (PB1) | 52 SCK (PB1) | SCK (PB1) | 1 SCK (PB1) | 168 | | 2 | 10 SS (PB2) | 51 MOSI (PB2) | MOSI (PB2) | 2 MOSI (PB2) | 169 | | 3 | 11 MISO (PB3) | 50 MISO (PB3) | MISO (PB3) | 3 MISO (PB3) | 170 | | 4 | 12 MOSI (PB4) | 10 (PB4) | 8/A8 (PB4) | 4 (PB4) | 171 | | 5 | 13 SCK (PB5) | 11 (PB5) | 9/A9 (PB5) | 5 (PB5) | 172 | | 6 | XTAL1 (PB6)* | 12 (PB6) | 10/A10 (PB6) | 6 (PB6) | 173 | | 7 | XTAL2 (PB7)* | 13 (PB7) | 11 (PB7) | 7 (PB7) | 174 | | ----- | --------------- | -------------- | -------------- | --------------- | 175 | | 8 | A0 (PC0) | 0 RX (PE0)* | | (PC6)* | 176 | | 9 | A1 (PC1) | 15 RX3 (PJ0)* | | (PC5)* | 177 | | 10 | A2 (PC2) | 14 TX3 (PJ1)* | | (PC4)* | 178 | | 11 | A3 (PC3) | NC (PJ2)* | | (PC2)* | 179 | | 12 | A4 SDA (PC4) | NC (PJ3)* | | (PD5)* | 180 | | 13 | A5 SDC (PC5) | NC (PJ4)* | | | 181 | | 14 | RST (PC6)* | NC (PJ5)* | | | 182 | | 15 | | NC (PJ6)* | | | 183 | | ----- | --------------- | -------------- | -------------- | --------------- | 184 | | 16 | 0 RX (PD0) | A8 (PK0) | | | 185 | | 17 | 1 TX (PD1) | A9 (PK1) | | | 186 | | 18 | 2 INT0 (PD2) | A10 (PK2) | | | 187 | | 19 | 3 INT1 (PD3) | A11 (PK3) | | | 188 | | 20 | 4 (PD4) | A12 (PK4) | | | 189 | | 21 | 5 (PD5) | A13 (PK5) | | | 190 | | 22 | 6 (PD6) | A14 (PK6) | | | 191 | | 23 | 7 (PD7) | A15 (PK7) | | | 192 | | ----- | --------------- | -------------- | -------------- | --------------- | 193 | ``` 194 | 195 | #### Atmel Attinys 196 | ``` 197 | | PCINT | Attiny13 | Attiny x4 | Attiny x5 | Attiny x41 | 198 | | ----- | ------------ | --------------- | ------------- | ------------------- | 199 | | 0 | 0 MOSI (PB0) | 0 (PA0) | 0 MOSI (PB0) | A0/D0 (PA0) | 200 | | 1 | 1 MISO (PB1) | 1 (PA1) | 1 MISO (PB1) | A1/D1 (PA1) | 201 | | 2 | 2 SCK (PB2) | 2 (PA2) | 2 SCK (PB2) | A2/D2 (PA2) | 202 | | 3 | 3 (PB3) | 3 (PA3) | 3 XTAL1 (PB3) | A3/D3 (PA3) | 203 | | 4 | 4 (PB4) | 4 SCK (PA4) | 4 XTAL2 (PB4) | A4/D4 (PA4) | 204 | | 5 | 5 RST (PB5) | 5 MISO (PA5) | 5 RST (PB5) | A5/D5 PWM (PA5) | 205 | | 6 | | 6 MOSI (PA6) | | A7/D7 PWM (PA6) | 206 | | 7 | | 7 (PA7) | | A6/D6 PWM (PA7) | 207 | | ----- | ------------ | --------------- | ------------- | ------------------- | 208 | | 8 | | 10 XTAL1 (PB0)* | | A10/D10 XTAL1 (PB0) | 209 | | 9 | | 9 XTAL2 (PB1)* | | A9/D9 XTAL2 (PB1) | 210 | | 10 | | 8 INT0 (PB2)* | | A8/D8 PWM (PB2) | 211 | | 11 | | RST (PB3)* | | RST (PB3) | 212 | | 12 | | | | | 213 | | 13 | | | | | 214 | | 14 | | | | | 215 | | 15 | | | | | 216 | | ----- | ------------ | --------------- | ------------- | ------------------- | 217 | ``` 218 | 219 | #### Other Atmel MCUs 220 | ``` 221 | | PCINT | ATmega644P/1284P | 222 | | ----- | ----------------- | 223 | | 0 | A0/D24 (PA0) | 224 | | 1 | A1/D25 (PA1) | 225 | | 2 | A2/D26 (PA2) | 226 | | 3 | A3/D27 (PA3) | 227 | | 4 | A4/D28 (PA4) | 228 | | 5 | A5/D29 (PA5) | 229 | | 6 | A6/D30 (PA6) | 230 | | 7 | A7/D31 (PA7) | 231 | | ----- | ----------------- | 232 | | 8 | 0 (PB0) | 233 | | 9 | 1 (PB1) | 234 | | 10 | 2 INT2 (PB2) | 235 | | 11 | 3 PWM (PB3) | 236 | | 12 | 4 SS/PWM (PB4) | 237 | | 13 | 5 MOSI/PWM (PB5) | 238 | | 14 | 6 MISO/PWM (PB6) | 239 | | 15 | 7 SCK (PB7) | 240 | | ----- | ----------------- | 241 | | 16 | 16 SCL (PC0) | 242 | | 17 | 17 SDA (PC1) | 243 | | 18 | 18 TCK (PC2) | 244 | | 19 | 19 TMS (PC3) | 245 | | 20 | 20 TDO (PC4) | 246 | | 21 | 21 TDI (PC5) | 247 | | 22 | 22 (PC6) | 248 | | 23 | 23 (PC7) | 249 | | ----- | ----------------- | 250 | | 24 | 8 RX0 (PD0) | 251 | | 25 | 9 TX0 (PD1) | 252 | | 26 | 10 RX1/INT0 (PD2) | 253 | | 27 | 11 TX1/INT1 (PD3) | 254 | | 28 | 12 PWM (PD4) | 255 | | 29 | 13 PWM (PD5) | 256 | | 30 | 14 PWM (PD6) | 257 | | 31 | 15 PWM (PD7) | 258 | | ----- | ----------------- | 259 | ``` 260 | 261 | Developer Information 262 | ===================== 263 | If a PinChangeInterrupt occurs it will determine the triggered pin(s). 264 | The library uses weak callback functions that are called for the triggered pins(s). 265 | This way we can easily skip not triggered pins (I looked at the assembler) and also implement a fast LowLevel version. 266 | 267 | Also the order of the function execution is (normally) ordered from the lower pin number to the higher. 268 | Meaning pin 8 will be checked faster as pin 13 (Arduino Uno). Talking about micro seconds here! You can change the order in the settings. 269 | For example by default pin 0-3 have a low priority order than pin 4-7 (Arduino Uno). Because they are used for Serial and normal PinInterrupts. 270 | I don't expect anyone to use those pins at all with PCINT but at least the priority is lowered compared to the other pins. 271 | 272 | The API takes those weak functions and just overwrites all of them and call the function pointers of the attached functions instead. 273 | This way the function can be changed at runtime and its also easier to integrate into other libraries. 274 | The function pointers take a bit flash though (LowLevel: 1526/18, API: 1790/58 for Led example). 275 | 276 | You can get better performance and less code size if you deactivate the not used pins/ports manually in the settings file. 277 | This way only the needed pins get compiled and the code is optimized by the preprocessor. 278 | For a bit more comfortable/automatic optimization you can [install the library into the core](https://github.com/NicoHood/PinChangeInterrupt/#optional-installation) 279 | to get use of the .a linkage. This way only the used ports get compiled. 280 | So if you only use pins on a single port (eg 8-13) then only this port gets compiled. This only works with the core installation. 281 | 282 | 283 | That's it! I hope you like the library. I tried to make it as simple and small as possible. 284 | Keep in mind that PCINTs are not useful for every project but in most cases 285 | the new PinChangeInterrupts may help you a lot. 286 | 287 | 288 | Version History 289 | =============== 290 | ``` 291 | 1.2.9 Release (18.05.2021) 292 | * Added Attiny261/461/861 support #39 293 | * Added Attiny2313/2313A/4313 support #37 294 | * Added ATMega328PB support #30 295 | * Added ATMega48 support #38 296 | * Fixed ATMega88/168 support #38 297 | 298 | 1.2.8 Release (22.11.2020) 299 | * Add support for ATmega644 #34 300 | 301 | 1.2.7 Release (07.10.2018) 302 | * Add support for ATmega162 #21 303 | 304 | 1.2.6 Release (10.02.2018) 305 | * Fix makefile compilation problems 306 | 307 | 1.2.5 Release (02.09.2017) 308 | * Fixed makefile compilation 309 | * Added support to disable pcint/port via -DPCINT_DISABLE_PORT0 etc. 310 | * Added ATtinyX313 support 311 | * Fix ATmega1284P 312 | 313 | 1.2.4 Release (16.04.2016) 314 | * Fixed Attinyx4/x5 Issue #8 315 | 316 | 1.2.3 Release (24.12.2015) 317 | * Added Attiny441/841 support 318 | 319 | 1.2.2 Release (05.12.2015) 320 | * Fixed initial value when enabled issue 321 | * Enabled official dot_a_linkage 322 | * Added Attiny13 support Issue #4 323 | * Updated documentation 324 | * Improved detaching function 325 | * Improved attaching and enabling 326 | 327 | 1.2.1 Release (24.05.2015) 328 | * Fix Attiny Issue #1 329 | * Added enable/disable function 330 | * Added getPinChangeInterruptTrigger() function 331 | * Added to Arduino IDE library manager 332 | 333 | 1.2 Release (19.04.2015) 334 | * Added weak interrupt function 335 | * Improved interrupt function calls 336 | * Fixed attach/detach array position when ports are deactivated 337 | * Improved manual PCINT deactivation by user 338 | * Improved definitions for different boards 339 | * HoodLoader2 definition fixes 340 | * Improved speed 341 | * Improved specific boards 342 | * Moved attach function to .cpp file 343 | * Updated examples 344 | * Added API and LowLevel 345 | * Added Port3 support (ATmega644P/ATmega1284P) 346 | * Added PCINT_VERSION definition 347 | 348 | 1.1 Release (06.12.2014) 349 | * Added port deactivation 350 | * Ram usage improvements for AVRs with <3 PCINT ports 351 | 352 | 1.0 Release (04.12.2014) 353 | * Added general PinChangeInterrupt functions 354 | * Added support for most Arduino boards 355 | * Added basic example 356 | * Added an example with IRLremote 357 | ``` 358 | -------------------------------------------------------------------------------- /examples/PinChangeInterrupt_HowItWorks/PinChangeInterrupt_HowItWorks.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 4 | 5 | PinChangeInterrupt_HowItWorks 6 | Shows how to manually setup a single PCINT function with a few helper functions. 7 | 8 | Connect a button/cable to pin 7 and ground. 9 | The led will change its state if pin 7 changes. 10 | 11 | PinChangeInterrupts are different than normal Interrupts. 12 | See readme for more information. 13 | Dont use Serial or delay inside interrupts! 14 | This library is not compatible with SoftSerial. 15 | 16 | The following pins are usable for PinChangeInterrupt: 17 | Arduino Uno/Nano/Mini: All pins are usable 18 | Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), 19 | A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) 20 | Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 21 | HoodLoader2: All (broken out 1-7) pins are usable 22 | Attiny 24/44/84: All pins are usable 23 | Attiny 25/45/85: All pins are usable 24 | Attiny 13: All pins are usable 25 | Attiny 441/841: All pins are usable 26 | ATmega644P/ATmega1284P: All pins are usable 27 | */ 28 | 29 | //================================================================================ 30 | // User Settings 31 | //================================================================================ 32 | 33 | // choose a valid PinChangeInterrupt pin of your Arduino board 34 | #define PCINT_PIN 7 35 | #define PCINT_MODE CHANGE 36 | #define PCINT_FUNCTION blinkLed 37 | 38 | void setup() 39 | { 40 | // set pins to input with a pullup, led to output 41 | pinMode(PCINT_PIN, INPUT_PULLUP); 42 | pinMode(LED_BUILTIN, OUTPUT); 43 | 44 | // attach the new PinChangeInterrupt 45 | attachPinChangeInterrupt(); 46 | } 47 | 48 | void loop() { 49 | // empty 50 | } 51 | 52 | void blinkLed(void) { 53 | // switch Led state 54 | digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); 55 | } 56 | 57 | //================================================================================ 58 | // PCINT Definitions 59 | //================================================================================ 60 | 61 | #define PCMSK *digitalPinToPCMSK(PCINT_PIN) 62 | #define PCINT digitalPinToPCMSKbit(PCINT_PIN) 63 | #define PCIE digitalPinToPCICRbit(PCINT_PIN) 64 | #define PCPIN *portInputRegister(digitalPinToPort(PCINT_PIN)) 65 | 66 | #if (PCIE == 0) 67 | #define PCINT_vect PCINT0_vect 68 | #elif (PCIE == 1) 69 | #define PCINT_vect PCINT1_vect 70 | #elif (PCIE == 2) 71 | #define PCINT_vect PCINT2_vect 72 | #else 73 | #error This board doesnt support PCINT ? 74 | #endif 75 | 76 | volatile uint8_t oldPort = 0x00; 77 | 78 | void attachPinChangeInterrupt(void) { 79 | // update the old state to the actual state 80 | oldPort = PCPIN; 81 | 82 | // pin change mask registers decide which pins are enabled as triggers 83 | PCMSK |= (1 << PCINT); 84 | 85 | // PCICR: Pin Change Interrupt Control Register - enables interrupt vectors 86 | PCICR |= (1 << PCIE); 87 | } 88 | 89 | void detachPinChangeInterrupt(void) { 90 | // disable the mask. 91 | PCMSK &= ~(1 << PCINT); 92 | 93 | // if that's the last one, disable the interrupt. 94 | if (PCMSK == 0) 95 | PCICR &= ~(0x01 << PCIE); 96 | } 97 | 98 | ISR(PCINT_vect) { 99 | // get the new and old pin states for port 100 | uint8_t newPort = PCPIN; 101 | 102 | // compare with the old value to detect a rising or falling 103 | uint8_t change = newPort ^ oldPort; 104 | 105 | // check which pins are triggered, compared with the settings 106 | uint8_t trigger = 0x00; 107 | #if (PCINT_MODE == RISING) || (PCINT_MODE == CHANGE) 108 | uint8_t rising = change & newPort; 109 | trigger |= (rising & (1 << PCINT)); 110 | #endif 111 | #if (PCINT_MODE == FALLING) || (PCINT_MODE == CHANGE) 112 | uint8_t falling = change & oldPort; 113 | trigger |= (falling & (1 << PCINT)); 114 | #endif 115 | 116 | // save the new state for next comparison 117 | oldPort = newPort; 118 | 119 | // if our needed pin has changed, call the IRL interrupt function 120 | if (trigger & (1 << PCINT)) 121 | PCINT_FUNCTION(); 122 | } 123 | -------------------------------------------------------------------------------- /examples/PinChangeInterrupt_Led/PinChangeInterrupt_Led.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 4 | 5 | PinChangeInterrupt_TickTock 6 | Demonstrates how to use the library 7 | 8 | Connect a button/cable to pin 7 and ground. 9 | The Led state will change if the pin state does. 10 | 11 | PinChangeInterrupts are different than normal Interrupts. 12 | See readme for more information. 13 | Dont use Serial or delay inside interrupts! 14 | This library is not compatible with SoftSerial. 15 | 16 | The following pins are usable for PinChangeInterrupt: 17 | Arduino Uno/Nano/Mini: All pins are usable 18 | Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), 19 | A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) 20 | Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 21 | HoodLoader2: All (broken out 1-7) pins are usable 22 | Attiny 24/44/84: All pins are usable 23 | Attiny 25/45/85: All pins are usable 24 | Attiny 13: All pins are usable 25 | Attiny 441/841: All pins are usable 26 | ATmega644P/ATmega1284P: All pins are usable 27 | */ 28 | 29 | #include "PinChangeInterrupt.h" 30 | 31 | // Choose a valid PinChangeInterrupt pin of your Arduino board 32 | #define pinBlink 7 33 | 34 | void setup() { 35 | // set pin to input with a pullup, led to output 36 | pinMode(pinBlink, INPUT_PULLUP); 37 | pinMode(LED_BUILTIN, OUTPUT); 38 | 39 | // Manually blink once to test if LED is functional 40 | blinkLed(); 41 | delay(1000); 42 | blinkLed(); 43 | 44 | // Attach the new PinChangeInterrupt and enable event function below 45 | attachPCINT(digitalPinToPCINT(pinBlink), blinkLed, CHANGE); 46 | } 47 | 48 | void blinkLed(void) { 49 | // Switch Led state 50 | digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); 51 | } 52 | 53 | void loop() { 54 | // Nothing to do here 55 | } 56 | -------------------------------------------------------------------------------- /examples/PinChangeInterrupt_LowLevel/PinChangeInterrupt_LowLevel.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 4 | 5 | PinChangeInterrupt_LowLevel 6 | Demonstrates how to use the library without the API 7 | 8 | Make sure to comment "//#define PCINT_API" in the settings file. 9 | 10 | To maximize speed and size also uncomment all not used pins above. 11 | Then you could also uncomment "#define PCINT_COMPILE_ENABLED_ISR" 12 | to get away the .a linkage overhead. 13 | 14 | Connect a button/cable to pin 7 and ground (Uno). 15 | Strong overwritten callback functions are called when an interrupt occurs. 16 | The Led state will change if the pin state does. 17 | 18 | PinChangeInterrupts are different than normal Interrupts. 19 | See readme for more information. 20 | Dont use Serial or delay inside interrupts! 21 | This library is not compatible with SoftSerial. 22 | 23 | The following pins are usable for PinChangeInterrupt: 24 | Arduino Uno/Nano/Mini: All pins are usable 25 | Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), 26 | A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) 27 | Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 28 | HoodLoader2: All (broken out 1-7) pins are usable 29 | Attiny 24/44/84: All pins are usable 30 | Attiny 25/45/85: All pins are usable 31 | Attiny 13: All pins are usable 32 | Attiny 441/841: All pins are usable 33 | ATmega644P/ATmega1284P: All pins are usable 34 | */ 35 | 36 | #include "PinChangeInterrupt.h" 37 | 38 | // choose a valid PinChangeInterrupt pin of your Arduino board 39 | // manually defined pcint number 40 | #define pinBlink 7 41 | #define interruptBlink 23 42 | 43 | void setup() 44 | { 45 | // set pin to input with a pullup, led to output 46 | pinMode(pinBlink, INPUT_PULLUP); 47 | pinMode(LED_BUILTIN, OUTPUT); 48 | 49 | // attach the new PinChangeInterrupts and enable event functions below 50 | attachPinChangeInterrupt(interruptBlink, CHANGE); 51 | } 52 | 53 | void PinChangeInterruptEvent(interruptBlink)(void) { 54 | // switch Led state 55 | digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); 56 | } 57 | 58 | void loop() { 59 | // nothing to do here 60 | } 61 | -------------------------------------------------------------------------------- /examples/PinChangeInterrupt_TickTock/PinChangeInterrupt_TickTock.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 4 | 5 | PinChangeInterrupt_TickTock 6 | Demonstrates how to use the library 7 | 8 | Connect a button/cable to pin 10/11 and ground. 9 | The value printed on the serial port will increase 10 | if pin 10 is rising and decrease if pin 11 is falling. 11 | 12 | PinChangeInterrupts are different than normal Interrupts. 13 | See readme for more information. 14 | Dont use Serial or delay inside interrupts! 15 | This library is not compatible with SoftSerial. 16 | 17 | The following pins are usable for PinChangeInterrupt: 18 | Arduino Uno/Nano/Mini: All pins are usable 19 | Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), 20 | A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) 21 | Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 22 | HoodLoader2: All (broken out 1-7) pins are usable 23 | Attiny 24/44/84: All pins are usable 24 | Attiny 25/45/85: All pins are usable 25 | Attiny 13: All pins are usable 26 | Attiny 441/841: All pins are usable 27 | ATmega644P/ATmega1284P: All pins are usable 28 | */ 29 | 30 | #include "PinChangeInterrupt.h" 31 | 32 | // choose a valid PinChangeInterrupt pin of your Arduino board 33 | #define pinTick 10 34 | #define pinTock 11 35 | 36 | volatile long ticktocks = 0; 37 | 38 | void setup() 39 | { 40 | // start serial debug output 41 | Serial.begin(115200); 42 | Serial.println(F("Startup")); 43 | 44 | // set pins to input with a pullup 45 | pinMode(pinTick, INPUT_PULLUP); 46 | pinMode(pinTock, INPUT_PULLUP); 47 | 48 | // attach the new PinChangeInterrupts and enable event functions below 49 | attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick), tick, RISING); 50 | attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock), tock, FALLING); 51 | } 52 | 53 | void loop() { 54 | // integer to count the number of prints 55 | static int i = 0; 56 | delay(1000); 57 | 58 | // print values 59 | Serial.print(i, DEC); 60 | Serial.print(F(" ")); 61 | Serial.println(ticktocks); 62 | 63 | // abort if we printed 100 times 64 | if (i >= 100) { 65 | Serial.println(F("Detaching Interrupts.")); 66 | detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); 67 | detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock)); 68 | return; 69 | } 70 | else 71 | i++; 72 | 73 | // Temporary pause interrupts 74 | if (ticktocks > 500) { 75 | Serial.println(F("Disabling Tick Interrupt.")); 76 | disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); 77 | enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock)); 78 | } 79 | else if (ticktocks < -500) { 80 | Serial.println(F("Disabling Tock Interrupt.")); 81 | disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock)); 82 | enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); 83 | } 84 | else { 85 | enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); 86 | enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock)); 87 | } 88 | } 89 | 90 | void tick(void) { 91 | // increase value 92 | ticktocks++; 93 | } 94 | 95 | void tock(void) { 96 | // decrease value 97 | ticktocks--; 98 | } 99 | -------------------------------------------------------------------------------- /header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NicoHood/PinChangeInterrupt/62e4ef1929722e70d70616a64073963ef0892f32/header.png -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For PinChangeInterrupt 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | ####################################### 10 | # Methods and Functions (KEYWORD2) 11 | ####################################### 12 | 13 | attachPinChangeInterrupt KEYWORD2 14 | detachPinChangeInterrupt KEYWORD2 15 | attachPCINT KEYWORD2 16 | detachPCINT KEYWORD2 17 | PinChangeInterruptEvent KEYWORD2 18 | PCINTEvent KEYWORD2 19 | enablePCINT KEYWORD2 20 | enablePinChangeInterrupt KEYWORD2 21 | disablePCINT KEYWORD2 22 | disablePinChangeInterrupt KEYWORD2 23 | getPCINTTrigger KEYWORD2 24 | getPinChangeInterruptTrigger KEYWORD2 25 | 26 | ####################################### 27 | # Instances (KEYWORD2) 28 | ####################################### 29 | 30 | ####################################### 31 | # Constants (LITERAL1) 32 | ####################################### 33 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=PinChangeInterrupt 2 | version=1.2.9 3 | author=NicoHood 4 | maintainer=NicoHood 5 | sentence=A simple & compact PinChangeInterrupt library for Arduino. 6 | paragraph=PinChangeInterrupt library with a resource friendly implementation (API and LowLevel). PinChangeInterrupts are different than normal Interrupts. See readme for more information. 7 | category=Signal Input/Output 8 | url=https://github.com/NicoHood/PinChangeInterrupt 9 | architectures=avr 10 | dot_a_linkage=true 11 | -------------------------------------------------------------------------------- /src/PinChangeInterrupt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2021 NicoHood 3 | See the readme for credit to other people. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | #include "PinChangeInterrupt.h" 25 | 26 | // manually include cpp files here to save flash if only 1 ISR is present 27 | // or if the user knows he just wants to compile all enabled ports. 28 | #if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) 29 | #define PCINT_INCLUDE_FROM_CPP 30 | #include "PinChangeInterrupt0.cpp" 31 | #include "PinChangeInterrupt1.cpp" 32 | #include "PinChangeInterrupt2.cpp" 33 | #include "PinChangeInterrupt3.cpp" 34 | #else 35 | 36 | //================================================================================ 37 | // Weak Callbacks 38 | //================================================================================ 39 | 40 | // create all weak functions which are all (if not used) alias of the pcint_null_callback above 41 | /* 42 | for (int i = 0; i < 32; i++) { 43 | Serial.print("void PinChangeInterruptEventPCINT"); 44 | Serial.print(i); 45 | Serial.println("(void) __attribute__((weak, alias(\"pcint_null_callback\")));"); 46 | } 47 | */ 48 | void PinChangeInterruptEventPCINT0(void) __attribute__((weak, alias("pcint_null_callback"))); 49 | void PinChangeInterruptEventPCINT1(void) __attribute__((weak, alias("pcint_null_callback"))); 50 | void PinChangeInterruptEventPCINT2(void) __attribute__((weak, alias("pcint_null_callback"))); 51 | void PinChangeInterruptEventPCINT3(void) __attribute__((weak, alias("pcint_null_callback"))); 52 | void PinChangeInterruptEventPCINT4(void) __attribute__((weak, alias("pcint_null_callback"))); 53 | void PinChangeInterruptEventPCINT5(void) __attribute__((weak, alias("pcint_null_callback"))); 54 | void PinChangeInterruptEventPCINT6(void) __attribute__((weak, alias("pcint_null_callback"))); 55 | void PinChangeInterruptEventPCINT7(void) __attribute__((weak, alias("pcint_null_callback"))); 56 | void PinChangeInterruptEventPCINT8(void) __attribute__((weak, alias("pcint_null_callback"))); 57 | void PinChangeInterruptEventPCINT9(void) __attribute__((weak, alias("pcint_null_callback"))); 58 | void PinChangeInterruptEventPCINT10(void) __attribute__((weak, alias("pcint_null_callback"))); 59 | void PinChangeInterruptEventPCINT11(void) __attribute__((weak, alias("pcint_null_callback"))); 60 | void PinChangeInterruptEventPCINT12(void) __attribute__((weak, alias("pcint_null_callback"))); 61 | void PinChangeInterruptEventPCINT13(void) __attribute__((weak, alias("pcint_null_callback"))); 62 | void PinChangeInterruptEventPCINT14(void) __attribute__((weak, alias("pcint_null_callback"))); 63 | void PinChangeInterruptEventPCINT15(void) __attribute__((weak, alias("pcint_null_callback"))); 64 | void PinChangeInterruptEventPCINT16(void) __attribute__((weak, alias("pcint_null_callback"))); 65 | void PinChangeInterruptEventPCINT17(void) __attribute__((weak, alias("pcint_null_callback"))); 66 | void PinChangeInterruptEventPCINT18(void) __attribute__((weak, alias("pcint_null_callback"))); 67 | void PinChangeInterruptEventPCINT19(void) __attribute__((weak, alias("pcint_null_callback"))); 68 | void PinChangeInterruptEventPCINT20(void) __attribute__((weak, alias("pcint_null_callback"))); 69 | void PinChangeInterruptEventPCINT21(void) __attribute__((weak, alias("pcint_null_callback"))); 70 | void PinChangeInterruptEventPCINT22(void) __attribute__((weak, alias("pcint_null_callback"))); 71 | void PinChangeInterruptEventPCINT23(void) __attribute__((weak, alias("pcint_null_callback"))); 72 | void PinChangeInterruptEventPCINT24(void) __attribute__((weak, alias("pcint_null_callback"))); 73 | void PinChangeInterruptEventPCINT25(void) __attribute__((weak, alias("pcint_null_callback"))); 74 | void PinChangeInterruptEventPCINT26(void) __attribute__((weak, alias("pcint_null_callback"))); 75 | void PinChangeInterruptEventPCINT27(void) __attribute__((weak, alias("pcint_null_callback"))); 76 | void PinChangeInterruptEventPCINT28(void) __attribute__((weak, alias("pcint_null_callback"))); 77 | void PinChangeInterruptEventPCINT29(void) __attribute__((weak, alias("pcint_null_callback"))); 78 | void PinChangeInterruptEventPCINT30(void) __attribute__((weak, alias("pcint_null_callback"))); 79 | void PinChangeInterruptEventPCINT31(void) __attribute__((weak, alias("pcint_null_callback"))); 80 | 81 | #endif // PCINT_INCLUDE_FROM_CPP 82 | 83 | // useless function for weak implemented/not used functions, extern c needed for the alias 84 | extern "C" { 85 | void pcint_null_callback(void) { 86 | // useless 87 | } 88 | } 89 | 90 | //================================================================================ 91 | // PinChangeInterrupt User Functions 92 | //================================================================================ 93 | 94 | // variables to save the last port states and the interrupt settings 95 | uint8_t oldPorts[PCINT_NUM_USED_PORTS] = { 0 }; 96 | uint8_t fallingPorts[PCINT_NUM_USED_PORTS] = { 0 }; 97 | uint8_t risingPorts[PCINT_NUM_USED_PORTS] = { 0 }; 98 | 99 | void enablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask, const uint8_t arrayPos){ 100 | // Update the old state to the actual state 101 | switch(pcintPort){ 102 | #ifdef PCINT_INPUT_PORT0_USED 103 | case 0: 104 | oldPorts[arrayPos] = PCINT_INPUT_PORT0; 105 | break; 106 | #endif 107 | #ifdef PCINT_INPUT_PORT1_USED 108 | case 1: 109 | oldPorts[arrayPos] = PCINT_INPUT_PORT1; 110 | break; 111 | #endif 112 | #ifdef PCINT_INPUT_PORT2_USED 113 | case 2: 114 | oldPorts[arrayPos] = PCINT_INPUT_PORT2; 115 | break; 116 | #endif 117 | #ifdef PCINT_INPUT_PORT3_USED 118 | case 3: 119 | oldPorts[arrayPos] = PCINT_INPUT_PORT3; 120 | break; 121 | #endif 122 | } 123 | 124 | // Pin change mask registers decide which pins are ENABLE as triggers 125 | #ifdef PCMSK0 126 | #ifdef PCMSK1 127 | #ifdef PCMSK3 128 | // Special case for ATmega1284P where PCMSK3 is not directly after PCMSK2 129 | if(false){ 130 | #else 131 | // Special case for Attinyx4 where PCMSK1 and PCMSK0 are not next to each other 132 | if(&PCMSK1 - &PCMSK0 == 1){ 133 | #endif 134 | #endif 135 | *(&PCMSK0 + pcintPort) |= pcintMask; 136 | #ifdef PCMSK1 137 | } 138 | else{ 139 | switch(pcintPort){ 140 | case 0: 141 | PCMSK0 |= pcintMask; 142 | break; 143 | case 1: 144 | PCMSK1 |= pcintMask; 145 | break; 146 | #ifdef PCMSK2 147 | case 2: 148 | PCMSK2 |= pcintMask; 149 | break; 150 | #endif 151 | #ifdef PCMSK3 152 | case 3: 153 | PCMSK3 |= pcintMask; 154 | break; 155 | #endif 156 | } 157 | } 158 | #endif 159 | #elif defined(PCMSK) 160 | *(&PCMSK + pcintPort) |= pcintMask; 161 | #endif 162 | 163 | // PCICR: Pin Change Interrupt Control Register - enables interrupt vectors 164 | #ifdef PCICR 165 | PCICR |= (1 << (pcintPort + PCIE0)); 166 | #elif defined(GICR) /* e.g. ATmega162 */ 167 | GICR |= (1 << (pcintPort + PCIE0)); 168 | #elif defined(GIMSK) && defined(PCIE0) /* e.g. ATtiny X4 */ 169 | GIMSK |= (1 << (pcintPort + PCIE0)); 170 | #elif defined(GIMSK) && defined(PCIE) /* e.g. ATtiny X5 */ 171 | GIMSK |= (1 << (pcintPort + PCIE)); 172 | #else 173 | #error MCU has no such a register 174 | #endif 175 | } 176 | 177 | void disablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask) { 178 | bool disable = false; 179 | #ifdef PCMSK0 180 | #ifdef PCMSK1 181 | #ifdef PCMSK3 182 | // Special case for ATmega1284P where PCMSK3 is not directly after PCMSK2 183 | if (false){ 184 | #else 185 | // Special case for Attinyx4 where PCMSK1 and PCMSK0 are not next to each other 186 | if (&PCMSK1 - &PCMSK0 == 1) { 187 | #endif // ifdef PCMSK3 188 | #endif // ifdef PCMSK1 189 | // disable the mask. 190 | *(&PCMSK0 + pcintPort) &= ~pcintMask; 191 | 192 | // if that's the last one, disable the interrupt. 193 | if (*(&PCMSK0 + pcintPort) == 0) { 194 | disable = true; 195 | } 196 | #ifdef PCMSK1 197 | } 198 | else { 199 | switch (pcintPort) { 200 | case 0: 201 | // disable the mask. 202 | PCMSK0 &= ~pcintMask; 203 | 204 | // if that's the last one, disable the interrupt. 205 | if (!PCMSK0) { 206 | disable = true; 207 | } 208 | break; 209 | case 1: 210 | // disable the mask. 211 | PCMSK1 &= ~pcintMask; 212 | 213 | // if that's the last one, disable the interrupt. 214 | if (!PCMSK1) { 215 | disable = true; 216 | } 217 | break; 218 | #ifdef PCMSK2 219 | case 2: 220 | // disable the mask. 221 | PCMSK2 &= ~pcintMask; 222 | 223 | // if that's the last one, disable the interrupt. 224 | if (!PCMSK2) { 225 | disable = true; 226 | } 227 | break; 228 | #endif // ifdef PCMSK2 229 | #ifdef PCMSK3 230 | case 3: 231 | // disable the mask. 232 | PCMSK3 &= ~pcintMask; 233 | 234 | // if that's the last one, disable the interrupt. 235 | if (!PCMSK3) { 236 | disable = true; 237 | } 238 | break; 239 | #endif // ifdef PCMSK3 240 | } 241 | } 242 | #endif // ifdef PCMSK1 243 | #elif defined(PCMSK) 244 | // disable the mask. 245 | *(&PCMSK + pcintPort) &= ~pcintMask; 246 | 247 | // if that's the last one, disable the interrupt. 248 | if (*(&PCMSK + pcintPort) == 0) { 249 | disable = true; 250 | } 251 | #endif // ifdef PCMSK0 252 | 253 | if(disable) 254 | { 255 | #ifdef PCICR 256 | PCICR &= ~(1 << (pcintPort + PCIE0)); 257 | #elif defined(GICR) /* e.g. ATmega162 */ 258 | GICR &= ~(1 << (pcintPort + PCIE0)); 259 | #elif defined(GIMSK) && defined(PCIE0) /* e.g. ATtiny X4 */ 260 | GIMSK &= ~(1 << (pcintPort + PCIE0)); 261 | #elif defined(GIMSK) && defined(PCIE) /* e.g. ATtiny X5 */ 262 | GIMSK &= ~(1 << (pcintPort + PCIE)); 263 | #else 264 | #error MCU has no such a register 265 | #endif 266 | } 267 | } 268 | 269 | /* 270 | asm output (nothing to optimize here) 271 | 272 | ISR(PCINT0_vect) { 273 | push r1 274 | push r0 275 | in r0, 0x3f ; 63 276 | push r0 277 | eor r1, r1 278 | push r18 279 | push r19 280 | push r20 281 | push r21 282 | push r22 283 | push r23 284 | push r24 285 | push r25 286 | push r26 287 | push r27 288 | push r28 289 | push r30 290 | push r31 291 | 292 | // get the new and old pin states for port 293 | // uint8_t newPort = pinChangeInterruptPortToInput(port); 294 | in r24, 0x03; 3 //(1) loads byte into newPort from I/O register 295 | 296 | // loads old port and high + low setting 297 | lds r18, 0x011E //(1 or 2) loads oldPorts into register 298 | lds r28, 0x011B //(1 or 2) loads fallingPorts into register 299 | lds r25, 0x0118 //(1 or 2) loads risingPorts into register 300 | 301 | and r28, r18 // oldPorts & fallingPorts 302 | and r25, r24 // newPort & risingPorts 303 | or r28, r25 // (oldPorts & fallingPorts) | (newPort & risingPorts) 304 | eor r18, r24 // oldPorts^newPort 305 | and r28, r18 // ((oldPorts & fallingPorts) | (newPort & risingPorts)) & (oldPorts^newPort) 306 | 307 | // save the new state for next comparison 308 | // oldPorts[arrayPos] = newPort; 309 | sts 0x011E, r24 310 | 311 | // Execute all functions that should be triggered 312 | sbrc r28, 0 313 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 314 | sbrc r28, 1 315 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 316 | sbrc r28, 2 317 | call 0x318 ; 0x318 <_Z20PinChangeInterruptEventPCINT2v> 318 | sbrc r28, 3 319 | call 0x340 ; 0x340 <_Z20PinChangeInterruptEventPCINT3v> 320 | sbrc r28, 4 321 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 322 | sbrc r28, 5 323 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 324 | sbrc r28, 6 325 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 326 | sbrc r28, 7 327 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 328 | 329 | pop r31 330 | pop r30 331 | pop r28 332 | pop r27 333 | pop r26 334 | pop r25 335 | pop r24 336 | pop r23 337 | pop r22 338 | pop r21 339 | pop r20 340 | pop r19 341 | pop r18 342 | pop r0 343 | out 0x3f, r0 ; 63 344 | pop r0 345 | pop r1 346 | reti 347 | } 348 | */ 349 | -------------------------------------------------------------------------------- /src/PinChangeInterrupt.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2021 NicoHood 3 | See the readme for credit to other people. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | // Include Guard 25 | #pragma once 26 | 27 | // Software Version 28 | #define PCINT_VERSION 129 29 | 30 | #include 31 | #include 32 | 33 | #ifdef ARDUINO 34 | #include "Arduino.h" 35 | 36 | #ifndef ARDUINO_ARCH_AVR 37 | #error This library can only be used with AVR 38 | #endif 39 | 40 | #else 41 | 42 | #ifndef LOW 43 | #define LOW 0x0 44 | #endif 45 | #ifndef CHANGE 46 | #define CHANGE 0x1 47 | #endif 48 | #ifndef FALLING 49 | #define FALLING 0x2 50 | #endif 51 | #ifndef RISING 52 | #define RISING 0x3 53 | #endif 54 | 55 | #endif 56 | 57 | //================================================================================ 58 | // General Helper Definitions and Mappings 59 | //================================================================================ 60 | 61 | // Settings and Board definitions are seperated to get an better overview. 62 | // The order and position of the inclusion is important! 63 | #include "PinChangeInterruptSettings.h" 64 | #include "PinChangeInterruptBoards.h" 65 | #include "PinChangeInterruptPins.h" 66 | 67 | #if !PCINT_NUM_USED_PORTS 68 | #error Please enable at least one PCINT port and pin! 69 | #endif 70 | 71 | // manually include cpp files to save flash if only 1 ISR is present 72 | // it includes all ISR files but only the 1 available ISR will/can be compiled 73 | #if (PCINT_NUM_USED_PORTS == 1) 74 | #ifndef PCINT_COMPILE_ENABLED_ISR 75 | #define PCINT_COMPILE_ENABLED_ISR 76 | #endif 77 | #endif 78 | 79 | //================================================================================ 80 | // Makro Definitions 81 | //================================================================================ 82 | 83 | // generates the callback for easier reordering in Settings 84 | #define PCINT_MACRO_BRACKETS () 85 | #define PCINT_MACRO_TRUE == true) 86 | #define PCINT_CALLBACK(bit, pcint) \ 87 | if (PCINT_USE_PCINT ## pcint PCINT_MACRO_TRUE \ 88 | if (trigger & (1 << bit)) \ 89 | PinChangeInterruptEventPCINT ## pcint PCINT_MACRO_BRACKETS 90 | 91 | // definition used by the user to create custom LowLevel PCINT Events 92 | #define PinChangeInterruptEvent_Wrapper(n) PinChangeInterruptEventPCINT ## n 93 | #define PinChangeInterruptEvent(n) PinChangeInterruptEvent_Wrapper(n) 94 | 95 | // missing 1.0.6 definition workaround 96 | #ifndef NOT_AN_INTERRUPT 97 | #define NOT_AN_INTERRUPT -1 98 | #endif 99 | 100 | // convert a normal pin to its PCINT number (0 - max 23), used by the user 101 | // calculates the pin by the Arduino definitions 102 | #if defined(PCIE0) 103 | #define digitalPinToPinChangeInterrupt(p) (digitalPinToPCICR(p) ? ((8 * (digitalPinToPCICRbit(p) - PCIE0)) + digitalPinToPCMSKbit(p)) : NOT_AN_INTERRUPT) 104 | #elif defined(PCIE) 105 | #define digitalPinToPinChangeInterrupt(p) (digitalPinToPCICR(p) ? ((8 * (digitalPinToPCICRbit(p) - PCIE)) + digitalPinToPCMSKbit(p)) : NOT_AN_INTERRUPT) 106 | #else 107 | #error MCU has no such a register 108 | #endif 109 | 110 | // alias for shorter writing 111 | #define PCINTEvent(n) PinChangeInterruptEvent_Wrapper(n) 112 | #define digitalPinToPCINT digitalPinToPinChangeInterrupt 113 | #define attachPCINT attachPinChangeInterrupt 114 | #define enablePCINT enablePinChangeInterrupt 115 | #define detachPCINT detachPinChangeInterrupt 116 | #define disablePCINT disablePinChangeInterrupt 117 | #define getPCINTTrigger getPinChangeInterruptTrigger 118 | 119 | //================================================================================ 120 | // Function Prototypes + Variables 121 | //================================================================================ 122 | 123 | // typedef for our callback function pointers 124 | typedef void(*callback)(void); 125 | 126 | // useless function for weak implemented/not used functions, extern c needed for the alias 127 | #ifdef __cplusplus 128 | extern "C" { 129 | #endif 130 | void pcint_null_callback(void); 131 | #ifdef __cplusplus 132 | } 133 | #endif 134 | 135 | void PinChangeInterruptEventPCINT0(void); 136 | void PinChangeInterruptEventPCINT1(void); 137 | void PinChangeInterruptEventPCINT2(void); 138 | void PinChangeInterruptEventPCINT3(void); 139 | void PinChangeInterruptEventPCINT4(void); 140 | void PinChangeInterruptEventPCINT5(void); 141 | void PinChangeInterruptEventPCINT6(void); 142 | void PinChangeInterruptEventPCINT7(void); 143 | void PinChangeInterruptEventPCINT8(void); 144 | void PinChangeInterruptEventPCINT9(void); 145 | void PinChangeInterruptEventPCINT10(void); 146 | void PinChangeInterruptEventPCINT11(void); 147 | void PinChangeInterruptEventPCINT12(void); 148 | void PinChangeInterruptEventPCINT13(void); 149 | void PinChangeInterruptEventPCINT14(void); 150 | void PinChangeInterruptEventPCINT15(void); 151 | void PinChangeInterruptEventPCINT16(void); 152 | void PinChangeInterruptEventPCINT17(void); 153 | void PinChangeInterruptEventPCINT18(void); 154 | void PinChangeInterruptEventPCINT19(void); 155 | void PinChangeInterruptEventPCINT20(void); 156 | void PinChangeInterruptEventPCINT21(void); 157 | void PinChangeInterruptEventPCINT22(void); 158 | void PinChangeInterruptEventPCINT23(void); 159 | void PinChangeInterruptEventPCINT24(void); 160 | void PinChangeInterruptEventPCINT25(void); 161 | void PinChangeInterruptEventPCINT26(void); 162 | void PinChangeInterruptEventPCINT27(void); 163 | void PinChangeInterruptEventPCINT28(void); 164 | void PinChangeInterruptEventPCINT29(void); 165 | void PinChangeInterruptEventPCINT30(void); 166 | void PinChangeInterruptEventPCINT31(void); 167 | 168 | extern uint8_t oldPorts[PCINT_NUM_USED_PORTS]; 169 | extern uint8_t fallingPorts[PCINT_NUM_USED_PORTS]; 170 | extern uint8_t risingPorts[PCINT_NUM_USED_PORTS]; 171 | 172 | 173 | static inline uint8_t getArrayPosPCINT(uint8_t pcintPort) __attribute__((always_inline)); 174 | uint8_t getArrayPosPCINT(uint8_t pcintPort) { 175 | /* 176 | Maps the port to the array. 177 | This is needed since you can deactivate ports 178 | and the array will dynamically resize to save ram. 179 | 180 | The function does not need that much flash since the if and else 181 | are known at compile time, so the compiler removes all the complex logic. 182 | The return is is the input if all pins are activated for example. 183 | That's why the function is inline. 184 | */ 185 | 186 | if (PCINT_NUM_USED_PORTS == 1) { 187 | // only the first element is used for a single port 188 | return 0; 189 | } 190 | else if (PCINT_NUM_USED_PORTS == PCINT_NUM_PORTS) { 191 | // use all ports and down remap the array position. 192 | return pcintPort; 193 | } 194 | else if (PCINT_NUM_PORTS - PCINT_NUM_USED_PORTS == 1) { 195 | // one port is not used 196 | if (PCINT_USE_PORT0 == 0) { 197 | // first port is not used, decrease all port numbers 198 | return (pcintPort - 1); 199 | } 200 | else if (PCINT_HAS_PORT3 == 0) { 201 | // 3 ports (standard) 202 | if (PCINT_USE_PORT2 == 0) { 203 | // last port not used, no mapping needed 204 | return pcintPort; 205 | } 206 | else { 207 | // worst case, port in the middle not used, remap 208 | return ((pcintPort >> 1) & 0x01); 209 | //if (pcintPort == 0) return 0; 210 | //else return 1; 211 | } 212 | } 213 | else { 214 | // 4 ports (special case for a few AVRs) 215 | if (PCINT_USE_PORT3 == 0) { 216 | // last port not used, no mapping needed 217 | return pcintPort; 218 | } 219 | else { 220 | // worst case, one of two ports in the middle not used, remap 221 | if (PCINT_USE_PORT1 == 0) { 222 | // port1 not used, mapping needed 223 | if (pcintPort == 0) 224 | return 0; 225 | else 226 | return pcintPort - 1; 227 | } 228 | else if (PCINT_USE_PORT2 == 0) { 229 | // port2 not used, mapping needed 230 | if (pcintPort == 3) 231 | return 2; 232 | else 233 | return pcintPort; 234 | } 235 | } 236 | } 237 | 238 | // use all ports and down remap the array position. 239 | return pcintPort; 240 | } 241 | else if (PCINT_NUM_PORTS - PCINT_NUM_USED_PORTS == 2) { 242 | if (PCINT_USE_PORT2 == 0 && PCINT_USE_PORT3 == 0) { 243 | // no need for mapping 244 | return pcintPort; 245 | } 246 | else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT3 == 0) { 247 | // 1 offset 248 | return (pcintPort - 1); 249 | } 250 | else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT1 == 0) { 251 | // 2 offset 252 | return (pcintPort - 2); 253 | } 254 | else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT2 == 0) { 255 | // 2 -> 1 256 | return (pcintPort >> 1); 257 | } 258 | else if (PCINT_USE_PORT1 == 0 && PCINT_USE_PORT2 == 0) { 259 | // 3 -> 1 260 | return (pcintPort >> 1); 261 | } 262 | else if (PCINT_USE_PORT1 == 0 && PCINT_USE_PORT3 == 0) { 263 | // 3 -> 1, 1 -> 0 264 | return (pcintPort >> 1); 265 | } 266 | } 267 | 268 | // error 269 | return 0; 270 | } 271 | 272 | //================================================================================ 273 | // Attach Function (partly inlined) 274 | //================================================================================ 275 | 276 | void enablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask, const uint8_t arrayPos); 277 | void attachPinChangeInterrupt0(void); 278 | void attachPinChangeInterrupt1(void); 279 | void attachPinChangeInterrupt2(void); 280 | void attachPinChangeInterrupt3(void); 281 | 282 | #if defined(PCINT_API) 283 | 284 | /* 285 | for (int i = 0; i < 32; i++) { 286 | Serial.print("#if (PCINT_USE_PCINT"); 287 | Serial.print(i); 288 | Serial.println(" == true)"); 289 | Serial.print("extern volatile callback callbackPCINT"); 290 | Serial.print(i); 291 | Serial.println(";"); 292 | Serial.println("#endif"); 293 | } 294 | */ 295 | #if (PCINT_USE_PCINT0 == true) 296 | extern volatile callback callbackPCINT0; 297 | #endif 298 | #if (PCINT_USE_PCINT1 == true) 299 | extern volatile callback callbackPCINT1; 300 | #endif 301 | #if (PCINT_USE_PCINT2 == true) 302 | extern volatile callback callbackPCINT2; 303 | #endif 304 | #if (PCINT_USE_PCINT3 == true) 305 | extern volatile callback callbackPCINT3; 306 | #endif 307 | #if (PCINT_USE_PCINT4 == true) 308 | extern volatile callback callbackPCINT4; 309 | #endif 310 | #if (PCINT_USE_PCINT5 == true) 311 | extern volatile callback callbackPCINT5; 312 | #endif 313 | #if (PCINT_USE_PCINT6 == true) 314 | extern volatile callback callbackPCINT6; 315 | #endif 316 | #if (PCINT_USE_PCINT7 == true) 317 | extern volatile callback callbackPCINT7; 318 | #endif 319 | #if (PCINT_USE_PCINT8 == true) 320 | extern volatile callback callbackPCINT8; 321 | #endif 322 | #if (PCINT_USE_PCINT9 == true) 323 | extern volatile callback callbackPCINT9; 324 | #endif 325 | #if (PCINT_USE_PCINT10 == true) 326 | extern volatile callback callbackPCINT10; 327 | #endif 328 | #if (PCINT_USE_PCINT11 == true) 329 | extern volatile callback callbackPCINT11; 330 | #endif 331 | #if (PCINT_USE_PCINT12 == true) 332 | extern volatile callback callbackPCINT12; 333 | #endif 334 | #if (PCINT_USE_PCINT13 == true) 335 | extern volatile callback callbackPCINT13; 336 | #endif 337 | #if (PCINT_USE_PCINT14 == true) 338 | extern volatile callback callbackPCINT14; 339 | #endif 340 | #if (PCINT_USE_PCINT15 == true) 341 | extern volatile callback callbackPCINT15; 342 | #endif 343 | #if (PCINT_USE_PCINT16 == true) 344 | extern volatile callback callbackPCINT16; 345 | #endif 346 | #if (PCINT_USE_PCINT17 == true) 347 | extern volatile callback callbackPCINT17; 348 | #endif 349 | #if (PCINT_USE_PCINT18 == true) 350 | extern volatile callback callbackPCINT18; 351 | #endif 352 | #if (PCINT_USE_PCINT19 == true) 353 | extern volatile callback callbackPCINT19; 354 | #endif 355 | #if (PCINT_USE_PCINT20 == true) 356 | extern volatile callback callbackPCINT20; 357 | #endif 358 | #if (PCINT_USE_PCINT21 == true) 359 | extern volatile callback callbackPCINT21; 360 | #endif 361 | #if (PCINT_USE_PCINT22 == true) 362 | extern volatile callback callbackPCINT22; 363 | #endif 364 | #if (PCINT_USE_PCINT23 == true) 365 | extern volatile callback callbackPCINT23; 366 | #endif 367 | #if (PCINT_USE_PCINT24 == true) 368 | extern volatile callback callbackPCINT24; 369 | #endif 370 | #if (PCINT_USE_PCINT25 == true) 371 | extern volatile callback callbackPCINT25; 372 | #endif 373 | #if (PCINT_USE_PCINT26 == true) 374 | extern volatile callback callbackPCINT26; 375 | #endif 376 | #if (PCINT_USE_PCINT27 == true) 377 | extern volatile callback callbackPCINT27; 378 | #endif 379 | #if (PCINT_USE_PCINT28 == true) 380 | extern volatile callback callbackPCINT28; 381 | #endif 382 | #if (PCINT_USE_PCINT29 == true) 383 | extern volatile callback callbackPCINT29; 384 | #endif 385 | #if (PCINT_USE_PCINT30 == true) 386 | extern volatile callback callbackPCINT30; 387 | #endif 388 | #if (PCINT_USE_PCINT31 == true) 389 | extern volatile callback callbackPCINT31; 390 | #endif 391 | 392 | /* 393 | for (int i = 0; i < 32; i++) { 394 | Serial.print("#if (PCINT_USE_PCINT"); 395 | Serial.print(i); 396 | Serial.println(" == true)"); 397 | Serial.print("if (pcintNum == "); 398 | Serial.print(i); 399 | Serial.println(")"); 400 | Serial.print("callbackPCINT"); 401 | Serial.print(i); 402 | Serial.println(" = userFunc;"); 403 | Serial.println("#endif"); 404 | } 405 | */ 406 | 407 | // API attach function 408 | static inline void attachPinChangeInterrupt(const uint8_t pcintNum, void(*userFunc)(void), const uint8_t mode) __attribute__((always_inline)); 409 | void attachPinChangeInterrupt(const uint8_t pcintNum, void(*userFunc)(void), const uint8_t mode) { 410 | #else // no API attach function 411 | static inline void attachPinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) __attribute__((always_inline)); 412 | void attachPinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) { 413 | #endif // PCINT_API 414 | 415 | // check if pcint is a valid pcint, exclude deactivated ports 416 | uint8_t pcintPort = pcintNum / 8; 417 | uint8_t pcintBit = pcintNum % 8; 418 | 419 | // port 0 420 | if (pcintPort == 0 && PCINT_USE_PORT0 == true) { 421 | // use fake functions to make the ISRs compile with .a linkage 422 | #if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR) 423 | attachPinChangeInterrupt0(); 424 | #endif 425 | 426 | // attache the function pointers for the API 427 | #if defined(PCINT_API) 428 | #if (PCINT_USE_PCINT0 == true) 429 | if (pcintNum == 0) 430 | callbackPCINT0 = userFunc; 431 | #endif 432 | #if (PCINT_USE_PCINT1 == true) 433 | if (pcintNum == 1) 434 | callbackPCINT1 = userFunc; 435 | #endif 436 | #if (PCINT_USE_PCINT2 == true) 437 | if (pcintNum == 2) 438 | callbackPCINT2 = userFunc; 439 | #endif 440 | #if (PCINT_USE_PCINT3 == true) 441 | if (pcintNum == 3) 442 | callbackPCINT3 = userFunc; 443 | #endif 444 | #if (PCINT_USE_PCINT4 == true) 445 | if (pcintNum == 4) 446 | callbackPCINT4 = userFunc; 447 | #endif 448 | #if (PCINT_USE_PCINT5 == true) 449 | if (pcintNum == 5) 450 | callbackPCINT5 = userFunc; 451 | #endif 452 | #if (PCINT_USE_PCINT6 == true) 453 | if (pcintNum == 6) 454 | callbackPCINT6 = userFunc; 455 | #endif 456 | #if (PCINT_USE_PCINT7 == true) 457 | if (pcintNum == 7) 458 | callbackPCINT7 = userFunc; 459 | #endif 460 | #endif // PCINT_API 461 | } 462 | 463 | // port 1 464 | else if (pcintPort == 1 && PCINT_USE_PORT1 == true) { 465 | // use fake functions to make the ISRs compile with .a linkage 466 | #if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR) 467 | attachPinChangeInterrupt1(); 468 | #endif 469 | 470 | // attache the function pointers for the API 471 | #if defined(PCINT_API) 472 | #if (PCINT_USE_PCINT8 == true) 473 | if (pcintNum == 8) 474 | callbackPCINT8 = userFunc; 475 | #endif 476 | #if (PCINT_USE_PCINT9 == true) 477 | if (pcintNum == 9) 478 | callbackPCINT9 = userFunc; 479 | #endif 480 | #if (PCINT_USE_PCINT10 == true) 481 | if (pcintNum == 10) 482 | callbackPCINT10 = userFunc; 483 | #endif 484 | #if (PCINT_USE_PCINT11 == true) 485 | if (pcintNum == 11) 486 | callbackPCINT11 = userFunc; 487 | #endif 488 | #if (PCINT_USE_PCINT12 == true) 489 | if (pcintNum == 12) 490 | callbackPCINT12 = userFunc; 491 | #endif 492 | #if (PCINT_USE_PCINT13 == true) 493 | if (pcintNum == 13) 494 | callbackPCINT13 = userFunc; 495 | #endif 496 | #if (PCINT_USE_PCINT14 == true) 497 | if (pcintNum == 14) 498 | callbackPCINT14 = userFunc; 499 | #endif 500 | #if (PCINT_USE_PCINT15 == true) 501 | if (pcintNum == 15) 502 | callbackPCINT15 = userFunc; 503 | #endif 504 | #endif // PCINT_API 505 | } 506 | 507 | // port 2 508 | else if (pcintPort == 2 && PCINT_USE_PORT2 == true) { 509 | // use fake functions to make the ISRs compile with .a linkage 510 | #if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR) 511 | attachPinChangeInterrupt2(); 512 | #endif 513 | // attache the function pointers for the API 514 | #if defined(PCINT_API) 515 | #if (PCINT_USE_PCINT16 == true) 516 | if (pcintNum == 16) 517 | callbackPCINT16 = userFunc; 518 | #endif 519 | #if (PCINT_USE_PCINT17 == true) 520 | if (pcintNum == 17) 521 | callbackPCINT17 = userFunc; 522 | #endif 523 | #if (PCINT_USE_PCINT18 == true) 524 | if (pcintNum == 18) 525 | callbackPCINT18 = userFunc; 526 | #endif 527 | #if (PCINT_USE_PCINT19 == true) 528 | if (pcintNum == 19) 529 | callbackPCINT19 = userFunc; 530 | #endif 531 | #if (PCINT_USE_PCINT20 == true) 532 | if (pcintNum == 20) 533 | callbackPCINT20 = userFunc; 534 | #endif 535 | #if (PCINT_USE_PCINT21 == true) 536 | if (pcintNum == 21) 537 | callbackPCINT21 = userFunc; 538 | #endif 539 | #if (PCINT_USE_PCINT22 == true) 540 | if (pcintNum == 22) 541 | callbackPCINT22 = userFunc; 542 | #endif 543 | #if (PCINT_USE_PCINT23 == true) 544 | if (pcintNum == 23) 545 | callbackPCINT23 = userFunc; 546 | #endif 547 | #endif // PCINT_API 548 | } 549 | 550 | // port 3 551 | else if (pcintPort == 3 && PCINT_USE_PORT3 == true) { 552 | // use fake functions to make the ISRs compile with .a linkage 553 | #if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR) 554 | attachPinChangeInterrupt3(); 555 | #endif 556 | // attache the function pointers for the API 557 | #if defined(PCINT_API) 558 | #if (PCINT_USE_PCINT24 == true) 559 | if (pcintNum == 24) 560 | callbackPCINT24 = userFunc; 561 | #endif 562 | #if (PCINT_USE_PCINT25 == true) 563 | if (pcintNum == 25) 564 | callbackPCINT25 = userFunc; 565 | #endif 566 | #if (PCINT_USE_PCINT26 == true) 567 | if (pcintNum == 26) 568 | callbackPCINT26 = userFunc; 569 | #endif 570 | #if (PCINT_USE_PCINT27 == true) 571 | if (pcintNum == 27) 572 | callbackPCINT27 = userFunc; 573 | #endif 574 | #if (PCINT_USE_PCINT28 == true) 575 | if (pcintNum == 28) 576 | callbackPCINT28 = userFunc; 577 | #endif 578 | #if (PCINT_USE_PCINT29 == true) 579 | if (pcintNum == 29) 580 | callbackPCINT29 = userFunc; 581 | #endif 582 | #if (PCINT_USE_PCINT30 == true) 583 | if (pcintNum == 30) 584 | callbackPCINT30 = userFunc; 585 | #endif 586 | #if (PCINT_USE_PCINT31 == true) 587 | if (pcintNum == 31) 588 | callbackPCINT31 = userFunc; 589 | #endif 590 | #endif // PCINT_API 591 | } 592 | else return; 593 | 594 | // get bitmask and array position 595 | uint8_t pcintMask = (1 << pcintBit); 596 | uint8_t arrayPos = getArrayPosPCINT(pcintPort); 597 | 598 | // save settings related to mode and registers 599 | if (mode == CHANGE || mode == RISING) 600 | risingPorts[arrayPos] |= pcintMask; 601 | if (mode == CHANGE || mode == FALLING) 602 | fallingPorts[arrayPos] |= pcintMask; 603 | 604 | // call the actual hardware attach function 605 | enablePinChangeInterruptHelper(pcintPort, pcintMask, arrayPos); 606 | } 607 | 608 | // enable interrupt again if temporary disabled 609 | static inline void enablePinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline)); 610 | void enablePinChangeInterrupt(const uint8_t pcintNum) { 611 | // get PCINT registers 612 | uint8_t pcintPort = pcintNum / 8; 613 | uint8_t pcintBit = pcintNum % 8; 614 | 615 | // check if pcint is a valid pcint, exclude deactivated ports 616 | if (pcintPort == 0) { 617 | if (PCINT_USE_PORT0 == false) 618 | return; 619 | } 620 | else if (pcintPort == 1) { 621 | if (PCINT_USE_PORT1 == false) 622 | return; 623 | } 624 | else if (pcintPort == 2) { 625 | if (PCINT_USE_PORT2 == false) 626 | return; 627 | } 628 | else if (pcintPort == 3) { 629 | if (PCINT_USE_PORT3 == false) 630 | return; 631 | } 632 | else return; 633 | 634 | // call the actual hardware attach function 635 | uint8_t pcintMask = (1 << pcintBit); 636 | uint8_t arrayPos = getArrayPosPCINT(pcintPort); 637 | enablePinChangeInterruptHelper(pcintPort, pcintMask, arrayPos); 638 | } 639 | 640 | 641 | //================================================================================ 642 | // Detach Function (partly inlined) 643 | //================================================================================ 644 | 645 | void disablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask); 646 | static inline void detachPinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline)); 647 | 648 | void detachPinChangeInterrupt(const uint8_t pcintNum) { 649 | // get PCINT registers 650 | uint8_t pcintPort = pcintNum / 8; 651 | uint8_t pcintBit = pcintNum % 8; 652 | 653 | // check if pcint is a valid pcint, exclude deactivated ports 654 | // port 0 655 | if (pcintPort == 0 && PCINT_USE_PORT0 == true) { 656 | // attache the function pointers for the API 657 | #if defined(PCINT_API) 658 | #if (PCINT_USE_PCINT0 == true) 659 | if (pcintNum == 0) 660 | callbackPCINT0 = pcint_null_callback; 661 | #endif 662 | #if (PCINT_USE_PCINT1 == true) 663 | if (pcintNum == 1) 664 | callbackPCINT1 = pcint_null_callback; 665 | #endif 666 | #if (PCINT_USE_PCINT2 == true) 667 | if (pcintNum == 2) 668 | callbackPCINT2 = pcint_null_callback; 669 | #endif 670 | #if (PCINT_USE_PCINT3 == true) 671 | if (pcintNum == 3) 672 | callbackPCINT3 = pcint_null_callback; 673 | #endif 674 | #if (PCINT_USE_PCINT4 == true) 675 | if (pcintNum == 4) 676 | callbackPCINT4 = pcint_null_callback; 677 | #endif 678 | #if (PCINT_USE_PCINT5 == true) 679 | if (pcintNum == 5) 680 | callbackPCINT5 = pcint_null_callback; 681 | #endif 682 | #if (PCINT_USE_PCINT6 == true) 683 | if (pcintNum == 6) 684 | callbackPCINT6 = pcint_null_callback; 685 | #endif 686 | #if (PCINT_USE_PCINT7 == true) 687 | if (pcintNum == 7) 688 | callbackPCINT7 = pcint_null_callback; 689 | #endif 690 | #endif // PCINT_API 691 | } 692 | 693 | // port 1 694 | else if (pcintPort == 1 && PCINT_USE_PORT1 == true) { 695 | // attache the function pointers for the API 696 | #if defined(PCINT_API) 697 | #if (PCINT_USE_PCINT8 == true) 698 | if (pcintNum == 8) 699 | callbackPCINT8 = pcint_null_callback; 700 | #endif 701 | #if (PCINT_USE_PCINT9 == true) 702 | if (pcintNum == 9) 703 | callbackPCINT9 = pcint_null_callback; 704 | #endif 705 | #if (PCINT_USE_PCINT10 == true) 706 | if (pcintNum == 10) 707 | callbackPCINT10 = pcint_null_callback; 708 | #endif 709 | #if (PCINT_USE_PCINT11 == true) 710 | if (pcintNum == 11) 711 | callbackPCINT11 = pcint_null_callback; 712 | #endif 713 | #if (PCINT_USE_PCINT12 == true) 714 | if (pcintNum == 12) 715 | callbackPCINT12 = pcint_null_callback; 716 | #endif 717 | #if (PCINT_USE_PCINT13 == true) 718 | if (pcintNum == 13) 719 | callbackPCINT13 = pcint_null_callback; 720 | #endif 721 | #if (PCINT_USE_PCINT14 == true) 722 | if (pcintNum == 14) 723 | callbackPCINT14 = pcint_null_callback; 724 | #endif 725 | #if (PCINT_USE_PCINT15 == true) 726 | if (pcintNum == 15) 727 | callbackPCINT15 = pcint_null_callback; 728 | #endif 729 | #endif // PCINT_API 730 | } 731 | 732 | // port 2 733 | else if (pcintPort == 2 && PCINT_USE_PORT2 == true) { 734 | // attache the function pointers for the API 735 | #if defined(PCINT_API) 736 | #if (PCINT_USE_PCINT16 == true) 737 | if (pcintNum == 16) 738 | callbackPCINT16 = pcint_null_callback; 739 | #endif 740 | #if (PCINT_USE_PCINT17 == true) 741 | if (pcintNum == 17) 742 | callbackPCINT17 = pcint_null_callback; 743 | #endif 744 | #if (PCINT_USE_PCINT18 == true) 745 | if (pcintNum == 18) 746 | callbackPCINT18 = pcint_null_callback; 747 | #endif 748 | #if (PCINT_USE_PCINT19 == true) 749 | if (pcintNum == 19) 750 | callbackPCINT19 = pcint_null_callback; 751 | #endif 752 | #if (PCINT_USE_PCINT20 == true) 753 | if (pcintNum == 20) 754 | callbackPCINT20 = pcint_null_callback; 755 | #endif 756 | #if (PCINT_USE_PCINT21 == true) 757 | if (pcintNum == 21) 758 | callbackPCINT21 = pcint_null_callback; 759 | #endif 760 | #if (PCINT_USE_PCINT22 == true) 761 | if (pcintNum == 22) 762 | callbackPCINT22 = pcint_null_callback; 763 | #endif 764 | #if (PCINT_USE_PCINT23 == true) 765 | if (pcintNum == 23) 766 | callbackPCINT23 = pcint_null_callback; 767 | #endif 768 | #endif // PCINT_API 769 | } 770 | 771 | // port 3 772 | else if (pcintPort == 3 && PCINT_USE_PORT3 == true) { 773 | // attache the function pointers for the API 774 | #if defined(PCINT_API) 775 | #if (PCINT_USE_PCINT24 == true) 776 | if (pcintNum == 24) 777 | callbackPCINT24 = pcint_null_callback; 778 | #endif 779 | #if (PCINT_USE_PCINT25 == true) 780 | if (pcintNum == 25) 781 | callbackPCINT25 = pcint_null_callback; 782 | #endif 783 | #if (PCINT_USE_PCINT26 == true) 784 | if (pcintNum == 26) 785 | callbackPCINT26 = pcint_null_callback; 786 | #endif 787 | #if (PCINT_USE_PCINT27 == true) 788 | if (pcintNum == 27) 789 | callbackPCINT27 = pcint_null_callback; 790 | #endif 791 | #if (PCINT_USE_PCINT28 == true) 792 | if (pcintNum == 28) 793 | callbackPCINT28 = pcint_null_callback; 794 | #endif 795 | #if (PCINT_USE_PCINT29 == true) 796 | if (pcintNum == 29) 797 | callbackPCINT29 = pcint_null_callback; 798 | #endif 799 | #if (PCINT_USE_PCINT30 == true) 800 | if (pcintNum == 30) 801 | callbackPCINT30 = pcint_null_callback; 802 | #endif 803 | #if (PCINT_USE_PCINT31 == true) 804 | if (pcintNum == 31) 805 | callbackPCINT31 = pcint_null_callback; 806 | #endif 807 | #endif // PCINT_API 808 | } 809 | else return; 810 | 811 | // get bitmask and array position 812 | uint8_t pcintMask = (1 << pcintBit); 813 | uint8_t arrayPos = getArrayPosPCINT(pcintPort); 814 | 815 | // delete setting 816 | risingPorts[arrayPos] &= ~pcintMask; 817 | fallingPorts[arrayPos] &= ~pcintMask; 818 | 819 | // call the actual hardware disable function 820 | disablePinChangeInterruptHelper(pcintPort, pcintMask); 821 | } 822 | 823 | static inline void disablePinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline)); 824 | void disablePinChangeInterrupt(const uint8_t pcintNum) { 825 | // get PCINT registers 826 | uint8_t pcintPort = pcintNum / 8; 827 | uint8_t pcintBit = pcintNum % 8; 828 | 829 | // check if pcint is a valid pcint, exclude deactivated ports 830 | if (pcintPort == 0) { 831 | if (PCINT_USE_PORT0 == false) 832 | return; 833 | } 834 | else if (pcintPort == 1) { 835 | if (PCINT_USE_PORT1 == false) 836 | return; 837 | } 838 | else if (pcintPort == 2) { 839 | if (PCINT_USE_PORT2 == false) 840 | return; 841 | } 842 | else if (pcintPort == 3) { 843 | if (PCINT_USE_PORT3 == false) 844 | return; 845 | } 846 | else return; 847 | 848 | // get bitmask 849 | uint8_t pcintMask = (1 << pcintBit); 850 | 851 | // Do not delete mode settings nor detach the user function 852 | // Just turn off interrupts 853 | 854 | // call the actual hardware disable function 855 | disablePinChangeInterruptHelper(pcintPort, pcintMask); 856 | } 857 | 858 | //================================================================================ 859 | // getTrigger Function (inlined) 860 | //================================================================================ 861 | 862 | static inline uint8_t getPinChangeInterruptTrigger(const uint8_t pcintNum) __attribute__((always_inline)); 863 | uint8_t getPinChangeInterruptTrigger(const uint8_t pcintNum) { 864 | // get PCINT registers 865 | uint8_t pcintPort = pcintNum / 8; 866 | uint8_t pcintBit = pcintNum % 8; 867 | 868 | // check if pcint is a valid pcint, exclude deactivated ports 869 | if (pcintPort == 0) { 870 | if (PCINT_USE_PORT0 == false) 871 | return CHANGE; 872 | } 873 | else if (pcintPort == 1) { 874 | if (PCINT_USE_PORT1 == false) 875 | return CHANGE; 876 | } 877 | else if (pcintPort == 2) { 878 | if (PCINT_USE_PORT2 == false) 879 | return CHANGE; 880 | } 881 | else if (pcintPort == 3) { 882 | if (PCINT_USE_PORT3 == false) 883 | return CHANGE; 884 | } 885 | else return CHANGE; 886 | 887 | uint8_t arrayPos = getArrayPosPCINT(pcintPort); 888 | 889 | // Check if no mode was set, return an error 890 | if(!(risingPorts[arrayPos] & (1 << pcintBit)) && !(fallingPorts[arrayPos] & (1 << pcintBit))) 891 | return CHANGE; 892 | 893 | // specify the CHANGE mode 894 | if (oldPorts[arrayPos] & (1 << pcintBit)) 895 | return RISING; 896 | else 897 | return FALLING; 898 | } 899 | -------------------------------------------------------------------------------- /src/PinChangeInterrupt0.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2021 NicoHood 3 | See the readme for credit to other people. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | #include "PinChangeInterrupt.h" 25 | 26 | //================================================================================ 27 | // Interrupt Handler 28 | //================================================================================ 29 | 30 | // prevent compilation twice if included from the .cpp to force compile all ISRs 31 | #if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \ 32 | || !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR) 33 | 34 | #if (PCINT_USE_PORT0 == true) 35 | 36 | void attachPinChangeInterrupt0(void) { 37 | // fake function to make the IDE link this file 38 | } 39 | 40 | ISR(PCINT0_vect) { 41 | // get the new and old pin states for port 42 | uint8_t newPort = PCINT_INPUT_PORT0; 43 | 44 | // compare with the old value to detect a rising or falling 45 | uint8_t arrayPos = getArrayPosPCINT(0); 46 | uint8_t change = newPort ^ oldPorts[arrayPos]; 47 | uint8_t rising = change & newPort; 48 | uint8_t falling = change & oldPorts[arrayPos]; 49 | 50 | // check which pins are triggered, compared with the settings 51 | uint8_t risingTrigger = rising & risingPorts[arrayPos]; 52 | uint8_t fallingTrigger = falling & fallingPorts[arrayPos]; 53 | uint8_t trigger = risingTrigger | fallingTrigger; 54 | 55 | // save the new state for next comparison 56 | oldPorts[arrayPos] = newPort; 57 | 58 | // Execute all functions that should be triggered 59 | // This way we can exclude a single function 60 | // and the calling is also much faster 61 | // We may also reorder the pins for different priority 62 | #if !defined(PCINT_CALLBACK_PORT0) 63 | PCINT_CALLBACK(0, 0); 64 | PCINT_CALLBACK(1, 1); 65 | PCINT_CALLBACK(2, 2); 66 | PCINT_CALLBACK(3, 3); 67 | PCINT_CALLBACK(4, 4); 68 | PCINT_CALLBACK(5, 5); 69 | PCINT_CALLBACK(6, 6); 70 | PCINT_CALLBACK(7, 7); 71 | #else 72 | PCINT_CALLBACK_PORT0 73 | #endif 74 | } 75 | 76 | #if defined(PCINT_API) 77 | 78 | /* 79 | for (int i = 0; i < 32; i++) { 80 | Serial.print("#if (PCINT_USE_PCINT"); 81 | Serial.print(i); 82 | Serial.println(" == true)"); 83 | Serial.print("volatile callback callbackPCINT"); 84 | Serial.print(i); 85 | Serial.println(" = pcint_null_callback;"); 86 | Serial.print("void PinChangeInterruptEventPCINT"); 87 | Serial.print(i); 88 | Serial.println("(void){"); 89 | Serial.print(" callbackPCINT"); 90 | Serial.print(i); 91 | Serial.println("();"); 92 | Serial.println("}"); 93 | Serial.println("#endif"); 94 | } 95 | */ 96 | #if (PCINT_USE_PCINT0 == true) 97 | volatile callback callbackPCINT0 = pcint_null_callback; 98 | void PinChangeInterruptEventPCINT0(void) { 99 | callbackPCINT0(); 100 | } 101 | #endif 102 | #if (PCINT_USE_PCINT1 == true) 103 | volatile callback callbackPCINT1 = pcint_null_callback; 104 | void PinChangeInterruptEventPCINT1(void) { 105 | callbackPCINT1(); 106 | } 107 | #endif 108 | #if (PCINT_USE_PCINT2 == true) 109 | volatile callback callbackPCINT2 = pcint_null_callback; 110 | void PinChangeInterruptEventPCINT2(void) { 111 | callbackPCINT2(); 112 | } 113 | #endif 114 | #if (PCINT_USE_PCINT3 == true) 115 | volatile callback callbackPCINT3 = pcint_null_callback; 116 | void PinChangeInterruptEventPCINT3(void) { 117 | callbackPCINT3(); 118 | } 119 | #endif 120 | #if (PCINT_USE_PCINT4 == true) 121 | volatile callback callbackPCINT4 = pcint_null_callback; 122 | void PinChangeInterruptEventPCINT4(void) { 123 | callbackPCINT4(); 124 | } 125 | #endif 126 | #if (PCINT_USE_PCINT5 == true) 127 | volatile callback callbackPCINT5 = pcint_null_callback; 128 | void PinChangeInterruptEventPCINT5(void) { 129 | callbackPCINT5(); 130 | } 131 | #endif 132 | #if (PCINT_USE_PCINT6 == true) 133 | volatile callback callbackPCINT6 = pcint_null_callback; 134 | void PinChangeInterruptEventPCINT6(void) { 135 | callbackPCINT6(); 136 | } 137 | #endif 138 | #if (PCINT_USE_PCINT7 == true) 139 | volatile callback callbackPCINT7 = pcint_null_callback; 140 | void PinChangeInterruptEventPCINT7(void) { 141 | callbackPCINT7(); 142 | } 143 | #endif 144 | 145 | #endif // PCINT_API 146 | 147 | #endif // PCINT_USE_PORT0 148 | 149 | #endif // PCINT_INCLUDE_FROM_CPP 150 | -------------------------------------------------------------------------------- /src/PinChangeInterrupt1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2021 NicoHood 3 | See the readme for credit to other people. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | #include "PinChangeInterrupt.h" 25 | 26 | //================================================================================ 27 | // Interrupt Handler 28 | //================================================================================ 29 | 30 | // prevent compilation twice if included from the .cpp to force compile all ISRs 31 | #if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \ 32 | || !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR) 33 | 34 | #if (PCINT_USE_PORT1 == true) 35 | 36 | void attachPinChangeInterrupt1(void) { 37 | // fake function to make the IDE link this file 38 | } 39 | 40 | ISR(PCINT1_vect) { 41 | // get the new and old pin states for port 42 | uint8_t newPort = PCINT_INPUT_PORT1; 43 | 44 | // compare with the old value to detect a rising or falling 45 | uint8_t arrayPos = getArrayPosPCINT(1); 46 | uint8_t change = newPort ^ oldPorts[arrayPos]; 47 | uint8_t rising = change & newPort; 48 | uint8_t falling = change & oldPorts[arrayPos]; 49 | 50 | // check which pins are triggered, compared with the settings 51 | uint8_t risingTrigger = rising & risingPorts[arrayPos]; 52 | uint8_t fallingTrigger = falling & fallingPorts[arrayPos]; 53 | uint8_t trigger = risingTrigger | fallingTrigger; 54 | 55 | // save the new state for next comparison 56 | oldPorts[arrayPos] = newPort; 57 | 58 | // Execute all functions that should be triggered 59 | // This way we can exclude a single function 60 | // and the calling is also much faster 61 | // We may also reorder the pins for different priority 62 | #if !defined(PCINT_CALLBACK_PORT1) 63 | PCINT_CALLBACK(0, 8); 64 | PCINT_CALLBACK(1, 9); 65 | PCINT_CALLBACK(2, 10); 66 | PCINT_CALLBACK(3, 11); 67 | PCINT_CALLBACK(4, 12); 68 | PCINT_CALLBACK(5, 13); 69 | PCINT_CALLBACK(6, 14); 70 | PCINT_CALLBACK(7, 15); 71 | #else 72 | PCINT_CALLBACK_PORT1 73 | #endif 74 | } 75 | 76 | #if defined(PCINT_API) 77 | 78 | /* 79 | for (int i = 0; i < 32; i++) { 80 | Serial.print("#if (PCINT_USE_PCINT"); 81 | Serial.print(i); 82 | Serial.println(" == true)"); 83 | Serial.print("volatile callback callbackPCINT"); 84 | Serial.print(i); 85 | Serial.println(" = pcint_null_callback;"); 86 | Serial.print("void PinChangeInterruptEventPCINT"); 87 | Serial.print(i); 88 | Serial.println("(void){"); 89 | Serial.print(" callbackPCINT"); 90 | Serial.print(i); 91 | Serial.println("();"); 92 | Serial.println("}"); 93 | Serial.println("#endif"); 94 | } 95 | */ 96 | #if (PCINT_USE_PCINT8 == true) 97 | volatile callback callbackPCINT8 = pcint_null_callback; 98 | void PinChangeInterruptEventPCINT8(void) { 99 | callbackPCINT8(); 100 | } 101 | #endif 102 | #if (PCINT_USE_PCINT9 == true) 103 | volatile callback callbackPCINT9 = pcint_null_callback; 104 | void PinChangeInterruptEventPCINT9(void) { 105 | callbackPCINT9(); 106 | } 107 | #endif 108 | #if (PCINT_USE_PCINT10 == true) 109 | volatile callback callbackPCINT10 = pcint_null_callback; 110 | void PinChangeInterruptEventPCINT10(void) { 111 | callbackPCINT10(); 112 | } 113 | #endif 114 | #if (PCINT_USE_PCINT11 == true) 115 | volatile callback callbackPCINT11 = pcint_null_callback; 116 | void PinChangeInterruptEventPCINT11(void) { 117 | callbackPCINT11(); 118 | } 119 | #endif 120 | #if (PCINT_USE_PCINT12 == true) 121 | volatile callback callbackPCINT12 = pcint_null_callback; 122 | void PinChangeInterruptEventPCINT12(void) { 123 | callbackPCINT12(); 124 | } 125 | #endif 126 | #if (PCINT_USE_PCINT13 == true) 127 | volatile callback callbackPCINT13 = pcint_null_callback; 128 | void PinChangeInterruptEventPCINT13(void) { 129 | callbackPCINT13(); 130 | } 131 | #endif 132 | #if (PCINT_USE_PCINT14 == true) 133 | volatile callback callbackPCINT14 = pcint_null_callback; 134 | void PinChangeInterruptEventPCINT14(void) { 135 | callbackPCINT14(); 136 | } 137 | #endif 138 | #if (PCINT_USE_PCINT15 == true) 139 | volatile callback callbackPCINT15 = pcint_null_callback; 140 | void PinChangeInterruptEventPCINT15(void) { 141 | callbackPCINT15(); 142 | } 143 | #endif 144 | 145 | #endif // PCINT_API 146 | 147 | #endif // PCINT_USE_PORT1 148 | 149 | #endif // PCINT_INCLUDE_FROM_CPP 150 | -------------------------------------------------------------------------------- /src/PinChangeInterrupt2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2021 NicoHood 3 | See the readme for credit to other people. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | #include "PinChangeInterrupt.h" 25 | 26 | //================================================================================ 27 | // Interrupt Handler 28 | //================================================================================ 29 | 30 | // prevent compilation twice if included from the .cpp to force compile all ISRs 31 | #if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \ 32 | || !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR) 33 | 34 | #if (PCINT_USE_PORT2 == true) 35 | 36 | void attachPinChangeInterrupt2(void) { 37 | // fake function to make the IDE link this file 38 | } 39 | 40 | ISR(PCINT2_vect) { 41 | // get the new and old pin states for port 42 | uint8_t newPort = PCINT_INPUT_PORT2; 43 | 44 | // compare with the old value to detect a rising or falling 45 | uint8_t arrayPos = getArrayPosPCINT(2); 46 | uint8_t change = newPort ^ oldPorts[arrayPos]; 47 | uint8_t rising = change & newPort; 48 | uint8_t falling = change & oldPorts[arrayPos]; 49 | 50 | // check which pins are triggered, compared with the settings 51 | uint8_t risingTrigger = rising & risingPorts[arrayPos]; 52 | uint8_t fallingTrigger = falling & fallingPorts[arrayPos]; 53 | uint8_t trigger = risingTrigger | fallingTrigger; 54 | 55 | // save the new state for next comparison 56 | oldPorts[arrayPos] = newPort; 57 | 58 | // Execute all functions that should be triggered 59 | // This way we can exclude a single function 60 | // and the calling is also much faster 61 | // We may also reorder the pins for different priority 62 | #if !defined(PCINT_CALLBACK_PORT2) 63 | PCINT_CALLBACK(0, 16); 64 | PCINT_CALLBACK(1, 17); 65 | PCINT_CALLBACK(2, 18); 66 | PCINT_CALLBACK(3, 19); 67 | PCINT_CALLBACK(4, 20); 68 | PCINT_CALLBACK(5, 21); 69 | PCINT_CALLBACK(6, 22); 70 | PCINT_CALLBACK(7, 23); 71 | #else 72 | PCINT_CALLBACK_PORT2 73 | #endif 74 | } 75 | 76 | #if defined(PCINT_API) 77 | 78 | /* 79 | for (int i = 0; i < 32; i++) { 80 | Serial.print("#if (PCINT_USE_PCINT"); 81 | Serial.print(i); 82 | Serial.println(" == true)"); 83 | Serial.print("volatile callback callbackPCINT"); 84 | Serial.print(i); 85 | Serial.println(" = pcint_null_callback;"); 86 | Serial.print("void PinChangeInterruptEventPCINT"); 87 | Serial.print(i); 88 | Serial.println("(void){"); 89 | Serial.print(" callbackPCINT"); 90 | Serial.print(i); 91 | Serial.println("();"); 92 | Serial.println("}"); 93 | Serial.println("#endif"); 94 | } 95 | */ 96 | #if (PCINT_USE_PCINT16 == true) 97 | volatile callback callbackPCINT16 = pcint_null_callback; 98 | void PinChangeInterruptEventPCINT16(void) { 99 | callbackPCINT16(); 100 | } 101 | #endif 102 | #if (PCINT_USE_PCINT17 == true) 103 | volatile callback callbackPCINT17 = pcint_null_callback; 104 | void PinChangeInterruptEventPCINT17(void) { 105 | callbackPCINT17(); 106 | } 107 | #endif 108 | #if (PCINT_USE_PCINT18 == true) 109 | volatile callback callbackPCINT18 = pcint_null_callback; 110 | void PinChangeInterruptEventPCINT18(void) { 111 | callbackPCINT18(); 112 | } 113 | #endif 114 | #if (PCINT_USE_PCINT19 == true) 115 | volatile callback callbackPCINT19 = pcint_null_callback; 116 | void PinChangeInterruptEventPCINT19(void) { 117 | callbackPCINT19(); 118 | } 119 | #endif 120 | #if (PCINT_USE_PCINT20 == true) 121 | volatile callback callbackPCINT20 = pcint_null_callback; 122 | void PinChangeInterruptEventPCINT20(void) { 123 | callbackPCINT20(); 124 | } 125 | #endif 126 | #if (PCINT_USE_PCINT21 == true) 127 | volatile callback callbackPCINT21 = pcint_null_callback; 128 | void PinChangeInterruptEventPCINT21(void) { 129 | callbackPCINT21(); 130 | } 131 | #endif 132 | #if (PCINT_USE_PCINT22 == true) 133 | volatile callback callbackPCINT22 = pcint_null_callback; 134 | void PinChangeInterruptEventPCINT22(void) { 135 | callbackPCINT22(); 136 | } 137 | #endif 138 | #if (PCINT_USE_PCINT23 == true) 139 | volatile callback callbackPCINT23 = pcint_null_callback; 140 | void PinChangeInterruptEventPCINT23(void) { 141 | callbackPCINT23(); 142 | } 143 | #endif 144 | 145 | #endif // PCINT_API 146 | 147 | #endif // PCINT_USE_PORT2 148 | 149 | #endif // PCINT_INCLUDE_FROM_CPP 150 | -------------------------------------------------------------------------------- /src/PinChangeInterrupt3.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2021 NicoHood 3 | See the readme for credit to other people. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | #include "PinChangeInterrupt.h" 25 | 26 | //================================================================================ 27 | // Interrupt Handler 28 | //================================================================================ 29 | 30 | // prevent compilation twice if included from the .cpp to force compile all ISRs 31 | #if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \ 32 | || !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR) 33 | 34 | #if (PCINT_USE_PORT3 == true) 35 | 36 | void attachPinChangeInterrupt3(void) { 37 | // fake function to make the IDE link this file 38 | } 39 | 40 | ISR(PCINT3_vect) { 41 | // get the new and old pin states for port 42 | uint8_t newPort = PCINT_INPUT_PORT3; 43 | 44 | // compare with the old value to detect a rising or falling 45 | uint8_t arrayPos = getArrayPosPCINT(3); 46 | uint8_t change = newPort ^ oldPorts[arrayPos]; 47 | uint8_t rising = change & newPort; 48 | uint8_t falling = change & oldPorts[arrayPos]; 49 | 50 | // check which pins are triggered, compared with the settings 51 | uint8_t risingTrigger = rising & risingPorts[arrayPos]; 52 | uint8_t fallingTrigger = falling & fallingPorts[arrayPos]; 53 | uint8_t trigger = risingTrigger | fallingTrigger; 54 | 55 | // save the new state for next comparison 56 | oldPorts[arrayPos] = newPort; 57 | 58 | // Execute all functions that should be triggered 59 | // This way we can exclude a single function 60 | // and the calling is also much faster 61 | // We may also reorder the pins for different priority 62 | #if !defined(PCINT_CALLBACK_PORT3) 63 | PCINT_CALLBACK(0, 24); 64 | PCINT_CALLBACK(1, 25); 65 | PCINT_CALLBACK(2, 26); 66 | PCINT_CALLBACK(3, 27); 67 | PCINT_CALLBACK(4, 28); 68 | PCINT_CALLBACK(5, 29); 69 | PCINT_CALLBACK(6, 30); 70 | PCINT_CALLBACK(7, 31); 71 | #else 72 | PCINT_CALLBACK_PORT3 73 | #endif 74 | } 75 | 76 | #if defined(PCINT_API) 77 | 78 | /* 79 | for (int i = 0; i < 32; i++) { 80 | Serial.print("#if (PCINT_USE_PCINT"); 81 | Serial.print(i); 82 | Serial.println(" == true)"); 83 | Serial.print("volatile callback callbackPCINT"); 84 | Serial.print(i); 85 | Serial.println(" = pcint_null_callback;"); 86 | Serial.print("void PinChangeInterruptEventPCINT"); 87 | Serial.print(i); 88 | Serial.println("(void){"); 89 | Serial.print(" callbackPCINT"); 90 | Serial.print(i); 91 | Serial.println("();"); 92 | Serial.println("}"); 93 | Serial.println("#endif"); 94 | } 95 | */ 96 | #if (PCINT_USE_PCINT24 == true) 97 | volatile callback callbackPCINT24 = pcint_null_callback; 98 | void PinChangeInterruptEventPCINT24(void) { 99 | callbackPCINT24(); 100 | } 101 | #endif 102 | #if (PCINT_USE_PCINT25 == true) 103 | volatile callback callbackPCINT25 = pcint_null_callback; 104 | void PinChangeInterruptEventPCINT25(void) { 105 | callbackPCINT25(); 106 | } 107 | #endif 108 | #if (PCINT_USE_PCINT26 == true) 109 | volatile callback callbackPCINT26 = pcint_null_callback; 110 | void PinChangeInterruptEventPCINT26(void) { 111 | callbackPCINT26(); 112 | } 113 | #endif 114 | #if (PCINT_USE_PCINT27 == true) 115 | volatile callback callbackPCINT27 = pcint_null_callback; 116 | void PinChangeInterruptEventPCINT27(void) { 117 | callbackPCINT27(); 118 | } 119 | #endif 120 | #if (PCINT_USE_PCINT28 == true) 121 | volatile callback callbackPCINT28 = pcint_null_callback; 122 | void PinChangeInterruptEventPCINT28(void) { 123 | callbackPCINT28(); 124 | } 125 | #endif 126 | #if (PCINT_USE_PCINT29 == true) 127 | volatile callback callbackPCINT29 = pcint_null_callback; 128 | void PinChangeInterruptEventPCINT29(void) { 129 | callbackPCINT29(); 130 | } 131 | #endif 132 | #if (PCINT_USE_PCINT30 == true) 133 | volatile callback callbackPCINT30 = pcint_null_callback; 134 | void PinChangeInterruptEventPCINT30(void) { 135 | callbackPCINT30(); 136 | } 137 | #endif 138 | #if (PCINT_USE_PCINT31 == true) 139 | volatile callback callbackPCINT31 = pcint_null_callback; 140 | void PinChangeInterruptEventPCINT31(void) { 141 | callbackPCINT31(); 142 | } 143 | #endif 144 | 145 | #endif // PCINT_API 146 | 147 | #endif // PCINT_USE_PORT3 148 | 149 | #endif // PCINT_INCLUDE_FROM_CPP 150 | -------------------------------------------------------------------------------- /src/PinChangeInterruptBoards.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2021 NicoHood 3 | See the readme for credit to other people. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | // include guard 25 | #pragma once 26 | 27 | //================================================================================ 28 | // Board Definitions 29 | //================================================================================ 30 | 31 | // Microcontroller specific definitions 32 | // Avr Variants are defined here: https://svn.savannah.gnu.org/viewvc/avr-libc/trunk/avr-libc/include/avr/io.h?view=markup 33 | 34 | #if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328A__) || defined(__AVR_ATmega328PA__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) \ 35 | || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega168PB__) \ 36 | || defined(__AVR_ATmega88__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88PB__) \ 37 | || defined(__AVR_ATmega48__) || defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega48PB__) 38 | // Arduino Uno 39 | #define PCINT_INPUT_PORT0 PINB 40 | #define PCINT_INPUT_PORT1 PINC 41 | #define PCINT_INPUT_PORT2 PIND 42 | 43 | #if defined(__AVR_ATmega328PB__) 44 | #define PCINT_INPUT_PORT3 PINE 45 | #endif 46 | 47 | #elif defined(__AVR_ATmega162__) 48 | 49 | #define PCINT_INPUT_PORT0 PINA 50 | #define PCINT_INPUT_PORT1 PINC 51 | 52 | #elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega640__) 53 | // Arduino Mega/Mega2560 54 | #define PCINT_INPUT_PORT0 PINB 55 | #define PCINT_INPUT_PORT2 PINK 56 | 57 | // special Port1 case, pins are on 2 HW Pin Ports (E,J) 58 | #if defined(PCINT_ENABLE_PCINT16) // PortE 59 | #if defined(PCINT_ENABLE_PCINT17) || defined(PCINT_ENABLE_PCINT18) \ 60 | || defined(PCINT_ENABLE_PCINT19) || defined(PCINT_ENABLE_PCINT20) \ 61 | || defined(PCINT_ENABLE_PCINT21) || defined(PCINT_ENABLE_PCINT22) \ 62 | || defined(PCINT_ENABLE_PCINT23) // PortJ 63 | // PortE and PortJ selected 64 | #define PCINT_INPUT_PORT1 ((PINE & 0x01) | (PINJ << 1)) 65 | #else 66 | // PortE only selected 67 | #define PCINT_INPUT_PORT1 PINE 68 | #endif 69 | #else 70 | // PortJ only selected 71 | // we still have to do the shift because the attach 72 | // function is not designed for this optimization 73 | #define PCINT_INPUT_PORT1 (PINJ << 1) 74 | #endif 75 | 76 | #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) 77 | // Arduino Leonardo/Micro 78 | #define PCINT_INPUT_PORT0 PINB 79 | 80 | #elif defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__) 81 | // u2 Series/HoodLoader2 82 | // u2 Series has crappy pin mappings for port 1 83 | #define PCINT_INPUT_PORT0 PINB 84 | #define PCINT_INPUT_PORT1 (((PINC >> 6) & (1 << 0)) | ((PINC >> 4) & (1 << 1)) | ((PINC >> 2) & (1 << 2)) | ((PINC << 1) & (1 << 3)) | ((PIND >> 1) & (1 << 4))) 85 | 86 | #elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 87 | // Attiny x5 88 | #define PCINT_INPUT_PORT0 PINB 89 | 90 | #elif defined(__AVR_ATtiny13__) 91 | // Attiny 13A 92 | #define PCINT_INPUT_PORT0 PINB 93 | // This is just a workaround for the missing definition in the following core: https://sourceforge.net/projects/ard-core13/ 94 | // It should work fine with: https://github.com/MCUdude/MicroCore 95 | #ifndef portInputRegister 96 | #define portInputRegister(P) ( (volatile uint8_t *)(PINB) ) 97 | #endif 98 | 99 | #elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) 100 | // Attiny x4 101 | #define PCINT_INPUT_PORT0 PINA 102 | #define PCINT_INPUT_PORT1 PINB 103 | 104 | #elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 105 | // 1284p and 644p, special 4 port case 106 | #define PCINT_INPUT_PORT0 PINA 107 | #define PCINT_INPUT_PORT1 PINB 108 | #define PCINT_INPUT_PORT2 PINC 109 | #define PCINT_INPUT_PORT3 PIND 110 | 111 | #elif defined(__AVR_ATtinyX41__) || defined(__AVR_ATtiny441__) || defined(__AVR_ATtiny841__) 112 | // Attiny x41 113 | #define PCINT_INPUT_PORT0 PINA 114 | #define PCINT_INPUT_PORT1 PINB 115 | 116 | // "iotn841.h" is missing those definitions, so we add them here 117 | #define PCINT0 0 118 | #define PCINT1 1 119 | #define PCINT2 2 120 | #define PCINT3 3 121 | #define PCINT4 4 122 | #define PCINT5 5 123 | #define PCINT6 6 124 | #define PCINT7 7 125 | 126 | #define PCINT8 0 127 | #define PCINT9 1 128 | #define PCINT10 2 129 | #define PCINT11 3 130 | 131 | #elif defined(__AVR_ATtiny2313__) 132 | #define PCINT_INPUT_PORT0 PINB 133 | 134 | #elif defined(__AVR_ATtiny2313A__) || defined(__AVR_ATtiny4313__) 135 | // All 8 pins 136 | #define PCINT_INPUT_PORT0 PINB 137 | // PinA has 3 PCINTs on the reset and clock lines, we do not use this port 138 | // PIND has 7 pins available, but the pin ordering is so messed up, 139 | // that it does not work with the current library structure. 140 | 141 | #elif defined(__AVR_ATtiny261__) || defined(__AVR_ATtiny461__) || defined(__AVR_ATtiny861__) 142 | // PORTB has Reset, clock and SPI while PORTA has I2C and Analog Pins. We just enable all pins. 143 | #define PCINT_INPUT_PORT0 PINA 144 | #define PCINT_INPUT_PORT1 PINB 145 | 146 | #else // Microcontroller not supported 147 | #error PinChangeInterrupt library does not support this MCU. 148 | #endif 149 | 150 | //================================================================================ 151 | // Add missing definitions 152 | //================================================================================ 153 | 154 | // add fakes if ports are not used 155 | #ifndef PCINT_INPUT_PORT0 156 | #define PCINT_INPUT_PORT0 0 157 | #else 158 | #define PCINT_INPUT_PORT0_USED 159 | #endif 160 | #ifndef PCINT_INPUT_PORT1 161 | #define PCINT_INPUT_PORT1 0 162 | #else 163 | #define PCINT_INPUT_PORT1_USED 164 | #endif 165 | #ifndef PCINT_INPUT_PORT2 166 | #define PCINT_INPUT_PORT2 0 167 | #else 168 | #define PCINT_INPUT_PORT2_USED 169 | #endif 170 | #ifndef PCINT_INPUT_PORT3 171 | #define PCINT_INPUT_PORT3 0 172 | #else 173 | #define PCINT_INPUT_PORT3_USED 174 | #endif 175 | -------------------------------------------------------------------------------- /src/PinChangeInterruptPins.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2021 NicoHood 3 | See the readme for credit to other people. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | // include guard 25 | #pragma once 26 | 27 | /* 28 | The strategy in this file: 29 | 30 | 0. Makefile optimization: 31 | To disable PCINT/PORTs via makefile use -DPCINT_DISABLE_PORT0 etc. 32 | This will undef a previously defined PCINT_ENABLE_PORT0. 33 | 34 | 1. Reduce the user settings to the enabled pins. 35 | If the whole port is deactivated, also disable all pins on this port. 36 | 37 | 2. Define the hardware available pins/ports. 38 | 39 | 3. Compare the hardware definition with the enabled pin definitions. 40 | If the pin is available and enabled, create a makro to use the pin. 41 | 42 | 4. Count all used pins (for each port). 43 | 44 | 5. If there are no pins used on a port, do not use the port 45 | 46 | 6. Finally we have a clear defintion of the used pins/ports like this: 47 | PCINT_USE_PCINT0 (true/false) 48 | PCINT_USE_PORT0 (true/false) 49 | 50 | Other definitions that can be used: 51 | PCINT_HAS_PORT0 (true/false) 52 | PCINT_HAS_PCINT0 (true/false) 53 | PCINT_NUM_PINS_PORT0 (0-8) 54 | PCINT_NUM_USED_PINS_PORT0 (0-8) 55 | EXTERNAL_NUM_PINCHANGEINTERRUPT (0-24) 56 | EXTERNAL_NUM_USED_PINCHANGEINTERRUPT (0-24) 57 | PCINT_NUM_PORTS (0-3) 58 | PCINT_NUM_USED_PORTS (0-3) 59 | */ 60 | 61 | //================================================================================ 62 | // Disabled Pins 63 | //================================================================================ 64 | /* 65 | for (int port = 0; port < 4; port++) { 66 | Serial.print("#if defined(PCINT_ENABLE_PORT"); 67 | Serial.print(port); 68 | Serial.print(") && defined(PCINT_DISABLE_PORT"); 69 | Serial.print(port); 70 | Serial.println(")"); 71 | Serial.print("#undef PCINT_ENABLE_PORT"); 72 | Serial.println(port); 73 | Serial.println("#endif"); 74 | Serial.println(); 75 | } 76 | 77 | for (int i = 0; i < 32; i++) { 78 | Serial.print("#if defined(PCINT_ENABLE_PCINT"); 79 | Serial.print(i); 80 | Serial.print(") && defined(PCINT_DISABLE_PCINT"); 81 | Serial.print(i); 82 | Serial.println(")"); 83 | Serial.print("#undef PCINT_ENABLE_PCINT"); 84 | Serial.println(i); 85 | Serial.println("#endif"); 86 | Serial.println(); 87 | } 88 | */ 89 | #if defined(PCINT_ENABLE_PORT0) && defined(PCINT_DISABLE_PORT0) 90 | #undef PCINT_ENABLE_PORT0 91 | #endif 92 | 93 | #if defined(PCINT_ENABLE_PORT1) && defined(PCINT_DISABLE_PORT1) 94 | #undef PCINT_ENABLE_PORT1 95 | #endif 96 | 97 | #if defined(PCINT_ENABLE_PORT2) && defined(PCINT_DISABLE_PORT2) 98 | #undef PCINT_ENABLE_PORT2 99 | #endif 100 | 101 | #if defined(PCINT_ENABLE_PORT3) && defined(PCINT_DISABLE_PORT3) 102 | #undef PCINT_ENABLE_PORT3 103 | #endif 104 | 105 | #if defined(PCINT_ENABLE_PCINT0) && defined(PCINT_DISABLE_PCINT0) 106 | #undef PCINT_ENABLE_PCINT0 107 | #endif 108 | 109 | #if defined(PCINT_ENABLE_PCINT1) && defined(PCINT_DISABLE_PCINT1) 110 | #undef PCINT_ENABLE_PCINT1 111 | #endif 112 | 113 | #if defined(PCINT_ENABLE_PCINT2) && defined(PCINT_DISABLE_PCINT2) 114 | #undef PCINT_ENABLE_PCINT2 115 | #endif 116 | 117 | #if defined(PCINT_ENABLE_PCINT3) && defined(PCINT_DISABLE_PCINT3) 118 | #undef PCINT_ENABLE_PCINT3 119 | #endif 120 | 121 | #if defined(PCINT_ENABLE_PCINT4) && defined(PCINT_DISABLE_PCINT4) 122 | #undef PCINT_ENABLE_PCINT4 123 | #endif 124 | 125 | #if defined(PCINT_ENABLE_PCINT5) && defined(PCINT_DISABLE_PCINT5) 126 | #undef PCINT_ENABLE_PCINT5 127 | #endif 128 | 129 | #if defined(PCINT_ENABLE_PCINT6) && defined(PCINT_DISABLE_PCINT6) 130 | #undef PCINT_ENABLE_PCINT6 131 | #endif 132 | 133 | #if defined(PCINT_ENABLE_PCINT7) && defined(PCINT_DISABLE_PCINT7) 134 | #undef PCINT_ENABLE_PCINT7 135 | #endif 136 | 137 | #if defined(PCINT_ENABLE_PCINT8) && defined(PCINT_DISABLE_PCINT8) 138 | #undef PCINT_ENABLE_PCINT8 139 | #endif 140 | 141 | #if defined(PCINT_ENABLE_PCINT9) && defined(PCINT_DISABLE_PCINT9) 142 | #undef PCINT_ENABLE_PCINT9 143 | #endif 144 | 145 | #if defined(PCINT_ENABLE_PCINT10) && defined(PCINT_DISABLE_PCINT10) 146 | #undef PCINT_ENABLE_PCINT10 147 | #endif 148 | 149 | #if defined(PCINT_ENABLE_PCINT11) && defined(PCINT_DISABLE_PCINT11) 150 | #undef PCINT_ENABLE_PCINT11 151 | #endif 152 | 153 | #if defined(PCINT_ENABLE_PCINT12) && defined(PCINT_DISABLE_PCINT12) 154 | #undef PCINT_ENABLE_PCINT12 155 | #endif 156 | 157 | #if defined(PCINT_ENABLE_PCINT13) && defined(PCINT_DISABLE_PCINT13) 158 | #undef PCINT_ENABLE_PCINT13 159 | #endif 160 | 161 | #if defined(PCINT_ENABLE_PCINT14) && defined(PCINT_DISABLE_PCINT14) 162 | #undef PCINT_ENABLE_PCINT14 163 | #endif 164 | 165 | #if defined(PCINT_ENABLE_PCINT15) && defined(PCINT_DISABLE_PCINT15) 166 | #undef PCINT_ENABLE_PCINT15 167 | #endif 168 | 169 | #if defined(PCINT_ENABLE_PCINT16) && defined(PCINT_DISABLE_PCINT16) 170 | #undef PCINT_ENABLE_PCINT16 171 | #endif 172 | 173 | #if defined(PCINT_ENABLE_PCINT17) && defined(PCINT_DISABLE_PCINT17) 174 | #undef PCINT_ENABLE_PCINT17 175 | #endif 176 | 177 | #if defined(PCINT_ENABLE_PCINT18) && defined(PCINT_DISABLE_PCINT18) 178 | #undef PCINT_ENABLE_PCINT18 179 | #endif 180 | 181 | #if defined(PCINT_ENABLE_PCINT19) && defined(PCINT_DISABLE_PCINT19) 182 | #undef PCINT_ENABLE_PCINT19 183 | #endif 184 | 185 | #if defined(PCINT_ENABLE_PCINT20) && defined(PCINT_DISABLE_PCINT20) 186 | #undef PCINT_ENABLE_PCINT20 187 | #endif 188 | 189 | #if defined(PCINT_ENABLE_PCINT21) && defined(PCINT_DISABLE_PCINT21) 190 | #undef PCINT_ENABLE_PCINT21 191 | #endif 192 | 193 | #if defined(PCINT_ENABLE_PCINT22) && defined(PCINT_DISABLE_PCINT22) 194 | #undef PCINT_ENABLE_PCINT22 195 | #endif 196 | 197 | #if defined(PCINT_ENABLE_PCINT23) && defined(PCINT_DISABLE_PCINT23) 198 | #undef PCINT_ENABLE_PCINT23 199 | #endif 200 | 201 | #if defined(PCINT_ENABLE_PCINT24) && defined(PCINT_DISABLE_PCINT24) 202 | #undef PCINT_ENABLE_PCINT24 203 | #endif 204 | 205 | #if defined(PCINT_ENABLE_PCINT25) && defined(PCINT_DISABLE_PCINT25) 206 | #undef PCINT_ENABLE_PCINT25 207 | #endif 208 | 209 | #if defined(PCINT_ENABLE_PCINT26) && defined(PCINT_DISABLE_PCINT26) 210 | #undef PCINT_ENABLE_PCINT26 211 | #endif 212 | 213 | #if defined(PCINT_ENABLE_PCINT27) && defined(PCINT_DISABLE_PCINT27) 214 | #undef PCINT_ENABLE_PCINT27 215 | #endif 216 | 217 | #if defined(PCINT_ENABLE_PCINT28) && defined(PCINT_DISABLE_PCINT28) 218 | #undef PCINT_ENABLE_PCINT28 219 | #endif 220 | 221 | #if defined(PCINT_ENABLE_PCINT29) && defined(PCINT_DISABLE_PCINT29) 222 | #undef PCINT_ENABLE_PCINT29 223 | #endif 224 | 225 | #if defined(PCINT_ENABLE_PCINT30) && defined(PCINT_DISABLE_PCINT30) 226 | #undef PCINT_ENABLE_PCINT30 227 | #endif 228 | 229 | #if defined(PCINT_ENABLE_PCINT31) && defined(PCINT_DISABLE_PCINT31) 230 | #undef PCINT_ENABLE_PCINT31 231 | #endif 232 | 233 | 234 | //================================================================================ 235 | // Enabled Pins 236 | //================================================================================ 237 | 238 | /* Disable all pins on a port, if port is deactivated 239 | We could then check every pin -> port definition 240 | But that'd be a mess and doesnt help 241 | Users who deactivate stuff should know 242 | what the are doing. 243 | So we use the enabled pins for all next definitions*/ 244 | /* 245 | for (int port = 0; port < 4; port++) { 246 | Serial.print("#if !defined(PCINT_ENABLE_PORT"); 247 | Serial.print(port); 248 | Serial.println(")"); 249 | for (int i = 0; i < 8; i++) { 250 | Serial.print("#if defined(PCINT_ENABLE_PCINT"); 251 | Serial.print(port * 8 + i); 252 | Serial.println(")"); 253 | Serial.print("#undef PCINT_ENABLE_PCINT"); 254 | Serial.println(port * 8 + i); 255 | Serial.println("#endif"); 256 | } 257 | Serial.println("#endif"); 258 | Serial.println(); 259 | } 260 | */ 261 | #if !defined(PCINT_ENABLE_PORT0) 262 | #if defined(PCINT_ENABLE_PCINT0) 263 | #undef PCINT_ENABLE_PCINT0 264 | #endif 265 | #if defined(PCINT_ENABLE_PCINT1) 266 | #undef PCINT_ENABLE_PCINT1 267 | #endif 268 | #if defined(PCINT_ENABLE_PCINT2) 269 | #undef PCINT_ENABLE_PCINT2 270 | #endif 271 | #if defined(PCINT_ENABLE_PCINT3) 272 | #undef PCINT_ENABLE_PCINT3 273 | #endif 274 | #if defined(PCINT_ENABLE_PCINT4) 275 | #undef PCINT_ENABLE_PCINT4 276 | #endif 277 | #if defined(PCINT_ENABLE_PCINT5) 278 | #undef PCINT_ENABLE_PCINT5 279 | #endif 280 | #if defined(PCINT_ENABLE_PCINT6) 281 | #undef PCINT_ENABLE_PCINT6 282 | #endif 283 | #if defined(PCINT_ENABLE_PCINT7) 284 | #undef PCINT_ENABLE_PCINT7 285 | #endif 286 | #endif 287 | 288 | #if !defined(PCINT_ENABLE_PORT1) 289 | #if defined(PCINT_ENABLE_PCINT8) 290 | #undef PCINT_ENABLE_PCINT8 291 | #endif 292 | #if defined(PCINT_ENABLE_PCINT9) 293 | #undef PCINT_ENABLE_PCINT9 294 | #endif 295 | #if defined(PCINT_ENABLE_PCINT10) 296 | #undef PCINT_ENABLE_PCINT10 297 | #endif 298 | #if defined(PCINT_ENABLE_PCINT11) 299 | #undef PCINT_ENABLE_PCINT11 300 | #endif 301 | #if defined(PCINT_ENABLE_PCINT12) 302 | #undef PCINT_ENABLE_PCINT12 303 | #endif 304 | #if defined(PCINT_ENABLE_PCINT13) 305 | #undef PCINT_ENABLE_PCINT13 306 | #endif 307 | #if defined(PCINT_ENABLE_PCINT14) 308 | #undef PCINT_ENABLE_PCINT14 309 | #endif 310 | #if defined(PCINT_ENABLE_PCINT15) 311 | #undef PCINT_ENABLE_PCINT15 312 | #endif 313 | #endif 314 | 315 | #if !defined(PCINT_ENABLE_PORT2) 316 | #if defined(PCINT_ENABLE_PCINT16) 317 | #undef PCINT_ENABLE_PCINT16 318 | #endif 319 | #if defined(PCINT_ENABLE_PCINT17) 320 | #undef PCINT_ENABLE_PCINT17 321 | #endif 322 | #if defined(PCINT_ENABLE_PCINT18) 323 | #undef PCINT_ENABLE_PCINT18 324 | #endif 325 | #if defined(PCINT_ENABLE_PCINT19) 326 | #undef PCINT_ENABLE_PCINT19 327 | #endif 328 | #if defined(PCINT_ENABLE_PCINT20) 329 | #undef PCINT_ENABLE_PCINT20 330 | #endif 331 | #if defined(PCINT_ENABLE_PCINT21) 332 | #undef PCINT_ENABLE_PCINT21 333 | #endif 334 | #if defined(PCINT_ENABLE_PCINT22) 335 | #undef PCINT_ENABLE_PCINT22 336 | #endif 337 | #if defined(PCINT_ENABLE_PCINT23) 338 | #undef PCINT_ENABLE_PCINT23 339 | #endif 340 | #endif 341 | 342 | #if !defined(PCINT_ENABLE_PORT3) 343 | #if defined(PCINT_ENABLE_PCINT24) 344 | #undef PCINT_ENABLE_PCINT24 345 | #endif 346 | #if defined(PCINT_ENABLE_PCINT25) 347 | #undef PCINT_ENABLE_PCINT25 348 | #endif 349 | #if defined(PCINT_ENABLE_PCINT26) 350 | #undef PCINT_ENABLE_PCINT26 351 | #endif 352 | #if defined(PCINT_ENABLE_PCINT27) 353 | #undef PCINT_ENABLE_PCINT27 354 | #endif 355 | #if defined(PCINT_ENABLE_PCINT28) 356 | #undef PCINT_ENABLE_PCINT28 357 | #endif 358 | #if defined(PCINT_ENABLE_PCINT29) 359 | #undef PCINT_ENABLE_PCINT29 360 | #endif 361 | #if defined(PCINT_ENABLE_PCINT30) 362 | #undef PCINT_ENABLE_PCINT30 363 | #endif 364 | #if defined(PCINT_ENABLE_PCINT31) 365 | #undef PCINT_ENABLE_PCINT31 366 | #endif 367 | #endif 368 | 369 | 370 | //================================================================================ 371 | // Hardware Definitions 372 | //================================================================================ 373 | 374 | #if defined(PCINT0_vect) 375 | #define PCINT_HAS_PORT0 true 376 | #else 377 | #define PCINT_HAS_PORT0 false 378 | #endif 379 | #if defined(PCINT1_vect) 380 | #define PCINT_HAS_PORT1 true 381 | #else 382 | #define PCINT_HAS_PORT1 false 383 | #endif 384 | #if defined(PCINT2_vect) 385 | #define PCINT_HAS_PORT2 true 386 | #else 387 | #define PCINT_HAS_PORT2 false 388 | #endif 389 | #if defined(PCINT3_vect) 390 | #define PCINT_HAS_PORT3 true 391 | #else 392 | #define PCINT_HAS_PORT3 false 393 | #endif 394 | 395 | // number of available ports 396 | #define PCINT_NUM_PORTS ( \ 397 | PCINT_HAS_PORT0 + \ 398 | PCINT_HAS_PORT1 + \ 399 | PCINT_HAS_PORT2 + \ 400 | PCINT_HAS_PORT3) 401 | 402 | /* 403 | for (int i = 0; i < 32; i++) { 404 | Serial.print("#ifdef PCINT"); 405 | Serial.println(i); 406 | Serial.print("#define PCINT_HAS_PCINT"); 407 | Serial.print(i); 408 | Serial.println(" true"); 409 | Serial.println("#else"); 410 | Serial.print("#define PCINT_HAS_PCINT"); 411 | Serial.print(i); 412 | Serial.println(" false"); 413 | Serial.println("#endif"); 414 | } 415 | */ 416 | #ifdef PCINT0 417 | #define PCINT_HAS_PCINT0 true 418 | #else 419 | #define PCINT_HAS_PCINT0 false 420 | #endif 421 | #ifdef PCINT1 422 | #define PCINT_HAS_PCINT1 true 423 | #else 424 | #define PCINT_HAS_PCINT1 false 425 | #endif 426 | #ifdef PCINT2 427 | #define PCINT_HAS_PCINT2 true 428 | #else 429 | #define PCINT_HAS_PCINT2 false 430 | #endif 431 | #ifdef PCINT3 432 | #define PCINT_HAS_PCINT3 true 433 | #else 434 | #define PCINT_HAS_PCINT3 false 435 | #endif 436 | #ifdef PCINT4 437 | #define PCINT_HAS_PCINT4 true 438 | #else 439 | #define PCINT_HAS_PCINT4 false 440 | #endif 441 | #ifdef PCINT5 442 | #define PCINT_HAS_PCINT5 true 443 | #else 444 | #define PCINT_HAS_PCINT5 false 445 | #endif 446 | #ifdef PCINT6 447 | #define PCINT_HAS_PCINT6 true 448 | #else 449 | #define PCINT_HAS_PCINT6 false 450 | #endif 451 | #ifdef PCINT7 452 | #define PCINT_HAS_PCINT7 true 453 | #else 454 | #define PCINT_HAS_PCINT7 false 455 | #endif 456 | #ifdef PCINT8 457 | #define PCINT_HAS_PCINT8 true 458 | #else 459 | #define PCINT_HAS_PCINT8 false 460 | #endif 461 | #ifdef PCINT9 462 | #define PCINT_HAS_PCINT9 true 463 | #else 464 | #define PCINT_HAS_PCINT9 false 465 | #endif 466 | #ifdef PCINT10 467 | #define PCINT_HAS_PCINT10 true 468 | #else 469 | #define PCINT_HAS_PCINT10 false 470 | #endif 471 | #ifdef PCINT11 472 | #define PCINT_HAS_PCINT11 true 473 | #else 474 | #define PCINT_HAS_PCINT11 false 475 | #endif 476 | #ifdef PCINT12 477 | #define PCINT_HAS_PCINT12 true 478 | #else 479 | #define PCINT_HAS_PCINT12 false 480 | #endif 481 | #ifdef PCINT13 482 | #define PCINT_HAS_PCINT13 true 483 | #else 484 | #define PCINT_HAS_PCINT13 false 485 | #endif 486 | #ifdef PCINT14 487 | #define PCINT_HAS_PCINT14 true 488 | #else 489 | #define PCINT_HAS_PCINT14 false 490 | #endif 491 | #ifdef PCINT15 492 | #define PCINT_HAS_PCINT15 true 493 | #else 494 | #define PCINT_HAS_PCINT15 false 495 | #endif 496 | #ifdef PCINT16 497 | #define PCINT_HAS_PCINT16 true 498 | #else 499 | #define PCINT_HAS_PCINT16 false 500 | #endif 501 | #ifdef PCINT17 502 | #define PCINT_HAS_PCINT17 true 503 | #else 504 | #define PCINT_HAS_PCINT17 false 505 | #endif 506 | #ifdef PCINT18 507 | #define PCINT_HAS_PCINT18 true 508 | #else 509 | #define PCINT_HAS_PCINT18 false 510 | #endif 511 | #ifdef PCINT19 512 | #define PCINT_HAS_PCINT19 true 513 | #else 514 | #define PCINT_HAS_PCINT19 false 515 | #endif 516 | #ifdef PCINT20 517 | #define PCINT_HAS_PCINT20 true 518 | #else 519 | #define PCINT_HAS_PCINT20 false 520 | #endif 521 | #ifdef PCINT21 522 | #define PCINT_HAS_PCINT21 true 523 | #else 524 | #define PCINT_HAS_PCINT21 false 525 | #endif 526 | #ifdef PCINT22 527 | #define PCINT_HAS_PCINT22 true 528 | #else 529 | #define PCINT_HAS_PCINT22 false 530 | #endif 531 | #ifdef PCINT23 532 | #define PCINT_HAS_PCINT23 true 533 | #else 534 | #define PCINT_HAS_PCINT23 false 535 | #endif 536 | #ifdef PCINT24 537 | #define PCINT_HAS_PCINT24 true 538 | #else 539 | #define PCINT_HAS_PCINT24 false 540 | #endif 541 | #ifdef PCINT25 542 | #define PCINT_HAS_PCINT25 true 543 | #else 544 | #define PCINT_HAS_PCINT25 false 545 | #endif 546 | #ifdef PCINT26 547 | #define PCINT_HAS_PCINT26 true 548 | #else 549 | #define PCINT_HAS_PCINT26 false 550 | #endif 551 | #ifdef PCINT27 552 | #define PCINT_HAS_PCINT27 true 553 | #else 554 | #define PCINT_HAS_PCINT27 false 555 | #endif 556 | #ifdef PCINT28 557 | #define PCINT_HAS_PCINT28 true 558 | #else 559 | #define PCINT_HAS_PCINT28 false 560 | #endif 561 | #ifdef PCINT29 562 | #define PCINT_HAS_PCINT29 true 563 | #else 564 | #define PCINT_HAS_PCINT29 false 565 | #endif 566 | #ifdef PCINT30 567 | #define PCINT_HAS_PCINT30 true 568 | #else 569 | #define PCINT_HAS_PCINT30 false 570 | #endif 571 | #ifdef PCINT31 572 | #define PCINT_HAS_PCINT31 true 573 | #else 574 | #define PCINT_HAS_PCINT31 false 575 | #endif 576 | 577 | 578 | // count numbers of available pins on each port 579 | /* 580 | for (int port = 0; port < 4; port++) { 581 | Serial.print("#define PCINT_NUM_PINS_PORT"); 582 | Serial.print(port); 583 | Serial.println(" ( \\"); 584 | for (int i = 0; i < 8; i++) { 585 | Serial.print("PCINT_HAS_PCINT"); 586 | Serial.print(port * 8 + i); 587 | if (i != 7) 588 | Serial.println(" + \\"); 589 | } 590 | Serial.println(")"); 591 | Serial.println(); 592 | } 593 | */ 594 | #define PCINT_NUM_PINS_PORT0 ( \ 595 | PCINT_HAS_PCINT0 + \ 596 | PCINT_HAS_PCINT1 + \ 597 | PCINT_HAS_PCINT2 + \ 598 | PCINT_HAS_PCINT3 + \ 599 | PCINT_HAS_PCINT4 + \ 600 | PCINT_HAS_PCINT5 + \ 601 | PCINT_HAS_PCINT6 + \ 602 | PCINT_HAS_PCINT7) 603 | 604 | #define PCINT_NUM_PINS_PORT1 ( \ 605 | PCINT_HAS_PCINT8 + \ 606 | PCINT_HAS_PCINT9 + \ 607 | PCINT_HAS_PCINT10 + \ 608 | PCINT_HAS_PCINT11 + \ 609 | PCINT_HAS_PCINT12 + \ 610 | PCINT_HAS_PCINT13 + \ 611 | PCINT_HAS_PCINT14 + \ 612 | PCINT_HAS_PCINT15) 613 | 614 | #define PCINT_NUM_PINS_PORT2 ( \ 615 | PCINT_HAS_PCINT16 + \ 616 | PCINT_HAS_PCINT17 + \ 617 | PCINT_HAS_PCINT18 + \ 618 | PCINT_HAS_PCINT19 + \ 619 | PCINT_HAS_PCINT20 + \ 620 | PCINT_HAS_PCINT21 + \ 621 | PCINT_HAS_PCINT22 + \ 622 | PCINT_HAS_PCINT23) 623 | 624 | #define PCINT_NUM_PINS_PORT3 ( \ 625 | PCINT_HAS_PCINT24 + \ 626 | PCINT_HAS_PCINT25 + \ 627 | PCINT_HAS_PCINT26 + \ 628 | PCINT_HAS_PCINT27 + \ 629 | PCINT_HAS_PCINT28 + \ 630 | PCINT_HAS_PCINT29 + \ 631 | PCINT_HAS_PCINT30 + \ 632 | PCINT_HAS_PCINT31) 633 | 634 | 635 | // number of available hardware pins 636 | #define EXTERNAL_NUM_PINCHANGEINTERRUPT ( \ 637 | PCINT_NUM_PINS_PORT0 + \ 638 | PCINT_NUM_PINS_PORT1 + \ 639 | PCINT_NUM_PINS_PORT2 + \ 640 | PCINT_NUM_PINS_PORT3) 641 | 642 | 643 | //================================================================================ 644 | // Used Pins 645 | //================================================================================ 646 | 647 | // check if pins are physically available and enabled 648 | /* 649 | for (int i = 0; i < 32; i++) { 650 | Serial.print("#if (PCINT_HAS_PCINT"); 651 | Serial.print(i); 652 | Serial.print(" == true) && defined(PCINT_ENABLE_PCINT"); 653 | Serial.print(i); 654 | Serial.println(")"); 655 | Serial.print("#define PCINT_USE_PCINT"); 656 | Serial.print(i); 657 | Serial.println(" true"); 658 | Serial.println("#else"); 659 | Serial.print("#define PCINT_USE_PCINT"); 660 | Serial.print(i); 661 | Serial.println(" false"); 662 | Serial.println("#endif"); 663 | } 664 | */ 665 | #if (PCINT_HAS_PCINT0 == true) && defined(PCINT_ENABLE_PCINT0) 666 | #define PCINT_USE_PCINT0 true 667 | #else 668 | #define PCINT_USE_PCINT0 false 669 | #endif 670 | #if (PCINT_HAS_PCINT1 == true) && defined(PCINT_ENABLE_PCINT1) 671 | #define PCINT_USE_PCINT1 true 672 | #else 673 | #define PCINT_USE_PCINT1 false 674 | #endif 675 | #if (PCINT_HAS_PCINT2 == true) && defined(PCINT_ENABLE_PCINT2) 676 | #define PCINT_USE_PCINT2 true 677 | #else 678 | #define PCINT_USE_PCINT2 false 679 | #endif 680 | #if (PCINT_HAS_PCINT3 == true) && defined(PCINT_ENABLE_PCINT3) 681 | #define PCINT_USE_PCINT3 true 682 | #else 683 | #define PCINT_USE_PCINT3 false 684 | #endif 685 | #if (PCINT_HAS_PCINT4 == true) && defined(PCINT_ENABLE_PCINT4) 686 | #define PCINT_USE_PCINT4 true 687 | #else 688 | #define PCINT_USE_PCINT4 false 689 | #endif 690 | #if (PCINT_HAS_PCINT5 == true) && defined(PCINT_ENABLE_PCINT5) 691 | #define PCINT_USE_PCINT5 true 692 | #else 693 | #define PCINT_USE_PCINT5 false 694 | #endif 695 | #if (PCINT_HAS_PCINT6 == true) && defined(PCINT_ENABLE_PCINT6) 696 | #define PCINT_USE_PCINT6 true 697 | #else 698 | #define PCINT_USE_PCINT6 false 699 | #endif 700 | #if (PCINT_HAS_PCINT7 == true) && defined(PCINT_ENABLE_PCINT7) 701 | #define PCINT_USE_PCINT7 true 702 | #else 703 | #define PCINT_USE_PCINT7 false 704 | #endif 705 | #if (PCINT_HAS_PCINT8 == true) && defined(PCINT_ENABLE_PCINT8) 706 | #define PCINT_USE_PCINT8 true 707 | #else 708 | #define PCINT_USE_PCINT8 false 709 | #endif 710 | #if (PCINT_HAS_PCINT9 == true) && defined(PCINT_ENABLE_PCINT9) 711 | #define PCINT_USE_PCINT9 true 712 | #else 713 | #define PCINT_USE_PCINT9 false 714 | #endif 715 | #if (PCINT_HAS_PCINT10 == true) && defined(PCINT_ENABLE_PCINT10) 716 | #define PCINT_USE_PCINT10 true 717 | #else 718 | #define PCINT_USE_PCINT10 false 719 | #endif 720 | #if (PCINT_HAS_PCINT11 == true) && defined(PCINT_ENABLE_PCINT11) 721 | #define PCINT_USE_PCINT11 true 722 | #else 723 | #define PCINT_USE_PCINT11 false 724 | #endif 725 | #if (PCINT_HAS_PCINT12 == true) && defined(PCINT_ENABLE_PCINT12) 726 | #define PCINT_USE_PCINT12 true 727 | #else 728 | #define PCINT_USE_PCINT12 false 729 | #endif 730 | #if (PCINT_HAS_PCINT13 == true) && defined(PCINT_ENABLE_PCINT13) 731 | #define PCINT_USE_PCINT13 true 732 | #else 733 | #define PCINT_USE_PCINT13 false 734 | #endif 735 | #if (PCINT_HAS_PCINT14 == true) && defined(PCINT_ENABLE_PCINT14) 736 | #define PCINT_USE_PCINT14 true 737 | #else 738 | #define PCINT_USE_PCINT14 false 739 | #endif 740 | #if (PCINT_HAS_PCINT15 == true) && defined(PCINT_ENABLE_PCINT15) 741 | #define PCINT_USE_PCINT15 true 742 | #else 743 | #define PCINT_USE_PCINT15 false 744 | #endif 745 | #if (PCINT_HAS_PCINT16 == true) && defined(PCINT_ENABLE_PCINT16) 746 | #define PCINT_USE_PCINT16 true 747 | #else 748 | #define PCINT_USE_PCINT16 false 749 | #endif 750 | #if (PCINT_HAS_PCINT17 == true) && defined(PCINT_ENABLE_PCINT17) 751 | #define PCINT_USE_PCINT17 true 752 | #else 753 | #define PCINT_USE_PCINT17 false 754 | #endif 755 | #if (PCINT_HAS_PCINT18 == true) && defined(PCINT_ENABLE_PCINT18) 756 | #define PCINT_USE_PCINT18 true 757 | #else 758 | #define PCINT_USE_PCINT18 false 759 | #endif 760 | #if (PCINT_HAS_PCINT19 == true) && defined(PCINT_ENABLE_PCINT19) 761 | #define PCINT_USE_PCINT19 true 762 | #else 763 | #define PCINT_USE_PCINT19 false 764 | #endif 765 | #if (PCINT_HAS_PCINT20 == true) && defined(PCINT_ENABLE_PCINT20) 766 | #define PCINT_USE_PCINT20 true 767 | #else 768 | #define PCINT_USE_PCINT20 false 769 | #endif 770 | #if (PCINT_HAS_PCINT21 == true) && defined(PCINT_ENABLE_PCINT21) 771 | #define PCINT_USE_PCINT21 true 772 | #else 773 | #define PCINT_USE_PCINT21 false 774 | #endif 775 | #if (PCINT_HAS_PCINT22 == true) && defined(PCINT_ENABLE_PCINT22) 776 | #define PCINT_USE_PCINT22 true 777 | #else 778 | #define PCINT_USE_PCINT22 false 779 | #endif 780 | #if (PCINT_HAS_PCINT23 == true) && defined(PCINT_ENABLE_PCINT23) 781 | #define PCINT_USE_PCINT23 true 782 | #else 783 | #define PCINT_USE_PCINT23 false 784 | #endif 785 | #if (PCINT_HAS_PCINT24 == true) && defined(PCINT_ENABLE_PCINT24) 786 | #define PCINT_USE_PCINT24 true 787 | #else 788 | #define PCINT_USE_PCINT24 false 789 | #endif 790 | #if (PCINT_HAS_PCINT25 == true) && defined(PCINT_ENABLE_PCINT25) 791 | #define PCINT_USE_PCINT25 true 792 | #else 793 | #define PCINT_USE_PCINT25 false 794 | #endif 795 | #if (PCINT_HAS_PCINT26 == true) && defined(PCINT_ENABLE_PCINT26) 796 | #define PCINT_USE_PCINT26 true 797 | #else 798 | #define PCINT_USE_PCINT26 false 799 | #endif 800 | #if (PCINT_HAS_PCINT27 == true) && defined(PCINT_ENABLE_PCINT27) 801 | #define PCINT_USE_PCINT27 true 802 | #else 803 | #define PCINT_USE_PCINT27 false 804 | #endif 805 | #if (PCINT_HAS_PCINT28 == true) && defined(PCINT_ENABLE_PCINT28) 806 | #define PCINT_USE_PCINT28 true 807 | #else 808 | #define PCINT_USE_PCINT28 false 809 | #endif 810 | #if (PCINT_HAS_PCINT29 == true) && defined(PCINT_ENABLE_PCINT29) 811 | #define PCINT_USE_PCINT29 true 812 | #else 813 | #define PCINT_USE_PCINT29 false 814 | #endif 815 | #if (PCINT_HAS_PCINT30 == true) && defined(PCINT_ENABLE_PCINT30) 816 | #define PCINT_USE_PCINT30 true 817 | #else 818 | #define PCINT_USE_PCINT30 false 819 | #endif 820 | #if (PCINT_HAS_PCINT31 == true) && defined(PCINT_ENABLE_PCINT31) 821 | #define PCINT_USE_PCINT31 true 822 | #else 823 | #define PCINT_USE_PCINT31 false 824 | #endif 825 | 826 | 827 | //================================================================================ 828 | // Number Used Pins 829 | //================================================================================ 830 | 831 | // count numbers of used pins on each port 832 | /* 833 | for (int port = 0; port < 4; port++) { 834 | Serial.print("#define PCINT_NUM_USED_PINS_PORT"); 835 | Serial.print(port); 836 | Serial.println(" ( \\"); 837 | for (int i = 0; i < 8; i++) { 838 | Serial.print("PCINT_USE_PCINT"); 839 | Serial.print(port * 8 + i); 840 | if (i != 7) 841 | Serial.println(" + \\"); 842 | } 843 | Serial.println(")"); 844 | Serial.println(); 845 | } 846 | */ 847 | #define PCINT_NUM_USED_PINS_PORT0 ( \ 848 | PCINT_USE_PCINT0 + \ 849 | PCINT_USE_PCINT1 + \ 850 | PCINT_USE_PCINT2 + \ 851 | PCINT_USE_PCINT3 + \ 852 | PCINT_USE_PCINT4 + \ 853 | PCINT_USE_PCINT5 + \ 854 | PCINT_USE_PCINT6 + \ 855 | PCINT_USE_PCINT7) 856 | 857 | #define PCINT_NUM_USED_PINS_PORT1 ( \ 858 | PCINT_USE_PCINT8 + \ 859 | PCINT_USE_PCINT9 + \ 860 | PCINT_USE_PCINT10 + \ 861 | PCINT_USE_PCINT11 + \ 862 | PCINT_USE_PCINT12 + \ 863 | PCINT_USE_PCINT13 + \ 864 | PCINT_USE_PCINT14 + \ 865 | PCINT_USE_PCINT15) 866 | 867 | #define PCINT_NUM_USED_PINS_PORT2 ( \ 868 | PCINT_USE_PCINT16 + \ 869 | PCINT_USE_PCINT17 + \ 870 | PCINT_USE_PCINT18 + \ 871 | PCINT_USE_PCINT19 + \ 872 | PCINT_USE_PCINT20 + \ 873 | PCINT_USE_PCINT21 + \ 874 | PCINT_USE_PCINT22 + \ 875 | PCINT_USE_PCINT23) 876 | 877 | #define PCINT_NUM_USED_PINS_PORT3 ( \ 878 | PCINT_USE_PCINT24 + \ 879 | PCINT_USE_PCINT25 + \ 880 | PCINT_USE_PCINT26 + \ 881 | PCINT_USE_PCINT27 + \ 882 | PCINT_USE_PCINT28 + \ 883 | PCINT_USE_PCINT29 + \ 884 | PCINT_USE_PCINT30 + \ 885 | PCINT_USE_PCINT31) 886 | 887 | 888 | // number of used hardware pins 889 | #define EXTERNAL_NUM_USED_PINCHANGEINTERRUPT ( \ 890 | PCINT_NUM_USED_PINS_PORT0 + \ 891 | PCINT_NUM_USED_PINS_PORT1 + \ 892 | PCINT_NUM_USED_PINS_PORT2 + \ 893 | PCINT_NUM_USED_PINS_PORT3) 894 | 895 | //================================================================================ 896 | // Used Ports 897 | //================================================================================ 898 | 899 | // check if ports are used 900 | #if PCINT_NUM_USED_PINS_PORT0 901 | #define PCINT_USE_PORT0 true 902 | #else 903 | #define PCINT_USE_PORT0 false 904 | #endif 905 | #if PCINT_NUM_USED_PINS_PORT1 906 | #define PCINT_USE_PORT1 true 907 | #else 908 | #define PCINT_USE_PORT1 false 909 | #endif 910 | #if PCINT_NUM_USED_PINS_PORT2 911 | #define PCINT_USE_PORT2 true 912 | #else 913 | #define PCINT_USE_PORT2 false 914 | #endif 915 | #if PCINT_NUM_USED_PINS_PORT3 916 | #define PCINT_USE_PORT3 true 917 | #else 918 | #define PCINT_USE_PORT3 false 919 | #endif 920 | 921 | // number of used ports 922 | #define PCINT_NUM_USED_PORTS ( \ 923 | PCINT_USE_PORT0 + \ 924 | PCINT_USE_PORT1 + \ 925 | PCINT_USE_PORT2 + \ 926 | PCINT_USE_PORT3) 927 | -------------------------------------------------------------------------------- /src/PinChangeInterruptSettings.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2021 NicoHood 3 | See the readme for credit to other people. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | // include guard 25 | #pragma once 26 | 27 | //================================================================================ 28 | // General Settings 29 | //================================================================================ 30 | 31 | /* Settings to de/activate ports/pins 32 | This will save you flash and ram because the arrays 33 | are managed dynamically with the definitions below. 34 | Make sure you still have all needed ports activated. 35 | Each deactivated port saves 3 bytes of ram. 36 | If you deactivate the whole port, 37 | you dont need to deactivate the pins. 38 | Same for the port if you deactivate all 8 pins. 39 | You dont have to deactivate pins/ports that dont exist. 40 | That is done by the macros. */ 41 | 42 | #ifndef PCINT_ENABLE_MANUAL 43 | 44 | #define PCINT_ENABLE_PORT0 45 | #define PCINT_ENABLE_PORT1 46 | #define PCINT_ENABLE_PORT2 47 | #define PCINT_ENABLE_PORT3 48 | 49 | #define PCINT_ENABLE_PCINT0 50 | #define PCINT_ENABLE_PCINT1 51 | #define PCINT_ENABLE_PCINT2 52 | #define PCINT_ENABLE_PCINT3 53 | #define PCINT_ENABLE_PCINT4 54 | #define PCINT_ENABLE_PCINT5 55 | #define PCINT_ENABLE_PCINT6 56 | #define PCINT_ENABLE_PCINT7 57 | #define PCINT_ENABLE_PCINT8 58 | #define PCINT_ENABLE_PCINT9 59 | #define PCINT_ENABLE_PCINT10 60 | #define PCINT_ENABLE_PCINT11 61 | #define PCINT_ENABLE_PCINT12 62 | #define PCINT_ENABLE_PCINT13 63 | #define PCINT_ENABLE_PCINT14 64 | #define PCINT_ENABLE_PCINT15 65 | #define PCINT_ENABLE_PCINT16 66 | #define PCINT_ENABLE_PCINT17 67 | #define PCINT_ENABLE_PCINT18 68 | #define PCINT_ENABLE_PCINT19 69 | #define PCINT_ENABLE_PCINT20 70 | #define PCINT_ENABLE_PCINT21 71 | #define PCINT_ENABLE_PCINT22 72 | #define PCINT_ENABLE_PCINT23 73 | #define PCINT_ENABLE_PCINT24 74 | #define PCINT_ENABLE_PCINT25 75 | #define PCINT_ENABLE_PCINT26 76 | #define PCINT_ENABLE_PCINT27 77 | #define PCINT_ENABLE_PCINT28 78 | #define PCINT_ENABLE_PCINT29 79 | #define PCINT_ENABLE_PCINT30 80 | #define PCINT_ENABLE_PCINT31 81 | 82 | #endif 83 | 84 | #ifdef ARDUINO 85 | // use API with function pointers (better optimized with .a linkage) 86 | #define PCINT_API 87 | 88 | // is the library compiled via .a file? 89 | // see readme for more information 90 | #define PCINT_ALINKAGE 91 | 92 | // force compile all enabled port ISRs (with .a linkage) 93 | //#define PCINT_COMPILE_ENABLED_ISR 94 | 95 | #endif 96 | 97 | //================================================================================ 98 | // Suggested Settings 99 | //================================================================================ 100 | 101 | // Arduino Uno (328) 102 | #if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega88__) 103 | /* Reordering interrupt callbacks priority 104 | Port0 has SPI on higher pins, ordering is fine 105 | Port1 has I2C on higher pins, ordering is fine 106 | Port2 has USART and Pin Interrupt on lower pins, 107 | move the priority down 108 | Its more likely the user will use pin 4-7 109 | */ 110 | #if !defined(PCINT_CALLBACK_PORT2) 111 | #define PCINT_CALLBACK_PORT2 \ 112 | PCINT_CALLBACK(4, 20); \ 113 | PCINT_CALLBACK(5, 21); \ 114 | PCINT_CALLBACK(6, 22); \ 115 | PCINT_CALLBACK(7, 23); \ 116 | PCINT_CALLBACK(0, 16); /* USART RX */ \ 117 | PCINT_CALLBACK(1, 17); /* USART TX */ \ 118 | PCINT_CALLBACK(2, 18); /* Pin Interrupt 0 */ \ 119 | PCINT_CALLBACK(3, 19); /* Pin Interrupt 1 */ 120 | #endif 121 | 122 | // deactivate crystal and reset pins by default 123 | #if defined(PCINT_ENABLE_PCINT6) 124 | #undef PCINT_ENABLE_PCINT6 // crystal 125 | #endif 126 | #if defined(PCINT_ENABLE_PCINT7) 127 | #undef PCINT_ENABLE_PCINT7 // crystal 128 | #endif 129 | #if defined(PCINT_ENABLE_PCINT14) 130 | #undef PCINT_ENABLE_PCINT14 // reset 131 | #endif 132 | #endif 133 | 134 | // Arduino Mega (2560) 135 | #if defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_AVR_MEGA) 136 | /* Port1 is structured a bit more complicated 137 | Also only 3 pins are connected on standard boards 138 | Seeeduino Mega has these pins optional! 139 | Disabling Port1 gives more speed and uses less flash 140 | Pins: 0(RX0), 14(TX3), 15(RX3) */ 141 | #if defined(PCINT_ENABLE_PORT1) 142 | #undef PCINT_ENABLE_PORT1 // better performence 143 | #endif 144 | 145 | /* Reordering interrupt callbacks priority 146 | Port2 has SPI on lower pins, move the priority down 147 | Its more likely the user will use pin 10-13 148 | Port1 by default deactivated, ordering is fine 149 | Port2 only has ADCs, ordering is fine 150 | */ 151 | #if !defined(PCINT_CALLBACK_PORT0) 152 | #define PCINT_CALLBACK_PORT0 \ 153 | PCINT_CALLBACK(4, 4); \ 154 | PCINT_CALLBACK(5, 5); \ 155 | PCINT_CALLBACK(6, 6); \ 156 | PCINT_CALLBACK(7, 7); \ 157 | PCINT_CALLBACK(0, 0); /* SPI SS */ \ 158 | PCINT_CALLBACK(1, 1); /* SPI SCK */ \ 159 | PCINT_CALLBACK(2, 2); /* SPI MISO */ \ 160 | PCINT_CALLBACK(3, 3); /* SPI MOSI */ 161 | #endif 162 | #endif 163 | 164 | // Arduino Leonardo/Micro (32u4) 165 | #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) 166 | /* Reordering interrupt callbacks priority 167 | Port0 has SPI on lower pins, move the priority down 168 | Its more likely the user will use pin 8-11 */ 169 | #if !defined(PCINT_CALLBACK_PORT0) 170 | #define PCINT_CALLBACK_PORT0 \ 171 | PCINT_CALLBACK(4, 4); \ 172 | PCINT_CALLBACK(5, 5); \ 173 | PCINT_CALLBACK(6, 6); \ 174 | PCINT_CALLBACK(7, 7); \ 175 | PCINT_CALLBACK(0, 0); /* SPI SS / RX LED */ \ 176 | PCINT_CALLBACK(1, 1); /* SPI SCK */ \ 177 | PCINT_CALLBACK(2, 2); /* SPI MISO */ \ 178 | PCINT_CALLBACK(3, 3); /* SPI MOSI */ 179 | #endif 180 | 181 | // RX LED on normal leonardo/micro 182 | #if defined(PCINT_ENABLE_PCINT0) && (defined(ARDUINO_AVR_LEONARDO) || defined(ARDUINO_AVR_MICRO)) 183 | #undef PCINT_ENABLE_PCINT0 184 | #endif 185 | #endif 186 | 187 | // Hoodloader2 (u2 Series) 188 | #if defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__) 189 | #if defined(ARDUINO_HOODLOADER2) 190 | // on HoodLoader2 Arduino boards only PB1-7 (port0) is broken out, save this flash 191 | #if defined(PCINT_ENABLE_PORT1) 192 | #undef PCINT_ENABLE_PORT1 193 | #endif 194 | 195 | // SS (PB0) is not connected on normal Arduino boards 196 | #if defined(PCINT_ENABLE_PCINT0) 197 | #undef PCINT_ENABLE_PCINT0 198 | #endif 199 | 200 | /* Reordering interrupt callbacks priority 201 | Port0 has SPI on lower pins, move the priority down 202 | Its more likely the user will use PB4-7 203 | Pretend the User has not soldered the 4 Pinheader 204 | so only do this for non Arduino boards. */ 205 | #else 206 | #if !defined(PCINT_CALLBACK_PORT0) 207 | #define PCINT_CALLBACK_PORT0 \ 208 | PCINT_CALLBACK(4, 4); \ 209 | PCINT_CALLBACK(5, 5); \ 210 | PCINT_CALLBACK(6, 6); \ 211 | PCINT_CALLBACK(7, 7); \ 212 | PCINT_CALLBACK(0, 0); /* SPI SS */ \ 213 | PCINT_CALLBACK(1, 1); /* SPI SCK */ \ 214 | PCINT_CALLBACK(2, 2); /* SPI MISO */ \ 215 | PCINT_CALLBACK(3, 3); /* SPI MOSI */ 216 | #endif 217 | #endif 218 | #endif 219 | 220 | /* Attiny 25/45/85 only has a very few pins 221 | activate all by default 222 | The order is also okay. */ 223 | 224 | #if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) 225 | // Port1 is connected to reset, crystal and Pin Interrupt 0 226 | // Deactivate it by default 227 | #if defined(PCINT_ENABLE_PORT1) 228 | #undef PCINT_ENABLE_PORT1 229 | #endif 230 | #endif 231 | --------------------------------------------------------------------------------