What does an interrupt handler do? - interrupt

I know that when a keyboard interrupt occurs, the handler has code to save the character that has been received. What about other events that create interrupts like stack overflows, arithmetic overflow, divide by zero, etc? What does the interrupt handler do when these events occur?

There are basicaly three types of interrupts:
Hardware interrupts happen when there is a signal from an external device, like for example the keyboard or a mouse. The interrupt handler for those will get the data from the device and then let the program continue as if nothing happened.
Software interrupts are triggered by the program itself, they are used to call subroutines in the operating system or in device drivers.
Exception interrupts are triggered by certain operations when there is an unexpected result or a condition where there can't be a normal result, for example a division by zero. What the handlers for those do differ a bit depending on what the error is, but generally they print out an error message and terminate the program.

Related

Clearing interrupt necessary inside an ISR? (for Atmega644p uC)

When an interrupt service routine is being executed, is it necessary to clear global interrupts (using the cli(); command for example) to prevent another ISR from being executed or queued?
For example, if an external interrupt INT0 is being executed and while it is executing this same external interrupt were to be triggered again. Would that interrupt be queued to be executed after the first interrupt is finished?
would the follow code prevent an interrupt from being queued if it is executed during the current interrupt or would I need to clear an interrupt queue register?
ISR(someISR_vect){
cli();
some code...
sei();
}
No, you do not need to do that manually. AVR hardware already disables interrupts for you and the compiler will not re-enable interrupts when your handler is executing (by default).
Quoting from the "Nested interrupts" section of this page (it has no anchors, CTRL + F "Nested"):
The AVR hardware clears the global interrupt flag in SREG before entering an interrupt vector. Thus, normally interrupts will remain disabled inside the handler until the handler exits, where the RETI instruction (that is emitted by the compiler as part of the normal function epilogue for an interrupt handler) will eventually re-enable further interrupts.
The ISR() macro defines a function with a special name, and generates a call to that function in the interrupt table in AVR firmware. Additionally, the defined function might have attributes set. The two attributes which are of interest to you are interrupt and signal. Both declare the function as an interrupt handler, which causes the return statement to be replaced with a reti instruction (return from interrupt) and also cause the compiler to generate "function entry and exit sequences suitable for use in an interrupt handler".
The difference is that the interrupt automatically generates sei instruction which cause the interrupts to be enabled during the execution of your handler, basically overriding the hardware-set default. On the other hand, signal does not do that.
The only thing left to do is to check which one is set by ISR() by default. By consulting avr-libc code on github, specifically the interrupt.h file we can see that the ISR() macro specifies the __signal__ attribute by default (according to this it's the same attribute). At the same time, the macro ISR_BLOCK which may be passed as an arg to ISR() is blank. Meanwhile, the interrupt attribute is specified by the ISR_NOBLOCK macro few lines below. According to this, the default attribute for your interrupt handlers is signal, which does not re-enable interrupts when your handler is executing. You may verify this by looking at a disassembly of your interrupt vector compiled with and without ISR_NOBLOCK set to see whether the sei instruction is generated.
As for the behaviour of interrupts while the global interrupt flag is disabled, i will refer to the manual of Atmega644p, which at current time i have found here (it appears to be from 2016, but i doubt anything has changed since then in that regard):
When using the CLI instruction to disable interrupts, the interrupts will be immediately disabled. No
interrupt will be executed after the CLI instruction, even if it occurs simultaneously with the CLI instruction. (...) When using the SEI instruction to enable interrupts, the instruction following SEI will be executed before
any pending interrupts, as shown in this example.
AVR does not have a way to queue interrupts while these are disabled. What happens is that once the interrupt happens, an interrupt-specific flag (in contrast to the global interrupt flag) is set. If the interrupts are disabled, the interrupt handler will not execute. This way an interrupt may be in a pending state as referred to in the quote above. An example would be a TOV (timer overflow) flag in the TC0 (timer0 control) register (found in section 16.9.8 in the manual). When the overflow happens in Timer0, the flag will be set to 1. If the interrupts are globally disabled, the interrupt handler will not run, but the flag will remain set. The interrupt will be in the pending state. If another interrupt of the same type (timer0 overflow) happens before the interrupt handler manages to run, it will be lost, as there is only one flag bit per interrupt type. On the other hand another interrupt type, which has a separate flag, might happen during that time. Since it has a separate interrupt bit flag, it will be not impacted by the timer0 overflow interrupt being in the pending state. It will also be put in the pending state (the flag will be set to 1 but no handler will run until the interrupts are enabled again).
This is true for flag-based interrupts. AFAIK there are a few interrupts in AVR which are not flag-based and which behave slightly differently, but i have no experience with those and do not want to spread misinformation about them. I'd assume it is still impossible to queue more than 1 of each in the pending state, though.
Using cli in an ISR is unnecessary because the AVR automatically disables interrupts when entering the ISR.
Using sei in an interrupt is actually pretty dangerous in theory. It allows other interrupts to run before your interrupt has finished and deallocated the stack space it is using. Therefore, you could have many nested interrupts running at the same time without limit, potentially filling up your stack.
To answer your other questions: using cli and sei just affects the global interrupt enable bit. An interrupt flag from a peripheral can still be 1 or get changed to 1 regardless of the state of that bit. The AVR will jump to its interrupt service routine the next time interrupts are globally enabled and the peripheral's interrupt flag is equal to 1.

PIC32, Differences between Interrupts

What is the difference between INTDisableInterrupts() and INTEnableSystemMultiVectoredInt() and asm volatile ("di")
In Pic32, there are "normal" interrupts and "Vectored" interrupts. If you aren't familliar with Pic32, "vectored" means that each interrupt has it's own interrupt handler function. You can have a function for UART interrupt and another function for RS232 (UART),...
You do not have to put everything in a 'high priority' and a 'low priority' interrupt anymore.
So :
INTDisableInterrupts() will simply disable the interrupts. This will call "di".
"di" : simply disables the interrupts, in assmebler.
INTEnableSystemMultiVectoredInt() will let tell your PIC32 to use a different function for all your interrupts. If you did not provide interrupt handler functions for each of your interrupts, then it will seem as if they are disabled. Your interrupts are NOT disabled however, and if you write an handler for an Vectored interrupt, your pic will use it.
UPDATE:
#newb7777
To answer your question :
If you have only one interrupt ( not vectored ), then you have one big function that must check all the "Interrupt Flag register" to know what caused the interrupt and process the right code.
If you have 'vectored interrupts', then the PIC behaves like most processors ( they almost all have vectored interrupts ). When something happened that would generate an interrupt then a register changes value. For instance one that would be called "UART_1_Rx_Received". Before executing an instruction, the processor sees that this flag is on and if the 'Interrupt enable register' and the 'global interrupt enable register' are both ON, then the interrupt function will be called. Note that all interrupts also have a priority. If a high-priority interrupt is running then it will never be interrupted by an interrupt with <= priority. If a low priority interrupt is running then a higher priority interrupt could interrupt it.
However, you should not lose interrupts because if a byte comes from the UART that would generate a low-priority interrupt and a higher-priority interrupt is running, then the flag will still be set. When the higher priority interrupt ends, then the lower priority will be executed.
Why do we disable interrupts then ? The main reasons to disable interrupts are:
- the interrupt changes the value of a variable. if the code loops :
for(i=0;i==BufferSize;i++)
and your interrupt changes the value of BufferSize while this loop executes, then the loop could execute forever (if BufferSize changes from 100 to 2 while I has the value 99 then I will not get back to 2 for a long time...). You may want to disable interrupt before doing the loop in that case.
Another reason could be that you want to execute something where timing is important.
another reason is that sometimes, MCU needs you to execute a few instructions in a specific order to unlock something that would be dangerous to execute by error so you don't want an interrupt in the middle of the process.
If you have a circular buffer that received bytes from an interrupt and you pool that buffer from the code then you want to make sure to disable interrupts before removing a variable from the buffer to make sure the variables don't change while you read them.
There are many reasons to disable interrupts, just keep in mind that you can also create a "volatile" variable for global variables that are used in and outside of interrupts.
One last thing to answer your question : if you get an interrupt for every byte that comes in your UART at 115,200 baud, and you have an interrupt function that takes a long time to execute, then it is possible to miss a byte or two. In that case if you are lucky there is a hardware buffer that allows you to get them but it is possible also that there isn't and you would lose byte in your communication port. Interrupts must always be as short as possible. When possible, set a flag in the interrupt and do the processing in your main loop outside of the interrupt. When you have many interrupt levels, always use high priority for interrupts that could trigger often and low priority if an interrupt processes for a long time.

Control Flags in Interrupt Routine and NMI [8086]

I know how an interrupt routine is executed in 8086. The thing that isn't clear to me is how different types of interrupts (i.e hardware, software and exception) uses the control flags (Interrupt Flag and Trap Flag) in their execution.
And other thing is what is Non-mask-able Interrupts and its use?
So please help me with this, Thanks.
An interrupt handler doesn't "do" anything with the IF and TF flags. They are cleared so the interrupt handler can do its job properly and safely. You need to understand what those flags do, then it becomes obvious why they are cleared during an interrupt.
When the Interrupt Flag or IF is set, the processor will allow external hardware signals (usually from a Programmable Interrupt Controller or PIC) to trigger interrupts. When it's cleared, hardware interrupt signals are ignored.
(The NMI or Non-Maskable Interrupt is an exception, a special case intended for "emergency-type" or "real-time" events, and it will trigger even if the IF is cleared.)
The Trap Flag or TF is used by debuggers. When the flag is set, the processor will execute exactly one instruction, then trigger an INT 1. A debugger can use this to single-step machine code without having to temporarily modify it (e.g. to temporarily insert an INT 3 instruction), which is not always even possible (e.g. single-stepping code stored in ROM).
Now why are both flags cleared during interrupts?
The IF is cleared because Intel didn't want to impose the restriction that interrupt handlers be reentrant. Reentrant code is code that can be safely suspended at any time, and called again from the top. If you allow interrupts while an interrupt handler is running, it is quite possible for a second interrupt to trigger while in the middle of handling the first one, which would cause the handle to re-enter. Note that software interrupt handlers (like the DOS interrupt handler 21h) typically don't have this concern because they are not called by asynchronous hardware signals; therefore, just about the first thing they do is execute STI to re-enable interrupts.
The situation with TF is very similar but a bit trickier to understand. I don't have experience writing an x86 debugger, so I don't know the ins-and outs. The short version is that the TF is cleared during interrupts to avoid chaos. What follows is a speculative excercise of mine.
First of all, it should be obvious that at least the single-step interrupt (type-1 or INT 1 if you will) MUST clear the flag, otherwise the debugger's single-step handler itself would trigger single-step interrupts or not run at all. Second, let's imagine that the TF is not cleared for every interrupt: if a hardware interrupt triggers while the debugger is trying to use the TF, the interrupt handler itself might be the one triggering the single-step interrupt, instead of the code being debugged. Worse, now the interrupts are suspended (see IF above) and not only are you looking at the wrong code (or thoroughly confused the debugger), but your keyboard doesn't work anymore. (As I said, I'm speculating: I have no idea what happens if IF is cleared but TF is set).
Asynchronous hardware interrupts need to be handled without "bothering" the current running program, that is, they need to execute without the program being aware of them. That includes "not bothering" a single-stepping debugger.

What happens when an ISR is running and another interrupt happens?

What happens if an ISR is running, and another interrupt occurs? Does the first interrupt get interrupted? Will the second interrupt get ignored? Or will it fire when the first ISR is done?
EDIT
I forgot to include it in the question (but I included it in the tags) that I meant to ask how this worked on Atmel AVR's.
Normally, an interrupt service routine proceeds until it is complete without being interrupted itself in most of the systems. However, If we have a larger system, where several devices may interrupt the microprocessor, a priority problem may arise.
If you set the interrupt enable flag within the current interrupt as well, then you can allow further interrupts that are higher priority than the one being executed. This "interrupt of an interrupt" is called a nested interrupt. It is handled by stopping execution of the original service routine and storing another sequence of registers on the stack. This is similar to nested subroutines. Because of the automatic decrementing of the stack pointer by each interrupt and subsequent incrementing by the RETURN instruction, the first interrupt service routine is resumed after the second interrupt is completed, and the interrupts are serviced in the proper order. Interrupts can be nested to any depth, limited only by the amount of memory available for the stack.
For example, In the following diagram, Thread A is running. Interrupt IRQx causes interrupt handler Intx to run, which is preempted by IRQy and its handler Inty. Inty returns an event causing Thread B to run; Intx returns an event causing Thread C to run.
Image Ref
For hardware interrupts, Priority Interrupt Controller Chips (PIC's) are hardware chips designed to make the task of a device presenting its own address to the CPU simple. The PIC also assesses the priority of the devices connected to it. Modern PIC's can also be programmed to prevent the generation of interrupts which are lower than a desired level.
UPDATE: How Nested Interrupt Works on Atmel AVRs
The AVR hardware clears the global interrupt flag in SREG before entering an interrupt vector. Therefore, normally interrupts remain disabled inside the handler until the handler exits, where the RETI instruction (that is emitted by the compiler as part of the normal function epilogue for an interrupt handler) will eventually re-enable further interrupts. For that reason, interrupt handlers normally do not nest. For most interrupt handlers, this is the desired behaviour, for some it is even required in order to prevent infinitely recursive interrupts (like UART interrupts, or level-triggered external interrupts).
In rare circumstances though nested interrupts might be desired by re-enabling the global interrupt flag as early as possible in the interrupt handler, in order to not defer any other interrupt more than absolutely needed. This could be done using an sei() instruction right at the beginning of the interrupt handler, but this still leaves few instructions inside the compiler-generated function prologue to run with global interrupts disabled. The compiler can be instructed to insert an SEI instruction right at the beginning of an interrupt handler by declaring the handler the following way:
ISR(XXX_vect, ISR_NOBLOCK)
{
...
}
where XXX_vect is the name of a valid interrupt vector for the MCU type.
Also, have a look at this Application Note for more info on interrupts on Atmel AVRs.
The way interrupts work:
The code sets the "Global Interrupt Enable" bit; without it, no interrupts will occur.
When something happens to cause an interrupt, a flag is set.
When the interrupt flag is noticed, the "Global Interrupt Enable" bit is cleared.
The appropriate ISR is run.
The "Global Interrupt Enable" bit is re-set.
Things now go back to step 2, unless an interrupt flag is already set during the ISR; then things go back to step 3.
So to answer the question: When the first ISR is finished, the second ISR will be run.
Hope this helps!

What happens if another interrupt is raised before the first interrupt action is completed?

This question is from the interrupt handling topic.
Suppose an interrupt is being serviced. What happens if another interrupt is raised even before the first interrupt action is completed?
The following applies to the x86 architecture only, but other architectures might well follow the same pattern:
There is a processor flag called IF (Interrupt Flag) that controls whether hardware interrupts can be processed, or have to be put on hold. When IF = 0, interrupts will be postponed until the flag is reenabled (Except for the NMI, the Non-Maskable Interrupt, which is intended as an 'emergency only' interrupt that cannot be blocked).
The IF is automatically cleared by the processor before an interrupt servicing routine is called. This is necessary to prevent interrupt calls to become reentrant out of control. Note that the interrupt servicing code itself could not do this on its own, because if IF were not disabled before entering the routine, it would be possible for more interrupts to occur before the servicing code has time to execute even a single instruction. Then, a "firehose" of interrupts would immediately result in (of all things) a stack overflow.
So, in answer to your direct question: typically, when a second hardware interrupt occurs while an initial one is being serviced, that interrupt will be put on hold until the first one has finished.
As usual, the full story is a bit more complicated. The Intel Architecture Software Developer’s Manual at Intel's web site gives a more complete description starting on page 10-4.
It depends on the system. Normally, if the new interrupt is a higher priority than the first, then it is responded to, suspending the handler for the first interrupt. When its handler finishes, then the original interrupt handler resumes. Finally, assuming no more interrupts, the original handler finishes and normal service resumes. Sometimes, the resumed process will be the process that was interrupted; sometimes, it will no longer be the most eligible process and some other one will resume.
Similarly, if a second or subsequent instance of the original interrupt occurs before the first handler completes, or if a lower or equal priority interrupt occurs, it will be held up until the first handler completes. Before normal processing is resumed, the kernel checks for outstanding interrupts that should have been handled but were blocked.
An interrupt handler may block other interrupts.
Well, if interrupts were not disabled after the first interrupt, the second will cause your interrupt service routine to be called again. You must make sure interrupts get disabled to avoid this decidedly undesirable behavior.
So, if your interrupt service routine is doing its thing, and then another interrupt occurs, it will be just as if you were doing anything else: the corresponding interrupt routine will be called.
On the Intel architecture, the "cli" instruction will disable interrupts, and "sti" will enable them again.