This post may be a solution to questions such as these:
- Seeing interrupt even though not enabling that interrupt
- Random high priority interrupt firing unintentionally
- How to nest interrupts of the same group
- How to nest interrupts of different groups
- Modify PIEIER to disable/enable interrupts in program
RULE: Do not modify PIEIER registers outside of an ISR for that group.
PIEIERx should only be modified within a group x interrupt before re-enabling interrupts. The common use case for this is when using nested interrupts. For example, PIEIER1 should only be modified within an ISR from group 1. Likewise PIEIER2 should only be modified within a group 2 ISR.
This modification should be done while the PIEACK bit for the group is still set and therefore no interrupts will be sent to the CPU while the modification is being done.
If this rule is violated, then spurious INTx.1 interrupts can be triggered.
When this happens: The PIEIERx register is used to determine which vector will be used for branch to an interrupt service routine. Because of this you must follow the proper procedure when clearing the bits within a PIEIERx register as described in the PIE section of the Technical Reference Manual for a particular device. If an interrupt from another group is sent during the ISR it is flagged at the CPU level, but is not serviced yet. If then the PIEIER is changed while the ISR is pending then when the CPU comes back and ask for the vector it may not find an interrupt that is both enabled and flagged. If this is the case it will fetch the first vector in the group.
Properly Handle Nested Interrupts
It is important to note that when you enter an ISR all the interrupts are disabled by the complier via INTM bit. If you want to nest interrupts of the same group then you should enable higher priority interrupts within a lower priority interrupt that is part of the same group. This is done by masking the IER appropriately, adjusting the PIEIER (of the same interrupt group), and then enabling interrupts.
You may nest a group interrupt inside another group’s ISR by re-enabling the interrupts for the other group (CPU IER register). What you cannot do is change the PIEIER register for a group inside a different group ISR.
For example within a group 6 ISR the user can re-enable interrupts for group 1. What the user cannot do is change the group 1 PIEIER1 register inside group 6 ISR. The user would have to be inside the group 1 ISR in order to modify the group 1 PIEIER1 register.
(But, if you must change the PIEIER of group 1 within a group 6 interrupt, there is a procedure for doing so in the PIE section of the Technical Reference Manual for a particular device)
Procedure for software-prioritizing (nesting) interrupts.
- Use the CPU IER register as a global priority and the individual PIEIER registers for group priorities. In this case the PIEIER register is only modified within an interrupt. In addition, only the PIEIER for the same group as the interrupt being serviced is modified. This modification is done while the PIEACK bit holds additional interrupts back from the CPU.
- Global Priority: This priority can be managed by manipulating the CPU IER register. This register controls the 16 maskable CPU interrupts (INT1 - INT16). These are the different interrupt groups.
- Group Priority: This can be managed by manipulating the PIE block interrupt enable registers (PIEIERx). There is one PIEIERx per group and each control the 8-interrupts multiplexed within that group. It is very important that only the PIEIERx register for the same group be changed.
2. Never disable a PIEIER bit for a group when servicing an interrupt from an unrelated group.
This is shown in assembly in the TMS320C28x FPU Primer, or you can follow the steps below to implement nested interrupts:
The steps required to nest interrupts are:
Step 1: Set the global priority:
- Modify the IER register to allow CPU interrupts with a higher user priority to be serviced.
- Note: at this time IER has already been saved on the stack.
Step 2: Set the group priority: (optional)
- Modify the appropriate PIEIERx register to allow group interrupts with a higher user set priority to be serviced.
- Do NOT clear PIEIER register bits from another group other than that being serviced by this ISR. Doing so can cause erroneous interrupts to occur.
Step 3: Enable interrupts:
- There are three steps to do this:
- Clear the PIEACK bits
- Wait at least one cycle
- Clear the INTM bit. Use the assembly statement asm(" CLRC INTM"); or TI examples use #define EINT asm(" CLRC INTM")
Step 4: Run the main part of the ISR
Step 5: Set INTM to disable interrupts. Use asm(" SETC INTM"); or TI examples use #define DINT asm(" SETC INTM")
Step 6: Restore PIEIERx (optional depending on step 2)
Step 7: Return from ISR
- This will restore INTM and IER automatically.
Example Code
//// C28x ISR Code
//// Enable nested interrupts
interrupt void EPWM1_TZINT_ISR(void)
{
uint16_t TempPIEIER;
TempPIEIER = PieCtrlRegs.PIEIER2.all; // Save PIEIER register for later
IER |= 0x002; // Set global priority by adjusting IER
IER &= 0x002;
PieCtrlRegs.PIEIER2.all &= 0x0002; // Set group priority by adjusting PIEIER2 to allow INT2.2 to interrupt current ISR
PieCtrlRegs.PIEACK.all = 0xFFFF; // Enable PIE interrupts
asm(" NOP"); // Wait one cycle
EINT; // Clear INTM to enable interrupts
//
// Insert ISR Code here.......
// for now just insert a delay
//
for(i = 1; i <= 10; i++) {}
//
// Restore registers saved:
//
DINT;
PieCtrlRegs.PIEIER2.all = TempPIEIER;
}
#endif
Advanced Software-Prioritizing with Masks Values Interrupts
For more advanced interrupt prioritization you can use mask values configured at compile time to set the global and group priorities. For more information on how to use mask values you can go to this wiki page (Interrupt_Nesting_on_C28x) or you can refer to the software prioritization example in the device support for you particular device found in ControlSUITE.
- http://processors.wiki.ti.com/index.php/Interrupt_Nesting_on_C28x
- Check the Systems Control and Interrupt section of the Technical Reference Manual for your particular device