3.6. Interrupt Handling¶
As long as you follow the guidelines in this section, you can interrupt and return to C/C++ code without disrupting the C/C++ environment. When the C/C++ environment is initialized, the startup routine does not enable or disable interrupts. If the system is initialized by way of a hardware reset, interrupts are disabled. If your system uses interrupts, you must handle any required enabling or masking of interrupts. Such operations have no effect on the C/C++ environment and are easily incorporated with asm statements or calling an assembly language function.
3.6.1. Saving Registers During Interrupts¶
When C/C++ code is interrupted, the interrupt routine must preserve the contents of all machine registers that are used by the routine or by any functions called by the routine. With the exception of banked registers, register preservation must be explicitly handled by the interrupt routine.
All banked registers are automatically preserved by the hardware (except for interrupts that are reentrant. If you write interrupt routines that are reentrant, you must add code that preserves the interrupt’s banked registers.) Each interrupt type has a set of banked registers. For information about interrupt types, see interrupt.
3.6.2. Using C/C++ Interrupt Routines¶
When C/C++ code is interrupted, the interrupt routine must preserve the contents of all machine registers that are used by the routine or by any functions called by the routine. Register preservation must be explicitly handled by the interrupt routine.
__interrupt void example (void)
{
...
}
If a C/C++ interrupt routine does not call any other functions, only those registers that the interrupt handler uses are saved and restored. However, if a C/C++ interrupt routine does call other functions, these functions can modify unknown registers that the interrupt handler does not use. For this reason, the routine saves all the save-on-call registers if any other functions are called. (This excludes banked registers.) Do not call interrupt handling functions directly.
Interrupts can be handled directly with C/C++ functions by using the __interrupt keyword. For information, see interrupt.
3.6.3. Using Assembly Language Interrupt Routines¶
You can handle interrupts with assembly language code as long as you follow the same register conventions the compiler does. Like all assembly functions, interrupt routines can use the stack, access global C/C++ variables, and call C/C++ functions normally. When calling C/C++ functions, be sure that any save-on-call registers are preserved before the call because the C/C++ function can modify any of these registers. You do not need to save save-on-entry registers because they are preserved by the called C/C++ function.
3.6.4. How to Map Interrupt Routines to Interrupt Vectors¶
To map interrupt routines to interrupt vectors you need to include a intvecs.asm file. This file will contain assembly language directives that can be used to set up C29x interrupt vectors with branches to your interrupt routines. Follow these steps to use this file:
Create intvecs.asm and include your interrupt routines. For each routine:
At the beginning of the file, add a .global directive that names the routine.
Modify the appropriate .word directive to create a branch to the name of your routine.
Assemble and link intvecs.asm with your applications code and with the compiler’s linker control file (lnk16.cmd or lnk32.cmd). The control file contains a SECTIONS directive that maps the .intvecs section into a specific memory location.
3.6.5. Using Software Interrupts¶
A software interrupt (SWI) is a synchronous exception generated by the execution of a particular instruction. Applications use software interrupts to request services from a protected system, such as an operating system, which can perform the services only while in a supervisor mode.
Since a call to the software interrupt function represents an invocation of the software interrupt, passing and returning data to and from a software interrupt is specified as normal function parameter passing with the following restriction:
All arguments passed to a software interrupt must reside in the four argument registers. No arguments can be passed by way of a software stack. Thus, only four arguments can be passed unless:
Floating-point doubles are passed, in which case each double occupies two registers.
Structures are returned, in which case the address of the returned structure occupies the first argument register.
The C/C++ compiler also treats the register usage of a called software interrupt the same as a called function. It assumes that all save-on-entry registers () are preserved by the software interrupt and that save-on-call registers (the remainder of the registers) can be altered by the software interrupt.
3.6.6. Other Interrupt Information¶
An interrupt routine can perform any task performed by any other function, including accessing global variables, allocating local variables, and calling other functions.
When you write interrupt routines, keep the following points in mind:
It is your responsibility to handle any special masking of interrupts.
A C/C++ interrupt routine cannot be called directly from C/C++ code.
In a system reset interrupt, such as c_int00, you cannot assume that the run-time environment is set up; therefore, you cannot allocate local variables, and you cannot save any information on the run-time stack.
In assembly language, remember to precede the name of a C/C++ interrupt with the appropriate linkname. For example, refer to c_int00 as _c_int00.
The FIQ, supervisor, abort, IRQ, and undefined modes have separate stacks that are not automatically set up by the C/C++ run-time environment. If you have interrupt routines in one of these modes, you must set up the software stack for that mode.
Interrupt routines are not reentrant. If an interrupt routine enables interrupts of its type, it must save a copy of the return address and SPSR (the saved program status register) before doing so.
Because a software interrupt is synchronous, the register saving conventions discussed in Saving Registers During Interrupts can be less restrictive as long as the system is designed for this. A software interrupt routine generated by the compiler, however, follows the conventions in Saving Registers During Interrupts.