I'm trying to learn interrupts by reading these slides and am wondering, why can polling be faster than interrupts? If a device has a direct wire to the CPU that it can use to signal an interrupt, I can't imagine something being faster than that.
Give each device a wire (interrupt line) that it can use to signal the
processor
• When interrupt signaled, processor executes a routine
called an interrupt handler to deal with the interrupt
(does it litterally mean a wire by the way?)
Polling can be better if processor has to respond to an event ASAP
Interrupt handling, needs context switching (pipeline break, save stack pointer, CPU registers, etc..) before servicing the interrupt, which needs some time (dependent on the architecture). Polling can be faster if it's the only task (keep polling for the event), as you stay in the same context. In this case, it's only the poll + loop instructions time.
Related
For uart reception, it's pretty obvious to me what can go wrong in case of 'blocking receive' over uart. Even in freertos with a dedicated task to read from uart, context / task switching could result in missing bytes that were received in the uart peripheral.
But for transmission I am not really sure if there is a need for interrupt based approach. I transmit from a task, and in my design it's no problem if that task is blocked for a short while. (it also blocks/sleeps on mutexes e.g).
Is there another strong argument to use use uart transmit in interrupt mode? I am not risking anything wrt loss of data, right?
In my case I use an stm32, but I guess the type of mcu is not really relevant here.
Let's focus on TX only and assume that we don't use interrupts and handle all the transmission with the tools provided by the RTOS.
µC UART hardware generally have a transmit shift register (TSR) and some kind of data register (DR). The software loads the DR, and if the TSR is empty, DR is instantly transferred into TSR and TX begins. The software is free to load another byte into DR, and the hardware loads the new byte from DR to TSR whenever the TX (shift-out) of the previous byte finishes. Hardware provides status bits for querying the status of DR & TSR. This way, the software can using polling method and still achieve continuous transmission with no gaps between the bytes.
I'm not sure if the hardware configuration I described above holds for every µC. I have experience with 8 & 16-bit PICs and STM32 F0, F1, F4 series. They are all similar. UART hardware doesn't provide additional hardware buffers.
Now, back to RTOS... Obviously, your TX task needs to be polling UART status bits. If we assume that UART baud rate is 115200 (which is a common value), you waste ~90 µs of polling for each byte. The general rule of RTOS is that if you are waiting for something to happen, your task needs to be blocked so other tasks can run. But block on what? What will tell you when to unblock? For this you need interrupts. Your task blocks on task notification, (ulTaskNotifyTake()), and the interrupt gives the notification using xTaskNotifyGive().
So, I can't imagine any other way without using interrupts. But, the method mentioned above isn't good either. It makes no sense to block - unblock with each byte.
There are 2 possible solutions:
Move TX handling completely to interrupt handler (ISR), and notify the task when TX is completed.
Use DMA instead! Almost all modern 32-bit µCs have DMA support. DMA generates a single interrupt when the TX is completed. You can notify the task from the DMA transfer complete interrupt.
On this answer I've focused on TX, but using DMA is the proper way of handling reception (RX) too.
I'm working a project where I am getting digital samples continuously through DMA on STM32f4. DMA generates a complete callback interrupt after every sample where I do some DSP. My plan is to allow freeRTOS to work on other tasks while DMA is waiting on the callback. However, DMA is generating callback too frequently, not allowing freeRTOS to run. I want to make it so that after every DMA complete callback, freeRTOS tasks is allowed to run for 6ms. I thought of calling __disable_irq() from complete callback and __enable_irq() from one of the tasks but that would not guarantee 6ms also I have a high priority button interrupt. I also tried disabling just DMA interrupt calling __set_BASEPRI(priority<<(8-__NVIC_PRIO_BITS)) then starting a timer for 6ms. On timer period elapsed callback in call __set_BASEPRI(0) to enable DMA interrupt. But for some reason this did not allow freeRTOS to run at all. It goes back and forth between DMA complete callback and Timer period elapsed callback.
I am new to embedded programming so any comment on this will help. Thank You.
You should not think of the DSP process being separate from the RTOS tasks, do the DSP in an RTOS task - the signal processing is the most time critical aspect of your system, you have to process the data as fast as it arrives with no loss.
If the DSP is being done in an interrupt context and starving your tasks, then clearly you are doing too much work in the interrupt context, and have too high an interrupt rate. You need to fix your design for something more schedulable.
If your DMA transfers are single samples, you will get one interrupt per sample - the ADC will do that on its own; so using DMA in that manner offers no advantage over direct ADC interrupt processing.
Instead you should use block processing, so you DMA a block of say 80 samples samples cyclically, for which you get a half-transfer interrupt at 40 samples, and full-transfer interrupt at 80 samples. So for each interrupt you might then trigger a task-event or semaphore to defer the DSP processing to a high-priority RTOS task. This achieves two things;
For the entirety of the n sample block acquisition time, the RTOS is free to:
be performing the DSP processing for the previous block,
use any remaining time to process the lower priority tasks.
Any interrupt overhead spent context switching etc. is reduced by 1/n, allowing more time performing core signal processing and background tasks.
Apart form reducing the number of interrupts and software overhead, the signal processing algorithms themselves can be optimised more readily when performing block-processing.
A variation on the above is rather then triggering a task event or semaphore from the DMA interrupt handler, you could place the new sample block in a message queue, which will then provide some buffering. This is useful if the DSP processing might be less deterministic, so cannot always guarantee to complete processing of one block before the next is ready. However overall it remains necessary that on average you complete block processing in the time it takes to acquire a block, with time to spare for other tasks.
If your lower priority tasks are still starved, then the clear indication is that your DSP process is simply too much for your processor. There may be scope for optimisation, but that would be a different question.
Using the suggested block-processing strategy I have in the past migrated an application from a TI C2000 DSP running at 200MHz and 98% CPU load, to a 72MHz STM32F1xx at 60% CPU load. The performance improvement is potentially very significant if you get it right.
With respect to your "high-priority" button interrupt, I would question your priority assignment. Buttons are operated manually with human response and perception times measured in 10's or even 100's of milliseconds. That is hardly your time critical task, whereas missing an ADC sample of a few microseconds would cause your signal processing to go seriously awry.
You may be making the mistake of confusing "high-priority" with "important". In the context or a real-time system, they are not the same thing. You could simply poll the button in a low-priority task, or if you use an interrupt, the interrupt should do no more than signal a task (or more realistically trigger a de-bounce timer) (see Rising edge interrupt triggering multiple times on STM32 Nucleo for example).
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!
I'd have some code that needs to be run as the result of a particular interrupt going off.
I don't want to execute it in the context of the interrupt itself but I also don't want it to execute in thread mode.
I would like to run it at a priority that's lower than the high level interrupt that precipitated its running but also a priority that higher than thread level (and some other interrupts as well).
I think I need to use one of the other interrupt handlers.
Which ones are the best to use and what the best way to invoke them?
At the moment I'm planning on just using the interrupt handlers for some peripherals that I'm not using and invoking them by setting bits directly through the NVIC but I was hoping there's a better, more official way.
Thanks,
ARM Cortex supports a very special kind of exception called PendSV. It seems that you could use this exception exactly to do your work. Virtually all preemptive RTOSes for ARM Cortex use PendSV to implement the context switch.
To make it work, you need to prioritize PendSV low (write 0xFF to the PRI_14 register in the NVIC). You should also prioritize all IRQs above the PendSV (write lower numbers in the respective priority registers in the NVIC). When you are ready to process the whole message, trigger the PendSV from the high-priority ISR:
*((uint32_t volatile *)0xE000ED04) = 0x10000000; // trigger PendSV
The ARM Cortex CPU will then finish your ISR and all other ISRs that possibly were preempted by it, and eventually it will tail-chain to the PendSV exception. This is where your code for parsing the message should be.
Please note that PendSV could be preempted by other ISRs. This is all fine, but you need to obviously remember to protect all shared resources by a critical section of code (briefly disabling and enabling interrupts). In ARM Cortex, you disable interrupts by executing __asm("cpsid i") and you enable interrupts by __asm("cpsie i"). (Most C compilers provide built-in intrinsic functions or macros for this purpose.)
Are you using an RTOS? Generally this type of thing would be handled by having a high priority thread that gets signaled to do some work by the interrupt.
If you're not using an RTOS, you only have a few tasks, and the work being kicked off by the interrupt isn't too resource intensive, it might be simplest having your high priority work done in the context of the interrupt handler. If those conditions don't hold, then implementing what you're talking about would be the start of a basic multitasking OS itself. That can be an interesting project in its own right, but if you're looking to just get work done, you might want to consider a simple RTOS.
Since you mentioned some specifics about the work you're doing, here's an overview of how I've handled a similar problem in the past:
For handling received data over a UART one method that I've used when dealing with a simpler system that doesn't have full support for tasking (ie., the tasks are round-robined i na simple while loop) is to have a shared queue for data that's received from the UART. When a UART interrupt fires, the data is read from the UART's RDR (Receive Data Register) and placed in the queue. The trick to deal with this in such a way that the queue pointers aren't corrupted is to carefully make the queue pointers volatile, and make certain that only the interrupt handler modifies the tail pointer and that only the 'foreground' task that's reading data off the queue modified the head pointer. A high-level overview:
producer (the UART interrupt handler):
read queue.head and queue.tail into locals;
increment the local tail pointer (not the actual queue.tail pointer). Wrap it to the start of the queue buffer if you've incremented past the end of the queue's buffer.
compare local.tail and local.head - if they're equal, the queue is full, and you'll have to do whatever error handing is appropriate.
otherwise you can write the new data to where local.tail points
only now can you set queue.tail == local.tail
return from the interrupt (or handle other UART related tasks, if appropriate, like reading from a transmit queue)
consumer (the foreground 'task')
read queue.head and queue.tail into locals;
if local.head == local.tail the queue is empty; return to let the next task do some work
read the byte pointed to by local.head
increment local.head and wrap it if necessary;
set queue.head = local.head
goto step 1
Make sure that queue.head and queue.tail are volatile (or write these bits in assembly) to make sure there are no sequencing issues.
Now just make sure that your UART received data queue is large enough that it'll hold all the bytes that could be received before the foreground task gets a chance to run. The foreground task needs to pull the data off the queue into it's own buffers to build up the messages to give to the 'message processor' task.
What you are asking for is pretty straightforward on the Cortex-M3. You need to enable the STIR register so you can trigger the low priority ISR with software. When the high-priority ISR gets done with the critical stuff, it just triggers the low priority interrupt and exits. The NVIC will then tail-chain to the low-priority handler, if there is nothing more important going on.
The "more official way" or rather the conventional method is to use a priority based preemptive multi-tasking scheduler and the 'deferred interrupt handler' pattern.
Check your processor documentation. Some processors will interrupt if you write the bit that you normally have to clear inside the interrupt. I am presently using a SiLabs c8051F344 and in the spec sheet section 9.3.1:
"Software can simulate an interrupt by setting any interrupt-pending flag to logic 1. If interrupts are enabled for the flag, an interrupt request will be generated and the CPU will vector to the ISR address associated with the interrupt-pending flag."
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.