AVR External Interrupt - Page 1
Forum section: electronics / general

author: dan3460
author_rank: Frequent Contributor
timestamp: January 06, 2017, 02:29:26 am
content: I have a very basic question, can I use the same button to call int0 from inside the ISR?I want to use only one button (actually is the push function on a rotary encoder) to call a setup program inside the ISR, but once inside the ISR pressing that same button will call the ISR again.Normally I answer this kind of questions doing experiments, but I'm sure one of you guys knows the answer.Thanks

author: Buriedcode
author_rank: Super Contributor
timestamp: January 06, 2017, 02:49:35 am
content: Assuming you're using the Atmega series, I believe each interrupt has its own program vector, and priority - with reset and INT0 having the highest priority.I think the global interrupt enable flag is cleared when an interrupt is triggered, prevented further interrupts whilst in the ISR for that interrupt vector. However, once you're out of that, it will jump to the interrupt that occurred whilst servicing the previous one.So, assuming you're in your ISR, whilst I don't recommend it, you could theoretically manually enabled the global interrupt enable flag when you enter the ISR (that was just cleared in hardware as you entered the ISR) allowing that interrupt to be interrupted by other, in your case INT0.Quick test:Create a timer interrupt with a delay loop inside - purely to waste time. If the timer fires every 1ms, and the delay is less than this, you could spend almost all your time in the ISR - awful practice for any real-world project, but this is just a test. In that delay loop it checks a single variable, if its 0xFF. If it is, it lights an LED.A second interrupt from INT0 simply sets that file register as 0xFF.This way, if you really are going to another interrupt vector whilst in an ISR, the LED will light. If it only enters the interrupt *after* your primary ISR has finished, nothing will light.If the ISR in your project is fired regularly enough, you could always just check the state of your input, or give it its own interrupt (INT0) but use this ISR to just set a flag that you can check in other ISR's.

author: cv007
author_rank: Frequent Contributor
timestamp: January 06, 2017, 06:45:38 am
content: QuoteCalling other functions inside an isr is a good sign you are probably doing too much inside the isr.QuoteWhen an interrupt occurs, interrupts are disabled until enabled again by either the 'reti' instruction (generated by compiler, at end of isr), or you deciding to enable interrupts via sei() function (bad idea). (trivia- If I remember correctly, on the avr you will always get at least one instruction to run after interrupts are enabled before an interrupt will fire- so after an isr returns it will always run 1 instruction even if another isr was pending. /trivia)The biggest reason not to enable interrupts within an isr is you can very easily get the stack to run into your data unless you have a very good handle on which interrupts are enabled and how they all could potentially interact. Another good reason is because there is no need to do anything like that.I'm not quite sure what you are doing, but lets say you have a rotary encoder which fires INT0, here is probably a minimal isr which will take care of what you need (I haven't used avr in a long time, and this is just to get you possibly thinking differently than before)volatile uint8_t int0_pinb_save;ISR(PCINT0_vect){int0_pinb_save = PINB; //save state of encoder pinsdisable_this_int0_isr(); //no more int0 until main loop sees int0 data}//the_main_loop...if( int0_flag_is_set() ){process_int0_encoder(); //using int0_pinb_saveclear_int0_flag();enable_int0_isr(); //ready for next int0 event}...the encoder could be processed in the isr (setting flags to notify of press or turn), I was just trying to show a minimal isr that could do the job.

author: dan3460
author_rank: Frequent Contributor
timestamp: January 06, 2017, 12:33:01 pm
content: Thanks for the answers, but opens new questions. Maybe I should clear a little what I'm doing. I have a button attached to INT0, when pressed jumps into the ISR for INT0. In there it shows to the user a small menu where some parameter can be set. Pressing the same button again exits the ISR back to the program.If I understood correctly, once in the ISR the interrupts are disabled, so pressing the button attached to INT0 will not trigger the interrupt again. Is that correct?Also, would be possible to explain why ISRs should be kept as minimal as possible? Just want to learn, in this case the only external functions that I'm calling are LCD instructions to show the user what to do.

author: cv007
author_rank: Frequent Contributor
timestamp: January 06, 2017, 02:36:02 pm
content: QuoteRephrase that to- I have a button attached to INT0, when pressed notifies may main loop that a button was pressedQuoteYes. Interrupts are disabled by hardware when the avr decides to process an interrupt. Interrupt flags will still get set , though.QuoteWhen you are in the isr, all other isr's are blocked (isr's are now disabled), so when your user decides to change a setting, he could take 10 minutes to fiddle around with your menu, all the while nothing else happens- all other interrupts will not run. Maybe INT0 is your only interrupt for now, but lets say you also have an RX isr , or a timer isr keeping track of time- these are now all halted while stuck in your INT0 isr waiting for a user to complete your menu- no more RX characters received, no more updating of time, etc.Here's what happens when one tries to get clever by re-enabling interrupts inside interrupts-INT0 irq fires- about ~18 registers get pushed (saved) on the stackyou are in INT0you enable irq's insidebutton gets pressed- button probably bounces a few time (lookup button bounce)INT0 fires again- another 18 registers pushed on the stacksecond bounce- repeat- another 18(stack is growing down and eventually will run into your data)lets stop here, no need to go any farther- where am I in your menu system now?- did I even get into the menu with the second bounce, or did I exit the menu?You could spend some time to analyze what is actually happening (the above is probably incorrect to some degree)- but you will end up concluding its bad idea because you really cannot determine what is happening- add a few more isr's and it becomes even more difficult.I'm sure others can explain better.

author: Buriedcode
author_rank: Super Contributor
timestamp: January 06, 2017, 10:02:45 pm
content: Quote from: cv007 on January 06, 2017, 02:36:02 pmNot sure I could haveGenerally the ISR is for capturing *important* (as in time-critical) events, be it a rising edge on an input that indicates a major fault, a rising edge for timing something, received serial data which is soon to be overwritten by more incoming data etc.. It should do its job, and go back to the main as quickly as possibly as to not block other events - as stated by cv007. For things that dont' happen very often, or quickly, like user button presses, regular polling can work but then how often the software checks is down to what the software is currently doing.I suggest for your project you either have a regular timer tick for reading the state of buttons, or its own small ISR that just captures its state. Generally I have ISR's just store data, and set a flag, with the main routine checking these flags one by one, and 'doing stuff' if it needs to be done.Some LCD 'routines' can be rather long - like printing a string on the screen. Longer than I would like to have in an ISR. This should be part of your main routine, with the ISR's servicing your user inputs (again, probably with a timer for debouching). Googling 'Arduino menu systems' could help.

author: dan3460
author_rank: Frequent Contributor
timestamp: January 07, 2017, 01:28:28 am
content: Point taken, thanks for the information. My first goal is to have a working prototype, I will keep the call in the way that I have it for now. But I will look into moving the setup function away from the ISR.Thanks guys, I very much appreciate the input and the time you take in answering.

author: kcbanner
author_rank: Contributor
timestamp: January 09, 2017, 04:10:17 pm
content: The ISR for the button push should simply be used to set a flag. Your main loop then can check that flag and change states in your menu system accordingly. Being in an ISR shouldn't be used as a "mode", as anything else going on is halted. I'm not sure what you are building, but say your micro is also talking over i2c or USB to another device, all that communication is now going to be stalled.