If your system doesn't support a programmable interrupt controller and you want tasks to be rescheduled when interrupts occur then on entry to an ISR the register state of the current task must be saved and the ctl_interrupt_count variable must be incremented.
When you are executing an interrupt handler the ctl_task_wait function should not be called. Other CrossWorks tasking library functions may be called but a task switch will only occur when the last interrupt handler has complete execution.
In order to achieve a task switch from an interrupt service routine the ctl_exit_isr function must be called (or rather jumped to) as the last action of an interrupt service routine.
void ctl_exit_isr(void *savedRegisters);
The savedRegisters parameter points to the registers saved on the stack on entry to the interrupt service routine. This function will decrement the TaskInterruptCount variable and if it is zero it will check if a task switch is required. If a task switch is needed then the register state in savedRegisters will be stored in the currently executing task and a new task will be made the executing task. If a context switch isn't required or the ctl_interrupt_count is non-zero then the register state in savedRegisters is restored and the interrupt handler returns.
This example declares an ISR using the GCC syntax for declaring naked functions and accessing assembly code instructions.
void irq_handler(void) __attribute__((naked)); void irq_handler(void) { asm("stmfd sp!, {r0-r12, lr}"); asm("mrs r0, spsr"); asm("stmfd sp!, {r0}"); ctl_interrupt_count++; .... // do interrupt handling stuff in here .... asm("mov r0, sp"); asm("b ctl_exit_isr"); }
Note that the registers spsr, r0-r12 and the r14 (user mode pc) must be saved on the stack. The user mode r13 and r14 registers don't need to be saved because they are held in banked registers.
Note that FIQ handlers are not supported on the ARM.
This example declares an ISR using the CrossWorks assembler. Currently there is no way to use the CrossWorks C compiler to declare an ISR that can be used with the CrossWorks tasking library.
ISR: push.w r4 push.w r5 push.w r6 push.w r7 push.w r8 push.w r9 push.w r10 push.w r11 push.w r12 push.w r13 push.w r14 push.w r15 add.w #1, &_ctl_interrupt_count .... // do interrupt handling stuff in here .... mov.w sp, r15 jmp _ctl_exit_isr
Note that registers r4-r15 have to be saved on the stack - the pc and status registers are saved by the processor when the interrupt occurs.