Which Cortex-M3 interrupts can I use for general purpose work? - embedded

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."

Related

How to get data from an interrupt into a task-based system?

I am preparing for an embedded systems interview and was given this question as one of the questions to prepare with.
From my research, I learned that interrupts are called by a piece of hardware when there is an important issue that the OS should take care of and because of this data cannot be returned by an interrupt.
However, I didn't find any definitive information about how interrupts work with a task-based system. Is this a trick question about interrupts or is there a method to get data from them?
It is true that an interrupt cannot "return" data to a caller, because there is no caller. Interrupts are triggered by asynchronous events independent of normal program flow.
However it is possible for an interrupt pass data to a thread/task context (or even other interrupts) via shared memory or inter-process communication (IPC) such as a message queue, pipe or mailbox. Such data exchange must be non-blocking. So for example, if a message queue is full, the ISR may not wait on the queue to become available - it must baulk and discard the data.
interrupts are called [...] when there is an important issue that the OS should take care of [...]
It is not about "importance" it is about timliness, determinusm, meeting real-time deadlines, and dealing with data before buffers or FIFOs are overrun for example. There need not even be an OS, ant interrupts are generally application specific and not an issue for the OS at all.
I didn't find any definitive information about how interrupts work with a task-based system.
Perhaps you need to hone your research technique (or Google Fu). https://www.google.com/search?q=rtos+interrupt+communication
It's not a trick question. The problem is the same whether you have a "task-based system" (RTOS) or not:
Interrupts will happen at random times, relative to your main program. I.e. you could be calculating something like a = b + c and the interrupt could happen at a time where b is loaded into a register, but before c is.
Interrupts execute in a different context from your main program. Depending on the architecture, you could have a separate stack, for example.
Given the above, the interrupt service routines cannot take any parameters and cannot return any values. The way to pass data in and out of an ISR is to use shared memory (e.g. a global variable).
There are several ways to get data from interrupt:
Using queue or similar approach (implement in freeRTOS). NOTE: there is special API for ISR.
Using global variable. For this way you need to care about consistency of data because interrupt can happen anytime.
...

TinyAVR 0-Series: Can I use pin-change sensing without entering interrupt handler?

I am evaluating the ATtiny806 running at 20MHz to build a cycle-accurate Intel 4004 microprocessor emulator. (I know it will be a bit too slow, but AVRs have a huge community.)
I need to synchronize to the external, two-phase non-overlapping clocks. These are not fast clocks (the original 4004 ran at 750kHz)
but if I spin-wait for every clock edge, I risk wasting most of my time budget.
The TinyAVR 0-series has a very nice pin-change interrupt facility that can be configured to trigger only on rising edges.
But, an interrupt routine round-trip is 8 cycles (3 in, 5 out).
My question is:
Can I leverage the pin-change sensing mechanism while never visiting an ISR?
(Other processor families let you poll for interruptible conditions without enabling interrupts from that peripheral). Can polling be done with a tight skip-on-bit/jump-back loop, followed by a set-bit instruction?
Straightforward way
You can always just poll on the level of the GPIO pin using the single cycle skip if bit set/clear instruction on the appropriate PORT register and bit.
But as you mention, polling does burn cycles so I'm not sure exactly what you want here - either a poll (that burns cycles but has low latency) or an interrupt (that has higher latency but allows processing to continue until the condition is true).
Note that if things get really tight and you are looking for, say, power savings by sleeping between clock signal transitions then you can do tricks like having an ISR that nevers returns (saving the IRET cycles) but that requires some careful coding probably with something like a state machine.
INTFLAG way
Alternately, if you want to use the internal pin state machine logic and you can live without interrupts, then you can use the INTFLAGS flags to check for the pin change configured in the ISC bits of the PINxCTRL register. As long as global interrupts are not enabled in SREG then you can spin poll on the appropriate INTFLAG bit to check/wait for the desired condition, and then write a 1 to that bit to clear the flag.
Note that if you want to make this fast, you will probably want to map the appropriate PORT to a VPORT since the VPORT registers are in I/O Memory. This lets you use SBIS to test the INTFLAG bit a single cycle and SBI to clear the bit in a single cycle (these instructions only work on IO memory and the normal PORT registers are not in IO Memory).
Finally one more complication, if you need to leave the interrupts on when doing this, it is probably possible by hacking the interrupt priority registers. You'd set the pin change to be on level 0, and then make sure the interrupts you care about are level 1 or higher, and then trick the interrupt controller into thinking that there is already a level 0 running so these interrupts do not actually fire. There are also other restrictions to this strategy so avoid it if at all possible.
Programmable logic way
If you want to get really esoteric, it is likely possible that you could route the input value of a pin to a configurable custom logic LUT in the chip and then route the output of that module to a bit that you test using a 1-cycle bit test (maybe an unused IO Pin). To do this, you'd feedback the output of the LUT back into one of its inputs and then use the LUT to create a strobe on the edge you are looking for. This is very complex, and also since the strobe has no acknowledgement that if the signal changes when you are not looking for it (in a spin check) then it will be lost and you will have to wait for the next edge (probably fatal in your application).

How would an ISR know what pin cause the interrupt?

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.

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!

Passing parameters between interrupt handlers on a Cortex-M3

I'm building a light kernel for a Cortex-M3.
From a high priority interrupt I'd like to invoke some code to run in a lower priority interrupt and pass some parameters along.
I don't want to use a queue to post work to the lower priority interrupt.
I just have a buffer and size to pass to it.
In the proramming manual it says that the SVC interrupt handler is synchronous which presumably means that if you invoke it from an interrupt that's a lower priority than SVC's handler it gets called immediately (the upshot of this being that you can pass parameters to it as though it were a function call (a little like the BIOS calls in MS-DOS)).
I'd like to do it the other way: passing parameters from a high priority interrupt to a lower priority one (at the moment I'm doing it by leaving the parameters in a fixed location in memory).
What's the best way to do this (if at all possible)?
Thanks,
I'm not familiar with the Cortex-M3 architecture, but I'm sure what you need to provide a locking mechanism on the shared memory.
The higher priority interrupt can interrupt the lower priority processing at any time (unless some how you are specifically synchronizing this with hardware and you are gaurenteed this won't happen, but this is probably not the case)
The locking mechanism maybe as simple as a one bit flag, within a critical section(disabling interrupts for the read-modify-write on the flag) to guarantee an atomic exchange on the locking flag.(i.e. the if the lower priority process/interrupt is accessing/updating the locking flag, the higher priority interrupt does come in and change it.) The flag is then the synchronization mechanism for reading and writing to the shared memory space, allowing for both processes to lock out the other while it is accessing the shared resource, without disabling interrupts for an extend time.(I guess if the shared memory access is quick enough, you could just disable interrupts while you access the share memory directly)