I am writing an program for the LPC1768 that simulates a state machine. In the beginning states the program must be able to handle button interrupts (EINT1 EINT2). Then interrupts are disabled on the NVIC (Nested Vector Interrupt Controller) but are still sent to it, becoming pending. If I re-enable the interrupts they are handled, so i tried to clear the pending ones before doing that. It solves the problem but then new interrupts aren't seen anymore by the NVIC and I don't understand why.
I disable interrupt using:
NVIC_DisableIRQ(EINT2_IRQn);
NVIC_DisableIRQ(EINT1_IRQn);
when it's time I clear pending ones and re-enable:
NVIC_ClearPendingIRQ(EINT1_IRQn);
NVIC_ClearPendingIRQ(EINT2_IRQn);
NVIC_EnableIRQ(EINT2_IRQn);
NVIC_EnableIRQ(EINT1_IRQn);
The code was not executed on the board but only debugged using the keil uvision5 software.
Related
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.
Interrupts can be enabled for a specific pin(s) on a digital I/O port, correct? How would the ISR determine which pin caused the interrupt?
Because the vector table has only one slot for the Port1 ISR. So the same ISR function gets called no matter which input pin on Port1 needs attention unless I'm wrong...
As other people have suggested in comments this can be MCU dependent, but for ARM(The core behind MSP432) generally the answer is it doesnt know, it looks for it.
ARM has a vectored interrupt system, which means that every source has its own vector of interrupt, so CPU can easily find out which source is triggering thr interrupt. so far so good.
but then it happens that a device can trigger multiple interrupts, like GPIO as you said, in this case, CPU knows that which port has triggered interrupt so fires it's ISR but then it is ISR responsibility to poll device registers to figure out exact interrupt source, there are many of this peripherals with multiple interrupt, timers, DMAs just to name a few.
This is exactly why normally peripherals have an interrupt enable bit, that lets them trigger interrupts, but they also have bit masks that controls what exactly can trigger that interrupt internally,
Also have a look at this link for an in action example, specially at their ISR that does exactly the same as described above
In a typical MCU, there are hundreds, or at a stretch even thousands of potential interrupt sources. Depending on the application, only some will be important, and even fewer will be genuinely timing critical.
For a GPIO port, you typically enable only the pins which are interesting to generate an interrupt. If you can arrange only one pin of a port to be generating the interrupt, the job is done, your handler for that port can do the work, safely knowing that it will only be called when the right pin is active.
When you care about the cause within a single peripheral, and don't have the luxury of individually vectored handlers, you need to fall back on the 'non vectored' approach, and check the status registers before working out which eventual handler function needs to be called.
Interestingly, you can't work out which pin caused the interrupt - all you can see is which pins are still active once you get round to polling the status register. If you care about the phasing between two pulses, you may not be able to achieve this discrimination within a single GPIO unless there is dedicated hardware support. Even multiple exception vectors wouldn't help, unless you can be sure that the first exception is always taken before the second pin could become set.
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 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!
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.