├── .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 | 
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 |
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 |
--------------------------------------------------------------------------------