Go Down

Topic: Trying to understand interrupt sketch (Read 283 times) previous topic - next topic

EasyGoing1

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:

Code: [Select]
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:
Code: [Select]
    // 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

gfvalvo

#1
Aug 23, 2019, 02:25 am Last Edit: Aug 23, 2019, 02:26 am by 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.
No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

econjack

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.

EasyGoing1

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 ... :-)

gfvalvo

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.
No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

noweare

Code: [Select]
      // 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.

EasyGoing1

Pins 2 and 3 on the Uno are the only external interrupt pins available.
Well this could be a kink in the armor ...  
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!

EasyGoing1

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?

EasyGoing1

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? ? ?

Grumpy_Mike

Quote
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)

noweare

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.

Delta_G

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. 

|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

EasyGoing1

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

Delta_G

#13
Aug 23, 2019, 06:58 am Last Edit: Aug 23, 2019, 06:58 am by Delta_G
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/
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

EasyGoing1

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?

Go Up