The interrupt vector in 2440test is somewhat hidden and goes around in circles. No wonder it is so difficult to understand. Let's unravel it and see what the process is.
Interrupt vector
b HandlerIRQ; handler for IRQ interrupt is very natural, because all microcontrollers are like that, the interrupt vector is usually placed at the beginning, and people who have used microcontrollers will be very familiar with it, so I won’t say more.
Exception service routine
Here we use exceptions instead of interrupts. After all, interrupts are just a type of exception. The following mainly analyzes "interrupt exceptions". To put it simply, they are the interrupts we usually use in microcontrollers! ! ! All interrupts caused by devices, such as TIMER interrupts, UART interrupts, external interrupts, etc., have a unified entry, that is, the interrupt exception IRQ! Then, we can tell from the IRQ service function what the current interrupt is, and then jump to the corresponding interrupt service routine. In this way, ARM is more complicated than a microcontroller, but the principle remains the same.
The above is the idea. Let’s continue the analysis based on this idea.
HandlerIRQ is obviously a label, we found
HandlerIRQ HANDLER HandleIRQ
Here is a macro definition. Let's find this macro and see how it is defined:
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump addrESS)stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to originaladdress)
ldr r0,=$HandleLabel ;load the address of HandleXXX to r0ldr r0,[r0] ;load the contents(service routine start address) of HandleXXXstr r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stackldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)MEND
After expanding this macro with HandlerIRQ, the result is actually HandlerIRQ like this
sub sp,sp,#4 ;decrement sp(to store jump address)stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to originaladdress)
ldr r0,=HandleIRQ ;load the address of HandleXXX to r0ldr r0,[r0] ;load the contents(service routine start address) of HandleXXXstr r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stackldmfd sp !,{r0,pc} ;POP the work register and pc(jump to ISR)##2
As for the specific jump principle, we will talk about it below
Well, it is much easier to see this way. Obviously, HandlerIRQ is still a label. The IRQ exception vector jumps here to execute. A quick look here shows that it should save the scene and then jump to the real processing function. Then it is easy to find such a sentence ldr r0,=HandleIRQ. Yes, we found another label HandleIRQ. It seems that the real processing function should be this HandleIRQ. Continue to look for AREA RamData, DATA, READWRITE
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00HandleReset # 4
HandleUndef #4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
Finally, we found HandleIRQ here. ^ is actually MAP. This program means that starting from _ISR_STARTADDRESS, a variable is reserved. Each variable has a label. The reserved space is 4 bytes, which is 32BIT. In fact, the address of the processing function written in C is placed here. To put it bluntly, it is a function pointer - this is very flexible.
Next, we need to install the IRQ processing handle, which means setting the address of the processing function so that the PC pointer can jump correctly.
So we then find the statement to install the handle
; Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is neededldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1cstr r1,[r0]
To put it simply, fill the address of IsrIRQ into the address corresponding to HandleIRQ. As mentioned earlier, HandleIRQ is the entry address of the interrupt processing function. Let's continue to find IsrIRQ
IsrIRQ
sub sp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
To understand this code, you must first learn about the 2440 interrupt system. INTOFFSET stores the offset number of the current interrupt. Based on the offset, you can tell which interrupt source caused the current interrupt.
Note that we are talking about interrupts, not exceptions. Let's see what the original table looks like^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00##3
HandleReset # 4
HandleUndef #4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ #4
HandleEINT0 #4
HandleEINT1 #4
HandleEINT2 #4
HandleEINT3 #4
.......
As you can see, the first few are exceptions. HandleEINT0 is where the IRQ exception vector is stored. This explains why the instruction in IsrIRQ above needs to be executed.
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
The reason is very simple. HandleEINT0 is the entry of all IRQ interrupt vector tables. Add an appropriate offset, INTOFFSET, to this address, and we will know which IRQ is requesting an interrupt.
As for how to jump specifically?
First, we said that the memory starting from HandleEINT0 stores the function pointer of the interrupt service function. In the ARM system, each pointer variable occupies 4 bytes. Here we explain why 4 bytes of space are allocated for each label. The function pointer is stored in it! ! ! Next, let's see how to jump. Let's continue to see IsrIRQ, which implements the jump str r8, [sp, #8]
ldmfd sp!,{r8-r9,pc}
In fact, the core is these two sentences. First find the address of the current interrupt service program, put it in R8, then pop the stack, and pop it to the PC, then the PC will naturally jump to the interrupt service program. As for the stack problem here, it is a very tricky one. You need to understand the ARM interrupt architecture well. If you need to understand it, you can read the "ARM Architecture and Programming" carefully. Our focus here is to study how to jump.
Finally, let's see how the terminal vector is installed in the C code, for example, how to set up the external interrupt of the key, see the code in /src/keyscan.c
Very simple, there are only 3 functions
KeyScan_Test is the main function of key test
Key_ISR is the key interrupt service function
In KeyScan_Test, we found a sentence like this: pISR_EINT0 = pISR_EINT2 = pISR_EINT8_23 = (U32)Key_ISR; Do you understand? Key_ISR is the key interrupt service function mentioned above. The name of the function represents the address of the function! ! ! !
The address of the interrupt service function, note that it is an address, which is a U32 type variable. Send it to several variables. We take pISR_EINT0 as an example. Check the header file definition and find // Interrupt vector in 2440addr.h
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))_ISR_STARTADDRESS Does it feel familiar? Yes, it is mentioned in the assembly code just analyzed^ _ISR_STARTADDRESS; _ISR_STARTADDRESS=0x33FF_FF00##4
HandleReset # 4
HandleUndef #4
......
Yes, the address is here, and then _ISR_STARTADDRESS+0x20 is to skip the previous exception vector and enter the entrance of the IRQ interrupt vector.
pISR_EINT0 = (U32)Key_ISR;
The completed operation is to store the address of Key_ISR in
HandleEINT0 #4
Inside this IRQ vector table!!!
When a key interrupt occurs, an IRQ exception interrupt occurs
The current PC value -4 is saved in LR_IRQ, and then executed
b HandlerIRQ
Then execute
HandlerIRQ
sub sp,sp,#4 ; Reserve a register to store the PC address stmfd sp!,{r0} ; Save R0 because it is used below ldr r0,=HandleIRQ ; Load the address of HandleIRQ (service program) into R0ldr r0,[r0]
str r0,[sp,#4] ; Save to the place just reserved
ldmfd sp!,{r0,pc}; Pop the stack, restore R0, and pop the calculated HandleIRQ address to PC. The stack grows downward, so SUB SP, SP, #4 is equivalent to PUSH XX, but this XX is not used at this time, because it is implemented by forcibly moving the SP pointer. Then get the address of the service program, and put this value back to the empty space on the stack just reserved, and finally POP out R0 to restore, and send the address of the service program just obtained to PC, so the effect is to jump to HandleIRQ.
Next, let's see how HandleIRQ was installed.
; Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is neededldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1cstr r1,[r0]
It can be seen that the value of the address of IsrIRQ is saved in HandleIRQ here, that is to say, the IRQ service program above actually refers to IsrIRQ at this time!
So the next thing is to transfer to IsrIRQ for execution:
IsrIRQ
sub sp,sp,#4 ; reserve a value to save PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET ; calculate the offset, explained below ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]; Because two registers R8 and R9 are saved, SP is shifted down by 8 bits ldmfd sp!,{r8-r9,pc}; Restore the register and pop it to PC, the same as above##5
How to save and operate SP, and the part that pops up to PC at the end are the same as the above example. Let's talk about the calculation part in the middle to calculate the offset. In fact, the principle is very simple. First, INTOFFSET saves which IRQ interrupt is currently. For example, 0 represents HandleEINT0, 1 represents HandleEINT1 ... and so on. This is not random. There is a table. This is from the S3C2440 datasheet. You can check it yourself.
Then we get the vector table of the interrupt handling function. The first address of this table is HandleEINT0. So it is natural to think, how to look up the table? Isn't that simple? Isn't HandleEINT0 + INTOFFSET? The base address plus the offset will get an item in the table. Of course, because each item of the interrupt handling vector occupies 4 bytes, we use lsl #2 to process it. Shifting left by 2 bits is equivalent to multiplying by 4, and the offset is multiplied by 4. This should be easy to understand.
In this example, we find HandleEINT0 and read the value inside. It contains the address of the HandleEINT0 service function. Where does this address come from? It is set in the C program. Let's look at the keyscan.c program and find a void KeyScan_Test(void) function, which contains the following sentence:
pISR_EINT0 = pISR_EINT2 = pISR_EINT8_23 = (U32)Key_ISR; Three key interrupt service routines are installed here, we only focus on interrupt 0, that is, pISR_EINT0 = (U32)Key_ISR;
What does this sentence mean? Let's take a look at the definition of pISR_EINT0. It is defined in 2440addr.h as #define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20)). Did you see it? Isn't _ISR_STARTADDRESS the entry address of the exception vector just mentioned? After adding 0x20, it actually points to HandleEINT0!!! So, the above means that the entry address of the Key_ISR processing function is sent to HandleEINT0.
Let's look at Key_ISR again. This is a typical service routine. _irq is added as a compilation keyword to tell the compiler that this function is an interrupt service routine and needs to save the required registers to avoid being destroyed. For details, please refer to the description on page 283 of "ARM Architecture and Programming".
static void __irq Key_ISR(void)
{
.......
}
After adding the _irq keyword, the compiler will handle all the saving actions and you don't need to worry about it. However, this is a keyword of the ARM-CC compiler, and there is no such thing in GCC, so it is better to save it yourself when GCC handles interrupts.
So far, the entire interruption process has been explained. I have learned a lot during the analysis.
IV. Responsibilities and Scope
1. Technical Documents of Products and Services Provided
The products provided refer to all items that the bidder must provide to the tenderer in accordance with the provisions of the procurement documents, including equipment, supporting software, spare parts, consumables, drawings, manuals, technical data and other products and related data specified in the procurement documents.
The services provided refer to
the technical services and other services provided by the bidder in various stages from product production preparation to the expiration of the contract as stipulated in the contract, and the after-sales services after the expiration of the contract.
2. Technical Documents
4.2.1 The technical documents provided by the bidder shall include both electronic and written versions, and shall at least include the following technical documents:
a. For new models of products introduced in the quotation or products that the tenderer has not tested, written technical data and configuration instructions shall be provided.
b. Other required technical documents
4.2.3 The content of the technical documents provided must be consistent with the products provided.
4.2.4 Provide three sets of complete technical documents.
4.2.6 The handover of technical documents is one of the basis for acceptance.
(3) The technical part is evaluated based on the following factors: the enterprise's manufacturing process level, production and testing equipment, production capacity, etc. Bidders should present their own advantageous information as much as possible.
Products provided refer to all items that the bidder must provide to the tenderer in accordance with the provisions of the procurement documents, including equipment, supporting software, spare parts, consumables, drawings, manuals, technical data and other products and related data specified in the procurement documents.
Services provided refer to the technical services and other services provided by the bidder in various stages from product production preparation to the expiration of the contract as stipulated in the contract, as well as after-sales services after the expiration of the contract.
2. Technical documents
4.2.1 The technical documents provided by the bidder shall include both electronic and written versions, and shall at least include the following technical documents:
a. Written technical data and configuration instructions shall be provided for new models of products introduced in the quotation or products that the tenderer has not tested.
b. Other required technical documents
4.2.3 The content of the technical documents provided must be consistent with the products provided.
4.2.4 Three sets of complete technical documents shall be provided.
4.2.6 The handover of technical documents is one of the basis for acceptance.
(3) The technical part is evaluated based on the following factors: the enterprise's manufacturing process level, production and testing equipment, production capacity, etc. Bidders should present their own advantageous information as much as possible.
|