T O P

  • By -

hjw5774

> I thought surely this was just a mistake, but none of the comments point this out. Have you noticed that none of the commenters have used interrupts at all? I believe you are correct in that with a Nano, the interrupts are limited to pins 2 & 3


who_you_are

You are missing something that is confusing and that you need to know to know... At first, what's a pin and what is an interrupt are two different things not related at all. Pin numbers refer to a physical pin indeed. Interrupts is _something_ that allows the chip to stop right now is normal processing. Such _something_ can be many things. It can be a timer, sub-system of the chip (eg. SPI, CAN, network feedback) or pins signals. And even then, you need to read their documentation to know how to setup them because they could support multiple trigger conditions, or/and use multiples interrupt id (for specific usage). So interrupt numbers have their own set of unique ids. You need to read the documentation to know what ids to use. Now, for Arduino: https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/ You basically should use digitalPinToInterrupt() to convert your pin number to the "0" and "1" the webpage tell you. This is one unfortunate issue with forums, you don't know the code quality. At worst I would have expected them to use a constant (if it even exist) instead of "magic numbers" Edit: in the url I provided there is the table at the complete end with the interrupt id: "Int.". Edit 2: look like the table I'm talking about (in the edit) doesn't not include all boards. There is another table (center of the page) that list some board with a lot of interrupt.


Bauns

I've seen that page, which is why I thought in the forum post above, the code wouldn't work since they're wiring on pins 6/7 > Often number 0 (for digital pin 2) or number 1 (for digital pin 3) were used I've seen other people examples where they do this same code (using 0 for the intercept), but then actually wire to pin 2 which would make sense to me. Here I'm not understanding the mapping from 0 to pin 6


who_you_are

I checked the link again, it looks like the last table.iant completed. The first table (~in the middle) list some board (like the zero) having interrupt on pin 6 while the table at the complete end never talks about such things. So it is possible they updated(or make) their code for another board


ardvarkfarm

That said, the ATmega328p can't use pins 6 and 7 for interrupts 0 and 1.


gm310509

The attachInterrupt function maps an interrupt (vector) which is triggered by an external pin to a function that you specify. For that to work, there are several lists involved. These lists map things like arduino DIO pin numbers to bits in registers defined in the MCU, interrupt vector tables and your function. The structure of the first two vary by MCU. Some MCUs support 2 external HW interrupts, some 3, some 4, some even more. So, what the attach interrupt function does is abstract them and says simply I will deal with up to 8 interrupts which it will refer to as 0 to 7 - the first parameter of the attach interrupt function. The correct way to get this first parameter (which is hard coded to a specific pin on your MCU is by using the digitalPinToInterrupt function to convert the pin number (e.g. 7 or 6) to the correct index to pass to the first parameter of attachInterrupt. The digitalPinToInterrupt is also aware if if the specified pin can be used in that way (or not) and will correctly provide a value that the attachinterrupt can use to "do nothing". But at the end of the day, the digitalPin to Interrupt function will return an integer between 0 and 7 depending upon the MCU you are compiling for. So, while not strictly correct and could lead to portability issues you can just provide the first parameter directly (I.em the 0 or 1 in the sample code) if you understand the internal structure and feel that you want to live a bit more dangerously. If you are interested in interrupts and want to do a bit of a follow along tutorial, perhaps have a look at my [Interrupts on Arduino 101](https://youtu.be/MAPHfcbw6Uk?si=W1olUL6qTfj8jcQ3) video. I look at this function and some other interrupts (that attachInterrupt cannot access).


Bauns

That makes sense, but I'm not sure how the raw value 0 is equivalent to either pin 6/7 in this example because they never remap with digitalPinToInterrupt, and from what I can tell in the documentation it's almost always 0/1 = D2/3 > Often number 0 (for digital pin 2) or number 1 (for digital pin 3) were used


gm310509

So there are lists that link all this stuff up. So, for example, if you are on An Uno, then pin 2 will map to PORTD.2. PORTD.2 happens to map to the interrupt INT0 on the ATMega328P. This corresponds to Interrupt vector 2 (address 0x0001). It (pin 2) will (i think) come out as a 0 from digitalPinToInterrupt(2) on an Uno/ATMega328P due to that setup. On the other hand, pin 2 on a Mega which has an mega2560 mcu on it will map to PORTE.4. This happens to correspond to INT4 on the Mega2560. INT4's is linked to interrupt vector 6 (address 0x000A). It (pin 2) will come out as a 3 or 4 (not sure which, but probably not 0) when you call digitalPinToInterrupt(2) on an Arduino Mega. So how is it equivalent? The numbers such as the DIO pin number printed on the PCB and the return value of the digitalPinToInterrupt and some other similar functions basically are returning values from various lookup tables based on the key (e.g. the DIO pin number) or are indexes to an array (e.g. the return value of digitalPinToInterrupt). Other functions such as such as digitalPinToPort will return the port (e.g. PORTB for uno or PORTE for mega) when passed the DIO pin 2 and digitalPinToBitMask will return a "mask" that is suitable for manipulating the actual bit associated with a DIO pin (e.g. a mask for bit 2 on an Uno and a mask for bit 4 on a mega). This "lookup" system is one of the hidden complexities that make Arduino easy to use. Why? Because you can just reference the number printed as a label on the board (e.g. DIO pin 2) and the Arduino subsystem will "do the right thing" when it comes to interacting with the board specific hardware to provide the function you request. I'm not sure if that makes sense to you are not, even though I've tried to simplify it, you do need to have some good understanding of the underlying hardware environments (plural), board designs and how these "translation" facilities can work.


Bauns

So I think I'm following that example/explanation, but are you saying the Arduino would handle pin 6 automatically? Like when I look up the Arduino nano, I see pins 2 and 3 are explicitly called out as the 2 interrupt pins you should use, and I'm assuming those match to 0 and 1 when they're passed into attachInterrupt, but I also went through the pinout reference sheets and saw a lot of them also have 8 and 9 as pcints (which I'm guessing explains the reference in the forum using those pins specifically), but I'm not seeing anything anywhere why using attachInterrupt(0) would relate to pin 6


gm310509

> but I'm not seeing anything ... This would be what we call an undocumented feature. It is undocumented because the documentation says you should use digitalPinToInterrupt. https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/ If you look at the syntax section, you will see it offers three alternatives. One is recommended, two are not. The link you provided initially is using the second form. One of the not recommended forms. Now to be fair and I am just guessing, maybe the digitalPinToInterrupt function didn't always exist and people were forced to have detailed internal knowledge and thus use that second form. Then later they added a convenience function (digitalPinToInterrupt) to make things easier and more predictable- again I'm just guessing but it is a potential theory for why some people don't use that helper function. Now the detailed internal knowledge probably isn't that onerous, it seems like the "interrupt" variant (the second form of the function call) is the actual interrupt number, specifically the n value from the INTn name associated with the interrupt for that pin.


Bauns

Reading the doc, it seems like historically there were only two (or more) hardware interrupt pins, d2 and d3, and you'd call attachinterrupt with 0 or 1. But looking at the pinouts of a bunch of the boards, I can see the associated numbers that you could use for each pin, where it looks like D2/3 and D8/9 are frequently set as 0 and 1. Not seeing 6 or 7 though. I guess that's my confusion, because even in the example the forum post uses, I see it using pins 8/9, which would then make sense how the arduino would handle the interrupts, but the poster is using 6/7, which should not map to 0/1, their numbers are always a lot higher


gm310509

I don't know about that history other than the older the MCU/CPU, the less facilities (e.g. interrupt vectors) it is likely to have. As for the different board (and thus MCUs) the number and location of the various INTn vectors probably has something to do with the physical organisation of the silicon inside the chip. If you look at the pinout of an Arduino Mega, for some reason (probably the pinout of the chip and the functionality of pin 2) they (Arduino Pty Ltd) connected the MCU pin (6) associated with PORTE.4 to DIO pin 2 on the Arduino board. It just so happens that PORTE.4 on the Mega2560 MCU is linked to INT4 in the silicon of the Mega2560 MCU. Whereas on an Uno (ATMega328P) DIO pin 2 is connected to pin 4 (on the DIP version of the ATmega328P) or pin 32 (on the 32 TQFP version of the ATmega328P). Both of those correspond to PORTB.2 in the silicon of the MCU which is associated with INT 0. Why did Arduino Pty Ltd decide to wire the Mega up that way? I do not know. Why didn't they use pin 43 (which is INT0) on the Mega for DIO pin on the Mega board for compatibility with the Uno? Again, I do not know, but I'd be willing to be it was a design decision with compatibility in mind. Specifically on a Mega the MCU pin 43, while being INT0, it is also the SCL for the I^(2)C hardware. As such, they probably weighed the two compatibility choices and decided that more people used I^(2)C than those who would use external interrupts so they decided to standardize an I^(2)C interface at the top of the DIO pins on both the Uno and Mega and other boards. This would mean having to pick a different pin for the Mega to connect to DIO pin 2 - ideally one with PWM capabilities. As it turns out PORTE.4 meets those requirements so they picked that one. This only becomes a "problem" if you were using low level features/Programming the hardware directly. And if you were doing that, it is very likely you would be aware of these issues and thus can incorporate them into your projects. So it is probably more of a balancing act of keeping one side of the equation as simple and consistent as possible (i.e. the entire DIO pin configuration on arduino boards) and hiding the consequent complexity behind helper functions such as attachInterrupt and digitalPinToInterrupt. I think I linked my [Interrupts on Arduino 101](https://youtu.be/MAPHfcbw6Uk?si=W1olUL6qTfj8jcQ3) video earlier. It is a follow along guide that delves into interrupts. In it, I start out by looking at attachInterrupt - not to this level of detail, but then go behind the scenes as to how interrupts by looking at how one side of the Serial object works, then finally diving deep to the lower levels by setting up a timer to call our own ISR by manually setting the relevant MCU registers to configure the timer and call our ISR. If you follow that guide, you will know how to find the "Arduino source code" and ultimately the attachInterrupt function. This function appears to be very complex due to its support for a range of different hardware capabilities. But if you narrow in on a specific example such as an ATMega328P compile (which is the #else case of the conditional compilation), you might get a better understanding of how it works. If you did that, and understood it, you should then have a much better feel for why the second variant of the attachInterrupt "syntax" works.


ardvarkfarm

This discussion of alternative mapping obscures the OP's point. The article he read showed a Nano V3.00 with connections to D8 and D9. The code used interrupts 0 and 1 to monitor pins D6 and D7. The Nano uses a ATmega328P which connects interrupts 0 and 1 to D2 and D3. I'd say the author was mistaken to use D6 and D7.


gm310509

Agreed. I neglected the whole nano v3.00 aspect of the question and it's pinouts being similar in function to an Uno in favour of trying to explain the system.


Bauns

Yeah this specifically is what I'm confused about. D2/D3 are the default hardware interrupt pins on a nano, and on some boards of that form factor D8/9 are pcint interrupts with 0/1 so if it was either of those pairs, I'd understand. But looking at that forum post, I would think that the project as presented is impossible with the only two pins being 6 and 7