cortex-m: where is exception number of interrupted interrupt stored - interrupt

For NVIC to be able to compare priorities it needs to know them.
That seems simple at first (it can get them from exception number; exception number of current interrupt is in SCB->ICSR bits [5:0]) but what happens when interrupt is interrupted? Where is exception number (or priority) of interrupted interrupt stored?
I've checked Yiu's book but can't find the answer there.

The Interrupt Program Status register contains "contains the exception type number of the current Interrupt Service Routine (ISR)" according to the ARM documentation.

NVIC_IPRn(Interrupt Priority Register) stores interrupt priorities as per bit description.
It's address starts from 0xE000E400 + 4n (secure)
Following is the bit assignment of NVIC_IPRn(0..128) register as per arm arm.
eg., LSB of NVIC_IPR0 contains the priority of INTR0.

Related

DMA_SxCR Enable bit unable to be written on stm32f412

I'm trying to start a DMA transfer on my stm32f412, and I've got everything set up to the point where I'm setting the control registers on the DMA channels/streams for TX and RX. I am able to set the enable (Bit 0) on the TX, but not the RX.
The datasheet has 3 options for the bit being cleared by hardware: 1.) On a DMA end of transfer (stream ready to be configured) 2.) If a transfer error occurs on the AHB master buses 3.) When the FIFO threshold on memory AHB port is not compatible with the size of the burst.
I don't think it could be the first or the third, because the DMA transfer hasn't even started yet, and there isn't a burst configured, it's just a single transfer. I'm not quite certain what the second means, but there aren't transfer errors marked in the error registers.
Any avenues to look into would be appreciated
Edit: Ugh, I was looking at the wrong registers for to find the DMA_LISR and _HISR. There was a transfer error on my RX channel.
From the description of DMA_SxCR_EN bit in the reference manual:
Note: Before setting EN bit to '1' to start a new transfer, the event flags corresponding to the
stream in DMA_LISR or DMA_HISR register must be cleared.
In my experience, these event flags include not only the error flags, but also the regular event flags like Transfer Complete or Half Transfer. In some cases, I also ended up clearing FIFO error flag, although I can't remember the reason behind it.
This problem manifests itself as "DMA works only once". In your case, it doesn't work even once, so there can be other problems. Still, I think it's worth trying to clear all the status flags before enabling the stream.

Switching context inside an ISR on Cortex-M

I'm trying to write a barebones round-robin scheduler for the Cortex-M using the CodeSourcery GCC toolchain. My scheduler uses the SysTick to fire an interrupt after the expiry of a time slice and the context switching takes place inside the ISR. To keep things simple, I am using only the main stack pointer (MSP) for everything.
I am stuck in determining how to handle loading the new context on the Cortex-M3. According to the Cortex-M3 Technical Reference Manual (TRM) the process pushes the PC, LR and status registers onto the current stack on the entry to the ISR.
If I push the rest of the registers to save the context of the present task and load a new SP value from the next task's control block how would I go about restoring the rest of its context?
According to what I understand, I need to pop out the registers I push (say {r4-r11}) and the processor will push out the rest (including the return address of the new task (LR) and status registers) automatically when the ISR returns. So I'm assuming I just need to execute a BX after I'm done to switch tasks?
Here is what it says on the TRM:
Exception returns occur when one of the following instructions loads a value of 0xFFFFFFFX into the PC when 1) POP/LDM which includes loading the PC 2) LDR with PC as a destination 3) BX with any register.
How do I go about loading the EXC_RETURN value? Should I just push it on to the stack (as it supposedly does here)? Assuming I've popped out the registers I've pushed via software, how does the Cortex go about popping the registers it has saved? In general, how do I restore a task's context?
I've tried reading the TRM and other ARM references but they seem unclear.
It is indeed quite complicated. I am writing a book about the FreeRTOS operating system running on Cortex-M cores. I have written a chapter about this. From reading your question I believe this chapter will help you:
Reading a bit more and some help on the #ARM IRC channel later I was able to understand the exception return mechanism. Here is what I understand.
As mentioned in the CM3 TRM, the core pushes the registers r0-r3, r12 along with the status, LR and PC on to the current process stack when an exception is registered. Thus, upon exception entry the stack contains 8 words which includes the LR containing the address to return to. The hardware pop mechanism essentially reverses the same action i.e. it pops out the last 8 words during which it loads the LR into the PC to return to the interrupted function.
Thus, the context can be switched simply by moving the stack pointer to an appropriate location such that the current stack frame resembles the stack frame of a task which has just been interrupted i.e. contains the exact words in the same order.
Upon exception entry and after saving the registers on to the stack, the LR is loaded with the EXC_RETURN value. This value contains special status flags to indicate return conditions. This is also used to indicate the end of the interrupt. That is, if the ISR needs to return to a task and switch the stack pointer from the current (MSP) to the PSP it can load the LR with the appropriate EXC_VALUE (indicated in TRM) and simply do a BX LR to switch states.
Here is a code fragment that does exactly what you need - https://github.com/DISTORTEC/distortos/blob/master/source/architecture/ARM/ARMv7-M/ARMv7-M-PendSV_Handler.cpp - it works as you described:
exception entry automatically stacks some registers,
you manually stack remaining registers,
you switch SP,
you unstack "remaining" registers,
exception return unstacks the rest of registers.

Process information when interrupted: stack or process control block

I am studying an Operating System course and we have this chapter about Processes. In this chapter we define the Process Control Block, which keeps the information about a process such as the program counter, content of registers, state, priority and so on. In this chapter it says that when the processor switches to another process (by interrupt), information will be saved in this process control block (PC, registers,...). In another chapter (1.4 Interrupts) it says when a process gets interrupted the PSW, PC and registers get put on the stack and when processor retakes control of this process it takes it from the stack.
It seems to be there are 2 different explanations here for what happens when an interrupt occurs. Do they both happen simultaneously or what? Can anyone explain this to me?
Thanks in advance
Sander
Think of an interrupt as a function call with the difference that it stores more information on the stack and occurs at any time breaking into the normal flow of the program instructions. So, if interrupt handler function decides just to return from the interrupt call, the state is restored from the stack.
Otherwise, if inside the interrupt call, OS decides to preempt the current user process, it saves all the process state to PCB and switch the stack to another process.
BTW, switching to another process can happen not only by interrupt but during any normal call to OS kernel API (syscall).

How does VxWorks prioritize interrupt bottom-halves?

Suppose I have two tasks, 'A' and 'B', of differing priority executing on SMP-supported VxWorks. Both 'A' and 'B' issue a command to an I/O device (such as a disk or NIC) and both block waiting for results. That is, both 'A' and 'B' are blocked at the same time. Some time later, the I/O device raises an interrupt and the ISR is invoked. The ISR then dispatches deferred work (aka "bottom-half") to a worker-task. Question: What is the priority of the worker-task?
VxWorks Device Driver Developer's Guide is a bit vague. It appears that the priority of the worker-task is set up a-priori. There are no automatic inheritance mechanisms that will increase the priority of the worker-task based upon the priorities of tasks ('A' and 'B') that are blocked waiting for results. This is similar to how threaded interrupt priorities work in PREEMPT_RT Linux. However, both QNX Neutrino and LynxOS will schedule the worker-task with the maximum priority of the blocked tasks-- Ex. priority(worker) = max_priority(A, B).
Can anyone clarify?
It depends exactly on which mechanism the "ISR dispatched deferred work" uses.
If a semaphore/messageQueue/Event is used, then the recipient task (A or B) will run at the priority specified when the task was created. In this scenario, the interrupt is essentially finished, and the task (A and/or B) are ready to run.
Whichever task is has the highest priority will get to run and perform it's work. Note that the task doesn't have access to any information from the interrupt context. If you use global structures (yuk) or pass data via a message queue, then the task could access those elements.
The network stack task (tNetTask) uses this approach, and a semaphore signals tNetTask when a packet has been received. When tNetTask has processed the packet (packet reassembly, etc...), it is then forwarded to whichever task is waiting on the corresponding socket.
It is possible to defer work from an ISR to tExcTask (via a call to excJobAdd). Note that with this approach, excJobAdd takes the pointer to a function and executes the function in the context of the tExcTask (which is at the highest priority in the system). It does not act as a self-contained task.
Note that some things like file systems, SCSI drivers, USB, etc... are much more than a simple driver with interrupts. They include a number of different components that unfortunately also increases complexity.

How can the processor recognize the device requesting the interrupt?

1) How can the processor recognize the device requesting the interrupt?
2) Given that different devices are likely to require different ISR, how can the processor obtain the starting address in each case?
3) Should a device be allowed to interrupt the processor while another interrupt is being serviced?
4) How should two or more simultaneous interrupt requests be handled?
1) How can the processor recognize the device requesting the interrupt?
The CPU has several interrupt lines, and if you need more devices than there are lines there's an "interrupt controller" chip (sometimes called a PIC) which will multiplex several devices and which the CPU can interrogate.
2) Given the different devices are likely to require different ISR How can the pressor obtain the starting address in each case?
That's difficult. It may be by convention (same type of device always on the same line); or it may be configured, e.g. in the BIOS setup.
3) Should a device be allowed to interrupt the processor while amother interrupt is being services?
When there's an interrupt, further interrupts are disabled. However the interrupt service routine (i.e. the device-specific code which the CPU is executing) may, if it's willing, reenable interrupts if it's willing to be interrupted.
4) How should two or more simultanement interrupt requests be handled?
Each interrupt has a priority: the higher-priority interrupt is handled first.
The concept of defining the priority among devices so as to know which one is to be serviced first in case of simultaneous requests is called priority interrupt system. This could be done with either software or hardware methods.
SOFTWARE METHOD – POLLING
In this method, all interrupts are serviced by branching to the same service program. This program then checks with each device if it is the one generating the interrupt. The order of checking is determined by the priority that has to be set. The device having the highest priority is checked first and then devices are checked in descending order of priority.
HARDWARE METHOD – DAISY CHAINING
The daisy-chaining method involves connecting all the devices that can request an interrupt in a serial manner. This configuration is governed by the priority of the devices. The device with the highest priority is placed first.