ARM processor architecture------implementation of nested interrupts

Publisher:RadiantGazeLatest update time:2021-10-20 Source: eefocusKeywords:ARM Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

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.

  1. __asm ​​void IRQ_Handler(void){  

  2.       PRESERVE8  

  3.       IMPORT handler1      

  4.        

  5.       // STORE LR_irq & SPSR_irq  

  6.       SUB LR, LR, #4  

  7.       MRS R0, SPSR  

  8.       STMFD SP!, {R0, LR}  

  9.    

  10.       // INTO SVC MODE  

  11.       MRS R0, CPSR  

  12.       BIC R0, #0x1f  

  13.       ORR R0, #0x13  

  14.       MSR CPSR_C, R0  

  15.        

  16.       // STORE REGISTORS OF SVC MODE  

  17.       STMFD SP!, {R0-R3,LR}  

  18.        

  19.       // ENABLE IRQ  

  20.       MRS R0, CPSR  

  21.       BIC R0, #0x80  

  22.       MSR CPSR_C, R0  

  23.        

  24.       // GO TO HANDLER  

  25.       BL handler1  

  26.        

  27.       // RESTORE REGISTORS OF SVC MODE  

  28.       LDMFD SP!, {R0-R3,LR}  

  29.        

  30.       // DISABLE IRQ  

  31.       MRS R0, CPSR  

  32.       ORR R0, #0x80  

  33.       MSR CPSR_C, R0        

  34.        

  35.       // INTO IRQ MODE  

  36.       MRS R0, CPSR  

  37.       BIC R0, #0x1f  

  38.       ORR R0, #0x12  

  39.       MSR CPSR_C, R0  

  40.        

  41.       // RESTORE LR_irq & SPSR_irq  

  42.       LDMFD SP!, {R0, LR}  

  43.       MSR SPSR_CFX, R0  

  44.        

  45.   // EXIT IRQ  

  46.       MOVS PC, LR   

  47. }  


Keywords:ARM Reference address:ARM processor architecture------implementation of nested interrupts

Previous article:Mini2440 bare metal programming -------- touch screen driver
Next article:ARM processor architecture-----Exception/interrupt handling

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号