Go Down

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

EasyGoing1

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

Delta_G

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
|| | ||| | || | ||  ~Woodstock

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

Delta_G

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

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

Grumpy_Mike

#18
Aug 23, 2019, 10:33 am Last Edit: Aug 23, 2019, 10:39 am by Grumpy_Mike
Quote
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.

EasyGoing1

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.

GolamMostafa

#20
Aug 23, 2019, 12:13 pm Last Edit: Aug 24, 2019, 08:20 am by GolamMostafa
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 ... :-)
1.  The following diagram of Fig-1 hints that the physical Pin-4/PD2/DPin-2 of ATmega328P MCU can be configured to work as an 'interrupt line 0 (INT0 for interrupt type 0)' to receive interrupt signal from external hardware device K1. The diagram also hints that the physical Pin-5/PD3/DPin-3 can be configured to work as an 'interrupt line 1 (INT1 for interrupt type 1)' to receive interrupt signal from external hardware device K2. The diagram does not tell the procedures of how DPin-2 (DPin-3) can be attached with INT0 (INT1).

Figure-1: INT0 and INT1 interrupt structures of ATmega328P MCU

2.  The procedures are (according to data sheets and practical results) listed below only for INT1 interrupt, and they will also be applicable for INT0 interrupt with corresponding change in the 'signal signatures'.

(1)  DPin-3 will turn into an 'INT1 interrupt' line when the user puts HIGH at INT1-bit of EIMSK Register (Fig-2) and HIGH at I-bit of SREG Register (Fig-3). As a result, the occurrence of a triggering signal (LOW, Rising Edge, or Falling Edge) at DPin-3 will force the MCU (MCU will be interrupted) to suspend the current program that it has been executing and then jump to ISRINT1 (interrupt sub routine due to INT1 interrupt).


Figure-2: Bit layout of EIMSK Register


Figure-3: Bit layout of SREG Register

(a)  Possible codes to store HIGH at INT1 bit of EIMSK Register
Code: [Select]
bitSet(EIMSK, 1);        //setBit(variable, bitPosition)
bitWrite(EIMSK, 1, HIGH);    //bitWrite(variable, bitPosition, bitValue)
EIMSK |= (1<<INT1);  //<< is not bit shift operation; bureaucratic style to store HIGH only at INT1 bit.
                         //| (pipe character) indicates OR operation and = indicates assignment


(b)  Possible codes to store HIGH at I bit of SREG Register
Code: [Select]
bitSet(SREG, 7);
bitWrite(SREG, 7, HIGH);
sei();                      //set HIGH at global interrupt flag (I bit); opposite is: cli()
interrupts();             //Arduino Code; opposite is noInterrupts()
SREG |= (1<<I);               //not tested


(2)  Setting the trigger level of the interrupting signal (the signal that will generate interrupt).
The Op has desired 'Rising Edge (RE)' as the trigger level of the interrupting signal. In Fig-1 when K2 is closed, a rising edge signal will appear at DPin-3. The RE trigger level is initialized by storing HIGH at both ISC11 (Interrupt Sense Control Bit 1 for INT1) and ISC10 bits of the EICRA Register (Fig-4).



Figure-4: Bit layout of EICRA Register

Possible codes to store HIGH at both ISC11 and ISC10 bits.
(a)  
Code: [Select]
byte x = EICRA;
x = x | 0b00001100;
ECIRA = x;

(b)  
Code: [Select]
bbitSet(EICRA, 3);  //HIGH ---> ISC11
bitSet(EICRA, 2);   //HIGH ---> ISC10

(c)  
Code: [Select]
EICRA |= (1<<ISC11)|(1<<ISC10);    //untested

3.  Final codes to initialize INT1 interrupt where DPin-3 is attached with INT1.
Code: [Select]
bitSet(EICRA, 3);   //HIGH ---> ISC11 bit
bitSet(EICRA, 2);          //HIGH ---> ISC10 bit

bitSet(EIMSK, 1);         //HIGH ---> INT1 bit
bitSet(SREG, 7);          //HIGH ---> I bit


After interruption, the MCU will vector at location 0x0004 which is redirected at the ISRINT1 routine by the following declaration:
Code: [Select]
ISR(INT1_vect)
{
   //insert codes as needed
}


All the above register level codes and ISR could be summarized by the declaration of the following Arduino codes:
Code: [Select]
attachInterrupt(digitalPinToInterrupt(3), ISRINT1, RISING);//DPin-3 for INT1, userISRName, triggerLevel

void ISRINT1()
{
   //insert codes as needed
}


4.  The final hardware structure of INT1 interrupt logic

Figure-5: Hrardware structure of INT1 interrupt logic

OPeration:  When rising edge occurs at DPin-3, the INTF1 flag assumes HIGH regardless of the open/close conditions of SWB and SWC (the interrupt enable/disable software switches). Once SWB and SWC are at closed conditions (usually done in the initialization process), the INTF1 flag will generate an interrupt request to the MCU. As a result, the MCU will first vector at location 0x0004 and then will jump to the ISR (interrupt sub routine) during which the INTF1 flag will be automatically cleared. This process is known as 'vectored interrupt'.

The status of INTF1 flag is also recorded at EIFR register so that the user can still detect the presence of a triggering signal at DPin-3 by polling the INTF1 flag in situation where interrupt structure remains disabled (SWB or SWC or both remain opened). This process is known as 'polled interrupt'; where, the INTF1 flag has to be cleared by the user by putting HIGH at the INTF1 bit of the EIFR register.

gfvalvo

#21
Aug 23, 2019, 01:14 pm Last Edit: Aug 23, 2019, 01:55 pm by gfvalvo
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?
Yea, it does take some digging. But, the beauty of the Open Source paradigm is that all the source code is available to you for inspection. If you work your way through the macro definitions, you'll eventually find that 'EICRA' is defined as:
Code: [Select]
(*(volatile uint8_t *)(0x69))
Then, looking up the address 0x69 in reference manual, you'll see:

So, that statement does indeed modify the contents of a register within the processor.

Also, as previously noted, the '<<' notation denotes a bit shift (to the left in this case). It's one of the most fundamental operations in the 'C' language and has absolutely nothing to do with Lambda Expressions.

No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

Grumpy_Mike

#22
Aug 23, 2019, 02:49 pm Last Edit: Aug 23, 2019, 02:50 pm by Grumpy_Mike
Quote
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 ?
It can't, but if you shift a 1 by three places to the left (1<<3) you end up with 1 in bit 3 with all the other bits zero.
This is exactly the same as writing b00001000 or 0x08 but those numbers are a little difficult to follow so the ISC11 variable is set to have a value of 3.

So all bit names are simply a variable set to the value of the bit number they refer to.

Therefore if you used (1<<ISC01) | (1<<ISC11) then you would get a number with a one in bit 3 and a one in bit 1 a value of b00001010 or 0x0A because the value of the variable ISC01 is one and the value of ISC11 is three.

Now as a quiz, what is the value of the variable ISC00 ?

noweare

The bit shifting is plain  C language you can experiment with bit shifting & (and) | (or) on your home PC and a C compiler you don't need an arduino.

Grumpy_Mike

The bit shifting is plain  C language you can experiment with bit shifting & (and) | (or) on your home PC and a C compiler you don't need an arduino.
And it is not just restricted to C, most languages, including Python, have these  operations.

In practice I most often use bit shifting for joining two bytes together to make an int.

The AND operation is very useful for restricting a counting variable to a power of two. For example suppose you want to count over the range 0 to 7, that is eight values, then
Code: [Select]
count++;
count = count & 0x7;

Will do it.
Or if you want to decide if a number is odd or even then simply "look" at the least significant bit isolated with an AND operation.
Code: [Select]
if(number & 1) { // the number is odd

Go Up