Chris O'Byrne - YAVRTOS |
|||||||||||||||||||||||||||
|
Interrupt Service Routines
Detailed DescriptionInterrupt Service Routines are functions that are called when an interrupt occurs, and are defined with the TASK_ISR() macro.Define Documentation
The macro for ISRs. The arguments are
The WinAVR™ ISR() macro can also be used to define ISRs - however, when using ISR() as opposed to TASK_ISR(), you cannot make use of any YAVRTOS API call from within your ISR, and your ISR will not (necessarily) be using the system stack. Taking this macro apart line-by-line, we have
// The standard way of calling an ISR void vector(void) __attribute__ ((signal,naked,__INTR_ATTRS)); // The ISR itself void vector(void) { // Save the entire CPU context to the stack (which could be a task stack or the system stack) save_cpu_context(); // Global interrupts were enabled just before this ISR was launched (otherwise it would not have // launched), and are disabled upon entry into the ISR. Set the interrupt enable bit at the location of // the saved status register on the saved stack so that when we restore the CPU context, interrupts will // be re-enabled. *(((uint8_t*)SP)+1) |= _BV(SREG_I); // Now, we have either interrupted a task or interrupted another ISR. system.interrupted_task will // be non-zero if a task has already been interrupted - i.e. if we have interrupted an ISR // Note that task_switch() also sets system.interrupted_task - any ISRs that manage to run during // the brief period when task_switch() enables interrupts should not subsequently run task_switch()! if (system.interrupted_task) { // We have interrupted an ISR (or we have interrupted task_switch()) // Execute the macro to see if we should do a task switch if (do_task_switch) { // The macro may have enabled interrupts - disable them again cli(); // Set bit 1 of system.interrupted_task - the bit that signals that a task switch is // required. We don't do the task switch just yet, as we have interrupted another ISR, // so we need to return to that ISR first. The ISR that interrupted the task will be the one // to actually perform the task switch (see below) // If we have actually interrupted task_switch(), then setting bit 1 of system.interrupted_task // will have no effect - but we were doing a task switch anyway! system.interrupted_task = 3; } else { // Task switch not required (this time). Make sure that interrupts are still disabled cli(); } } else { // We have interrupted a task // Save the stack pointer current_task->sp = (uint8_t *)SP; // Switch to the system stack SP = (uint16_t) system.stack_top; // Set the system.interrupted_task so that subsequent ISRs will know that they have interrupted // an ISR, not a task. This has the side-effect of disabling switch_task() - all API calls check // system.interrupted_task and do NOT perform a task switch if it is non-zero. system.interrupted_task = 1; // Execute the macro and see if we should do a task switch if (do_task_switch) { // The macro could have enabled interrupts - disable them cli(); // Signal to ourselves that we need a task switch - bit 1 of system.interrupted_task is set // when a task switch is required system.interrupted_task = 3; } else { // Make sure that interrupts are disabled cli(); } // At this point, any ISRs that interrupted us have finished. // Now, if a task switch is required, perform it! if (system.interrupted_task & 2) { // switch_task() will (eventually) reset system.interrupted_task, and never "returns" switch_task(); } // A task switch is not required - restore the stack pointer so that we return to the task SP = (uint16_t) current_task->sp; // We are about to return to the task - reset system.interrupted_task system.interrupted_task = 0; } // Return to whatever we were doing before this ISR was called restore_cpu_context(); __asm__ volatile ("ret" ::); }
|
||||||||||||||||||||||||||
YAVRTOS and YAVRTOS documentation Copyright © 2007-2008 Chris O'Byrne. Email - chris <at> obyrne <dot> com