全部博文(31)
分类: 嵌入式
2010-04-23 01:16:18
Applies to:
If an interrupt is received by the core during execution of an instruction that disables interrupts, the ARM7 family will still take the interrupt. This occurs for both IRQ and FIQ interrupts.
For example, consider the follow instruction sequence:
MRS r0, cpsrIf an IRQ interrupt is received during execution of the MSR instruction, then the behavior will be as follows:
This means that, on entry to the IRQ interrupt service routine, one can see the unusual effect that an IRQ interrupt has just been taken while the I bit in the SPSR is set. In the example above, the F bit will also be set in both the CPSR and SPSR. This means that FIQs are disabled upon entry to the IRQ service routine, and will remain so until explicitly re-enabled. FIQs will not be re-enabled automatically by the IRQ return sequence.
Although the example shows both IRQ and FIQ interrupts being disabled, similar behavior occurs when only one of the two interrupt types is being disabled. The fact that the core processes the IRQ after completion of the MSR instruction which disables IRQs does not normally cause a problem, since an interrupt arriving just one cycle earlier would be expected to be taken. When the interrupt routine returns with an instruction like:
SUBS pc, lr, #4the SPSR_IRQ is restored to the CPSR. The CPSR will now have the I bit and F bit set, and therefore execution will continue with all interrupts disabled.
However, this can cause problems in the following cases:
Problem 1: A particular routine may be called as an IRQ handler, or as a regular subroutine. When the routine is called as a regular subroutine, the calling code must first disable interrupts. The routine determines how it was called by examining the I bit of the SPSR and returns using the appropriate instruction. If the routine is entered due to an IRQ being received during execution of the MSR instruction which disables IRQs, then the I bit in the SPSR will be set. The routine would therefore assume that it could not have been entered via an IRQ.
Problem 2: FIQs and IRQs are both disabled by the same write to the CPSR. In this case, if an IRQ is received during the CPSR write, FIQs will be disabled for the execution time of the IRQ handler. This may not be acceptable in a system where FIQs must not be disabled for more than a few cycles.
Workaround:
There are 3 suggested workarounds. Which of these is most applicable will depend upon the requirements of the particular system.
Add code similar to the following at the start of the interrupt routine.
SUB lr, lr, #4 ; Adjust LR to point to returnThis code will test for the situation where the IRQ was received during a write to disable IRQs. If this is the case, the code returns immediately - resulting in the IRQ not being acknowledged (cleared), and further IRQs being disabled.
Similar code may also be applied to the FIQ handler, in order to resolve the first issue.
This is the recommended workaround, as it overcomes both problems mentioned above. However, in the case of problem two, it does add several cycles to the maximum length of time FIQs will be disabled.
Disable IRQs and FIQs using separate writes to the CPSR, eg:
MRS r0, cpsrThis is the best workaround where the maximum time for which FIQs are disabled is critical (it does not increase this time at all). However, it does not solve problem one, and requires extra instructions at every point where IRQs and FIQs are disabled together.
Re-enable FIQs at the beginning of the IRQ handler. As the required state of all bits in the c field of the CPSR are known, this can be most efficiently be achieved by writing an immediate value to CPSR_c, for example:
MSR cpsr_c, #I_Bit:OR:irq_MODE ;IRQ should be disabledThis requires only the IRQ handler to be modified, and FIQs may be re-enabled more quickly than by using workaround 1. However, this should only be used if the system can guarantee that FIQs are never disabled while IRQs are enabled. It does not address problem one.