Trying to understand interrupt sketch

Hello,

I’m working with a small sketch I found in an old forum post that says it assigns interrupt 1 to pin 3, then it has a routine that runs when pin 3 goes hi (rising edge).

Here is the relevant code:

void setup() {
    Serial.begin(9600);
    pinMode(SCL, OUTPUT);
    pinMode(SDO, INPUT);
    // set up INT1 on digital pin 3
    EICRA = (1 << ISC11) | (1 << ISC10);  // external INT1 on rising edge
    EIMSK = (1 << INT1);  // External Interrupt Request 1 Enable
    sei();
}


ISR(INT1_vect) {
    touchVal = 0;
    delayMicroseconds(100);
    for (byte i=0; i<=15; i++) {
        SET(PORTD, SCL);
        delayMicroseconds(50);
        touchVal |= (digitalRead(SDO) << i);
        CLR(PORTD, SCL);
        delayMicroseconds(50);
    }
}

I’m not even worried about the ISR routine, what I am interested in is the setup routine, specifically, this code:

    // set up INT1 on digital pin 3
    EICRA = (1 << ISC11) | (1 << ISC10);  // external INT1 on rising edge
    EIMSK = (1 << INT1);  // External Interrupt Request 1 Enable
    sei();

I want to use this code with the IRRemote library, which happens to take pin3 for any IR output and I don’t want to mess with that library. What I would like to do is change the code I am posting here, and assign this interrupt to pin 4, but there is nothing in the code (besides the comments) that indicate any reference to pin 3.

Can someone point me to a GOOD write-up perhaps or a good tutorial that will help me make sense of what’s going on int this code? Cause it looks like hieroglyphics to me.

Thank you,

Mike

Assuming you're using an Uno, then best reference is the ATmega328P Datasheet.

You can't change the pins associated with external interrupts. INT0 is associated with Pin 2 and INT1 is associated with Pin 3. You can use "Pin Change Interrupts" on other pins. They are also described in the above-referenced datasheet.

Pins 2 and 3 on the Uno are the only external interrupt pins available. However, see if the function attachInterrupt() might work for you. You might also read some of the work by Nick Gammon found here. He's forgotten more about interrupts that I will ever know.

gfvalvo: Assuming you're using an Uno, then best reference is the ATmega328P Datasheet.

You can't change the pins associated with external interrupts. INT0 is associated with Pin 2 and INT1 is associated with Pin 3. You can use "Pin Change Interrupts" on other pins. They are also described in the above-referenced datasheet.

Thank you, but datasheets are typically not meant to be tutorials for helping people learn new things ... I'm looking for that golden nugget write up where someone who thoroughly understands the topic is able to explain it in easy to digest verbiage ... as opposed to something like a datasheet where the words tend to flow like a hail storm or a road littered with pot holes... words are hard to chew and they tend to upset the stomach ... :-)

EasyGoing1: I'm looking for that golden nugget write up where someone who thoroughly understands the topic is able to explain it in easy to digest verbiage ...

In the world of embedded microprocessors, you have to first understand the capabilities and limitations of the underlying hardware (i.e. the datasheet). Without that, you looking at the golden nugget will be like dogs watching TV.

      // set up INT1 on digital pin 3
    EICRA = (1 << ISC11) | (1 << ISC10);  // external INT1 on rising edge
    EIMSK = (1 << INT1);  // External Interrupt Request 1 Enable
    sei();

The reference manual is your friend because it describes the everything in terms of registers and the bits that make up the register. At the lowest level that how peripherals operate.

So the code is saying: set bits ISC11 and ISC10 of the EICRA register
next line: set bit INT1 in the EIMSK register.
next line: set the global interrupt flag

(has to be enabled to turn on maskable interrupts, there are some that you can not turn off called unmaskable)

Just read find in the manual where those resgisters are talked about and you will see what those bits are responsible for.

econjack:
Pins 2 and 3 on the Uno are the only external interrupt pins available.

Well this could be a kink in the armor …

econjack:
However, see if the function attachInterrupt() might work for you. You might also read some of the work by Nick Gammon found here. He’s forgotten more about interrupts that I will ever know.

Thank you, Brilliant … after reading some of Nicks write up … this is what I’ve figured out so far:

EICRA = (1 << ISC11) | (1 << ISC10); // external INT1 on rising edge

External Interrupt Control Register … directly configuring Register A in the CPU directly to handle Interrupt 1 … looks like he’s using lambda notation to set bits 2 and 3 of this control register to trigger on the rising edge of interrupt 1 … which he says plainly in his comment … the lambda notation isn’t clear yet though…

EIMSK = (1 << INT1); // External Interrupt Request 1 Enable

Enables the control register that was just configured … in the CPU directly.

sei();

sei() is a global command that enables all interrupt functionality… as opposed to cli(); which will globally disable interrupts.

This is good … not so hieroglyphic-ish anymore, thank you!

gfvalvo:
In the world of embedded microprocessors, you have to first understand the capabilities and limitations of the underlying hardware (i.e. the datasheet). Without that, you looking at the golden nugget will be like dogs watching TV.

Having cut my teeth on Commodore computers in the 1980’s … (and no, I didn’t use it for games) … and having taken micro controllers during my electronics courses back in the early 1990’s … I pretty much understand the mechanics involved when a CPU shifts bits around to produce meaningful results for a user … but KNOWING that I would need to set a register flag in the CPU to make sure it handles an interrupt on a rising edge … is one thing …

EICRA = (1 << ISC11) | (1 << ISC10);

… is something else entirely and is not intuitively obvious to me that this line was changing a register in the CPU…

Incidentally, what is another way to write 1 << ISC11 ? Whats the pre-lambda way of saying the same thing?

noweare: The reference manual is your friend because it describes the everything in terms of registers and the bits that make up the register. At the lowest level that how peripherals operate.

So the code is saying: set bits ISC11 and ISC10 of the EICRA register next line: set bit INT1 in the EIMSK register. next line: set the global interrupt flag

(has to be enabled to turn on maskable interrupts, there are some that you can not turn off called unmaskable)

Just read find in the manual where those resgisters are talked about and you will see what those bits are responsible for.

So lemmie ask you this ... why is that method preferred over something similar to this:

attachInterrupt (digitalPinToInterrupt (2), switchPressed, CHANGE);

Does the direct approach somehow make it handle interrupts in a different way, order, fewer clock cycles or....? Or is it just programmers choice for that evening? Some people think in binary while others think in more natural language ... kinda thing? ? ?

Incidentally, what is another way to write 1 << ISC11

As ISC11 just resolves itself to a number you could use the bitWrite function to simply set the bit in the register.
This would leave the other bits unchanged so is more like :-
EICRA |= (1 << ISC11)

EasyGoing1: So lemmie ask you this ... why is that method preferred over something similar to this:

attachInterrupt (digitalPinToInterrupt (2), switchPressed, CHANGE);

Does the direct approach somehow make it handle interrupts in a different way, order, fewer clock cycles or....? Or is it just programmers choice for that evening? Some people think in binary while others think in more natural language ... kinda thing? ? ?

I don't know if it's preferred or not but attachInterrupt ... is an arduino thing. It's an abstraction so you don't have to know about registers and bits in the register.

Direct register programming is probably faster since your not going through other lines of code to do the same thing.

If your program works with any way you decide to program then it's all good.

EasyGoing1: So lemmie ask you this ... why is that method preferred over something similar to this:

attachInterrupt (digitalPinToInterrupt (2), switchPressed, CHANGE);

Does the direct approach somehow make it handle interrupts in a different way, order, fewer clock cycles or....? Or is it just programmers choice for that evening? Some people think in binary while others think in more natural language ... kinda thing? ? ?

It's a compatibility thing. If you want to be able to use a different Arduino with the same code, like a library, then you should use the attachInterrupt function. That is already coded so that it can support the multiple boards.

But what if you don't have the Arduino libraries and you're using something else? In that case this code may be more portable to different environments, but for the same processor.

Grumpy_Mike:
This would leave the other bits unchanged so is more like :-
EICRA |= (1 << ISC11)

OK, the way I read that in my head … sounds like this: “EICRA OR Equal to 1 less less than ISC11” … still makes no sense to me …

EasyGoing1: OK, the way I read that in my head ... sounds like this: "EICRA OR Equal to 1 less less than ISC11" ... still makes no sense to me ...

No, not 1 less than. It's 1 bit-shifted.

https://www.arduino.cc/reference/en/language/structure/bitwise-operators/bitshiftleft/

https://www.arduino.cc/reference/en/language/structure/bitwise-operators/bitshiftright/

noweare: I don't know if it's preferred or not but attachInterrupt ... is an arduino thing. It's an abstraction so you don't have to know about registers and bits in the register.

Direct register programming is probably faster since your not going through other lines of code to do the same thing.

If your program works with any way you decide to program then it's all good.

I think you nailed it when you said "is an arduino thing" ... writing directly to registers, I ASSUME would work no matter which compiler you tossed it into?

Delta_G:
No, not 1 less than. It’s 1 bit-shifted.

<< - Arduino Reference

>> - Arduino Reference

OK … it’s bit shifting … but it still isn’t clear to me what this statement

EICRA |= (1 << ISC11)

is doing … what is the |= all about? are we just shifting a 1 into the register ISC11 times?

This is where I found the bitshift pages. The |= is there too. If you haven't before, you should spend a few hours looking around here.

Go to the top of this page if you're in a web browser nad click Resources - reference.

Here's a link if that's easier.

https://www.arduino.cc/reference/en

Basically an OR sets a bit if it is set in the mask and an AND clears a bit if it is cleared in the mask and we use that a lot when twiddling bits in registers.

EICRA |= (1 << ISC11)

is doing … what is the |= all about? are we just shifting a 1 into the register ISC11 times?

It is making the ISC11 th bit a one and leaving all other bits in that register unchanged.

Where as
EICRA = (1 << ISC11)

It is making the ISC11 th bit a one and making all other bits a zero. As I said ISC11 is simply the number of a bit that performs a specific function, its value will always be something between zero and seven.

So suppose that ISC11 is the number 4 then (1 << ISC11) will generate a binary number with bit 4 set and all the other bits zero, in binary that would be 0001 0000

PS without looking it up I don’t actually know what number ISC11 corresponds to.

Grumpy_Mike:
It is making the ISC11 th bit a one and leaving all other bits in that register unchanged.

Where as
EICRA = (1 << ISC11)

It is making the ISC11 th bit a one and making all other bits a zero. As I said ISC11 is simply the number of a bit that performs a specific function, its value will always be something between zero and seven.

So suppose that ISC11 is the number 4 then (1 << ISC11) will generate a binary number with bit 4 set and all the other bits zero, in binary that would be 0001 0000

PS without looking it up I don’t actually know what number ISC11 corresponds to.

Ok so wait … it’s making the ISC11th BIT a 1 and the rest zero … yet ISC11 is a bit label that has a function whos value will always be something between 0 and 7 … how can a BIT have a value higher than 1 ?

ISC11 corresponds (I believe) to interrupt 1 … or pin 2 or 3 … or something … ah … found it …

And concerning the link you gave me for the Arduino command reference … I’ve been tapping that link for a few years now … but all this low level stuff is only something that I have recently found myself having to dabble in … I’ve never had a need to shift bits of any kind in any context … so this is all new my world … I understand what bit shifting IS … conceptually … and now Im just beginning to understand the programming language that can actually do it (and not just shifting bits, but manipulating registers and settings to achieve something useful) … I think what I need to as a next step is actually put it to practice and write some code that uses this stuff to do something useful … I seem to grasp things better when I engage it in a useful way … nothing solidifies learning better than applying the knowledge …

The hardest part of learning new and more complicated topics… is realizing when you don’t know what you don’t know so you have no way of asking the right questions nor even knowing what to search for … thats why I toss stuff like this out into the forums from time to time … hoping someone will be able to realize where I’m at and where I need to be and then point me in the right direction for getting there … hopefully on a path proven to have a shallower learning curve.