In traditional ARM, IRQ appears as a system exception. For the ARM core, there is only one system exception called IRQ. ARM generally finds the IRQ interrupt handler through the exception vector when processing IRQ. After entering the IRQ interrupt handler, ARM automatically masks IRQ, which means that subsequent interrupt requests are ignored during the interrupt response process. Even if VIC is used, VIC only suspends subsequent interrupt requests. In other words, traditional ARM interrupts cannot be nested or preempted.
However, ARM gives us a right, that is, we can manually open IRQ in the interrupt handler, so that the previous IRQ response process can be interrupted by the subsequent interrupt. This provides us with a way to solve interrupt nesting with software.
We all know the interrupt process very well: protect the scene à respond to interrupt à restore the scene. ARM has a corresponding stack register for each exception, and it will automatically switch without affecting each other. So naturally, in nesting, we can use SP_irq to protect and restore the scene. The process is as follows:
1. Entering the interrupt for the first time
2. ARM automatically saves CPSR to SPSR_irq
3. ARM automatically saves PC to LR_irq
4. ARM automatically turns off IRQ enable
5. Save general registers, LR_irq, SPSR_irq to the stack indicated by SP_irq
6. Turn on the IRQ enable bit
7. Perform interrupt service according to the interrupt number
7.1 Entering interrupt for the second time and starting nesting
7.2 ARM automatically saves CPSR to SPS_irq
7.3 ARM automatically saves PC to LR_irq
7.4 ARM automatically turns off IRQ enable
7.5 Save general registers, LR_irq, SPSR_irq to the stack indicated by SP_irq
7.6 Turn on the IRQ enable bit
7.7 Interrupt service according to interrupt number
7.8 Turn off IRQ enable bit
7.9 Restore general registers, LR_irq, SPSR_irq from SP_irq stack
7.10 Jump back to 7 via LR_irq
7.11ARM automatically restores CPSR from SPSR_irq
8. Turn off the IRQ enable bit
9. Restore general registers, LR_irq, SPSR_irq from SP_irq stack
10. Jump back to the task program through LR_irq
11. ARM automatically restores CPSR from SPSR_irq
In this way, nesting is achieved, and as long as the stack is large enough, many layers can be nested. Ignoring the priority, or teaching the interrupt controller to manage the priority, this is already good, although I don’t want to say it, but the problem still comes.
In the above process, there is a step to perform interrupt service according to the interrupt number. For different interrupt sources, we usually use different functions to write interrupt services, which is not only clear, but also helps to separate modules with different functions. So we need to change this step to: enter the service subroutine according to the interrupt number. In this step, we will involve function calls. In the process of function calling, PC is generally saved in LR_irq first, and LR_irq is restored to PC when returning. This is exactly the role of LR.
This fact is what caused the problem. Imagine this situation: when we enter the service routine, LR_irq is the return address of our program. At this time, the second interrupt comes. Recall what ARM automatically does when the interrupt occurs. ARM saves the PC to LR_irq! In this way, LR_irq is tampered with. Because we cannot predict when the interrupt will come, we cannot save this tampered LR_irq at all. After the program responds to the second interrupt, it returns all the way to this LR_irq, and as expected, it runs away.
It's disappointing, but we have a way to solve this problem. The solution is to switch the system to SVC state before entering the service subroutine. In this way, the return address will be saved in LR_svc when the subroutine is called, and it will not be tampered by the second interrupt. The process is as follows, and the differences from the first time are marked in red.
Why do we need to save r0-r3? Isn't it enough to save lr_svc?
1. Entering the interrupt for the first time
2. ARM automatically saves CPSR to SPSR_irq
3. ARM automatically saves PC to LR_irq
4. ARM automatically turns off IRQ enable
5. Save general registers, LR_irq, SPSR_irq to the stack indicated by SP_irq
6. Change the system status to SVC
7. Save R0-R3, LR_svc to the stack indicated by SP_svc
8. Turn on the IRQ enable bit
9. Enter the interrupt service subroutine according to the interrupt number
9.1 Entering interrupt for the second time and starting nesting
9.2 ARM automatically saves CPSR to SPS_irq
9.3 ARM automatically saves PC to LR_irq
9.4 ARM automatically turns off IRQ enable
9.5 Save general registers, LR_irq, SPSR_irq to the stack indicated by SP_irq
9.6 Change the system status to SVC
9.7 Save R0-R3, LR_svc to the stack indicated by SP_svc
9.8 Turn on the IRQ enable bit
9.9 Entering the interrupt service subroutine according to the interrupt number
9.10 Turn off IRQ enable bit
9.11 Restore R0-R3 from the stack indicated by SP_svc, LR_svc
9.12 Change system status to IRQ
9.13 Restore general registers, LR_irq, SPSR_irq from SP_irq stack
9.14 Jump back to 9 through LR_irq
9.15ARM automatically restores CPSR from SPSR_irq
10. Turn off the IRQ enable bit
11. Restore R0-R3 from the stack indicated by SP_svc, LR_svc
12. Change the system status to IRQ
13. Restore general registers, LR_irq, SPSR_irq from SP_irq stack
14. Jump back to the task program through LR_irq
15. ARM automatically restores CPSR from SPSR_irq
In this way, we can use the interrupt service subroutine without worrying about LR being tampered with. Let's take a look at the use of the stack during the nesting process. Before entering the SVC state, use the IRQ stack to save the general registers, LR_irq and SPSR_irq required for nesting. After entering the SVC state, use the SVC stack, and you need to save R0-R3 and LR_svc specified by the calling function. Of course, in the interrupt service routine, the SVC stack is also used. It can be seen that the stacks of both states are used. Of course, because the interrupt service routine uses the SVC stack, we can also consider putting the stack required for nesting into the SVC, so that the IRQ stack is not needed. The process is very similar to the previous method, except that the time to save LR_irq and SPSR_irq should be put after entering the SVC state, and the method can be copied through general registers. Finally, there is no need to return to the IRQ state, and the interrupt handler can be directly launched through SPSR_svc and LR_svc.
The program is posted below, using the stack split method, just an example.
__asm void IRQ_Handler(void){
PRESERVE8
IMPORT handler1
// STORE LR_irq & SPSR_irq
SUB LR, LR, #4
MRS R0, SPSR
STMFD SP!, {R0, LR}
// INTO SVC MODE
MRS R0, CPSR
BIC R0, #0x1f
ORR R0, #0x13
MSR CPSR_C, R0
// STORE REGISTORS OF SVC MODE
STMFD SP!, {R0-R3,LR}
// ENABLE IRQ
MRS R0, CPSR
BIC R0, #0x80
MSR CPSR_C, R0
// GO TO HANDLER
BL handler1
// RESTORE REGISTORS OF SVC MODE
LDMFD SP!, {R0-R3,LR}
// DISABLE IRQ
MRS R0, CPSR
ORR R0, #0x80
MSR CPSR_C, R0
// INTO IRQ MODE
MRS R0, CPSR
BIC R0, #0x1f
ORR R0, #0x12
MSR CPSR_C, R0
// RESTORE LR_irq & SPSR_irq
LDMFD SP!, {R0, LR}
MSR SPSR_CFX, R0
// EXIT IRQ
MOVS PC, LR
}
Previous article:Mini2440 bare metal programming -------- touch screen driver
Next article:ARM processor architecture-----Exception/interrupt handling
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Do you know all the various motors commonly used in automotive electronics?
- What are the functions of the Internet of Vehicles? What are the uses and benefits of the Internet of Vehicles?
- Power Inverter - A critical safety system for electric vehicles
- Analysis of the information security mechanism of AUTOSAR, the automotive embedded software framework
- Brief Analysis of Automotive Ethernet Test Content and Test Methods
- How haptic technology can enhance driving safety
- Let’s talk about the “Three Musketeers” of radar in autonomous driving
- Why software-defined vehicles transform cars from tools into living spaces
- How Lucid is overtaking Tesla with smaller motors
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Award-winning live broadcast | Beneng International launches millimeter-wave radar module based on Infineon technology, perfectly solving the pain points of the PIR market. Registration is open
- LTC3105 will not start
- Huawei is so poor that it has no money to buy keyboards and mice? Do you bring your own office supplies?
- [Evaluation of EC-01F-Kit, the NB-IoT development board of Essence] + Unboxing
- Review summary: BearPi-HM Micro foldable development board
- NeoPixel Infinity Cube
- [STM32F769Discovery development board trial] Discussion and application of DMA2D screen refresh efficiency
- Thank you for being here + my proactive change
- Using Energia to develop MSP430F5529LP under Windows 10 Basic process and problems encountered
- Wi-Fi 6E has been launched. What is the difference between it and ordinary Wi-Fi?