Erika Enterprise and Erika Enterprise Basic for dsPIC (R) DSC provide support for fast Interrupt Service Routines (ISR) which do not require any RTOS primitive to be called, as well as regular ISRs, which can call RTOS primitives (e.g., a timer interrupt can call ActivateTask to activate a periodic task). The first kind of ISRs are called ISR Type 1, and always have hardware interrupt priority greater than the second kind of ISRs which are called ISR Type 2.
At the implementation level, Erika Enterprise uses the dsPIC (R) DSC DISI assembler instruction to implement interrupt disabling. The DISI instruction only disables the first 6 priority levels out of the 7 available in the 16-bit dsPIC (R) DSC core. For this reason, ISR Type 2 must always have an interrupt priority between 1 and 6.
ISR Type 1 must always have a priority greater or equal than ISR Type 2. As a matter of fact, interrupt priority 7 is reserved for ISR Type 1 only. ISR names follow the Microchip convention. Basically the ISR names are listed inside the linker script for the particular target which are provided together with the
ASM30 assembler packaged together with Microchip MPLAB IDE under the directory
To define an ISR Type 1 the developer has to write an interrupt handler as it is written in typical dsPIC (R) DSC applications which does not use Erika Enterprise. Here is an example of the definition of an ISR Type 1 for the timer 3 Interrupt of a pic30F2010 device:
void __attribute__(( __interrupt__)) _T3Interrupt( void)
{
...
}
Writing an ISR 1 in this way implies that:
• The C function will be attached to the interrupt of the peripheral (in the example, timer 3). Every time an interrupt for the peripheral arrives, then the C function will be executed.
• The compiler will generate a proper function prologue and epilogue which saves the register used before starting executing the statements inside the function. The registers will be saved inside the stack of the interrupted task. For that reason, when using a multistack configuration, the user should reserve a proper space able to contain all the nested ISR Type 1 for each stack in the system. To define an ISR Type 2 the developer has to write a C function in the following way:
# include " cpu/ pic30/ inc/ ee_irqstub.h"
...
ISR2( _T3Interrupt)
{
...
}
Writing an ISR 2 in this way implies that:
• An assembler stub will generated for the ISR. The ISR stub will have the name of the ISR (in the example, _T3Interrupt). The assembler stub will call a C function named ISR2_functionname which content is specified as the content of the function (in the example, the function is called ISR2__T3Interrupt). The assembler function will be attached to the interrupt of the peripheral (in the example, timer 3). Every time an interrupt for the peripheral arrives, the assembler stub will execute,
which in turns calls the internal C function whose body has been specified by the developer.
• The assembler stub saves all the CPU registers on the current stack. After that, if a multistack configuration with private IRQ stack has been selected, the stack is changed to a private IRQ stack. Otherwise, the ISR will execute on the stack of the running task, as in the ISR1 case. At the end of the stub, the Erika Enterprise end IRQ function will be executed to choose which is the next task to run.
|