This is the mail archive of the ecos-discuss@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Cortex-M3 interrupt handling & context switching


Hi

After getting rid of some more toolchain troubles I'm again faced with the proper implementation of interrupt handling and context switching. I'm still a bit puzzled, and would really appreciate some help, if anyone knows a bit of the Cortex-M3 architecture and the ecos kernel. I would like to use the Cortex's feature of saving/restoring some of the processors state automatically when entering/leaving exceptions (namely pc, lr, r12, r0-r3). This would also determine the bottom half of the HAL_SavedRegisters type:

typedef struct
{
// Additional states
cyg_uint32 basepri; // Base priority
cyg_uint32 r4, r5, r6, r7, r8, r9, r10, r11; // Data registers
cyg_uint32 lr_exc; // Link register in exception context
// Handled by exception handler
cyg_uint32 r0, r1, r2, r3; // Data registers
cyg_uint32 lr_thd; // Link register in thread context
cyg_uint32 pc; // Program counter
cyg_uint32 xpsr; // Condition register
} HAL_SavedRegisters;


The context switch can then be implemented using a system service call (SVC). Calling the context switch from within a thread would automatically push half of the processor state to the thread's stack on exception entry and pop on exit. Switching stacks, and pushing/popping the rest of the registers can be done in the SVC handler. The initial load of the first context would have to be handled in a special case, popping the complete processor state without a SVC call. Does this make sense to you?

Interrupts are also handled as exception on the Cortex-M3, so on entering/leaving an interrupt, half of the processor state is also saved/restored automatically. Interrupts can be preempted by higher priority interrupts, which pushes a new stack frame. Also, multiple interrupts can be tail-chained, which drops the pop/push of the stack frame for more efficiency. My current approach would look something like this:

- exception entry
- mask higher priority interrupts if nesting is disabled and store current priority on stack
- store additional processor state if necessary
- determine interrupt vector
- call respective interrupt handler
- call interrupt_end() -> may switch contexts
- restore additional processor state
- restore interrupt priority
- return from exception


As SVC would be of higher priority than any other interrupt exception, the call to the SVC would always preempt and create a new stack frame, and successfully switch contexts. Do you think this should work?

One problem I see, is when enabling interrupt nesting. As soon as a higher priority interrupt preempts a lower priority one, and leads to a context switch, the lower priority interrupt can be delayed for quite a while. The Cortex-M3 offers the PendSV exception, which can be run at the and of nested, or tail-chained exception handling, offering a good point for the scheduler to switch to the highest priority thread. But as I see it, ecos needs a call to interrupt_end() for every processed interrupt, possibly leading to a context switch. We could increment cyg_scheduler_sched_lock before entering interrupt_end() to prevent a context switch. Then we could call the scheduler (Cyg_Scheduler::unlock()) from the PendSV handler. Is this possible?

Providing a separate interrupt stack could pretty easily achieved, as the Cortex-M3 provides two separate stack pointers, which can be swapped.

Anyway, this is how I currently look at the subject. Comments, critics, hints are highly welcome.

Best regards,
Simon




-- Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]