difference between IO-APIC-fasteoi and IO-APIC-edge - interrupt

In /proc/interrupts, I can see that some interrupt numbers belong to IO-APIC-fasteoi and some belong to IO-APIC-edge.
What is the difference between the two types of interrupt controllers?

The difference lies in the way the interrupts are triggered. The -edge interrupt are edge triggered. This is a rising level on the interrupt line.
The -fasteoi interrupts are level interrupts that are triggered until the interrupt event is acknowledged in the programmable interrupt controller (PIC). The EOI stands for End Of Interrupt. See also Wikipedia article on EOI.

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.

Handle interrupts with same priority

If I have a set of peripherals in an AVR microcontroller with equal priority, does the microcontroller use round-robin as a suitable arbitration mechanism for interrupting the sub system?
Or else, how can it manage interrupts with the same priority that happen at same time?
It depends.
For example "classical" AVR microcontrollers have simple one-level interrupt controller. That means, when interrupt is running, interrupt flag in SREG is cleared, thus blocking any other interrupt from running. IRET instruction enables this flag back again, and
after one instruction from the main code is executed, next interrupt is ready to be executed.
When several interrupt requests are asserted simultaneously, then only the one with the lowest interrupt vector address is chosen.
For example, refer to the ATMega328P datasheet (section 6.7 Reset and Interrupt Handling, page 15):
The lower the address the higher is the priority level.
Thus, if interrupt request flag is not cleared, or reasserted before return of the interrupt handler, the same interrupt will run again, and interrupt handlers with higher interrupt vector addresses might be never executed.
But in the newest versions of the architecture there is a more advanced interrupt controller, which allows to enable Round Robin scheduling, and assign to one of the interrupts a higher level (allowing it to be executed even if another interrupt handler is running).
For example in ATmega3208 (refer to the datasheet, section 12. CPU Interrupt Controller):
All interrupt vectors other than NMI are assigned to priority level 0 (normal) by default. The user may override this by assigning one of these vectors as a high priority vector. The device will have many normal priority vectors, and some of these may be pending at the same time. Two different scheduling schemes are available to choose which of the pending normal priority interrupts to service first: Static and round robin
So, the answer is: carefully read the datasheet on the part you're working with.
Section 9 of the ATmega328PB datasheet is entitled "AVR CPU Core" and it says:
All interrupts have a separate interrupt vector in the interrupt vector table.
The interrupts have priority in accordance with their interrupt vector position. The lower the interrupt vector address, the higher the priority.

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.

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.