Analysis of interrupt processing of S3C2410 && WinCE6.0
[Copy link]
The core of S3C2410 is ARM920T, so here we will first introduce the exceptions of ARM920T. There is a current program status register (CPSR) in ARM920T, in which BIT6 and BIT7 respectively control whether FIQ and IRQ are enabled or not. The interrupt on and off that we often talk about refers to setting these two bits.
The exception interrupts of the ARM system are shown in the figure below:
As you can see, there are a total of 7 exception modes in ARM920T. If multiple exceptions occur at the same time, the system decides which exception to handle based on the priority order. The priority order between them is from high to low:
1. Reset
2. Data Abort Data access abort
3. FIQ Fast Interrupt Request
4. IRQ External Interrupt Request
5. Instruction prefetch abort
6. Undefined instructions and software interrupts
When an exception occurs in the system, the PC pointer will jump to the corresponding exception interrupt handler. The correspondence between the exception interrupt and its handler is called the exception vector table, which is usually called the interrupt vector table. Generally, it is stored at a low address (0x0), but in WinCE, the table is stored at a high address (0xffff0000).
The interrupt processing process of S3C2410 is shown in the figure below:
As you can see, the registers closely related to interrupts in S3C2410 are mainly the following:
SUBSRCPND (Secondary Source Pending Register): After the hardware generates an interrupt, the corresponding bit of this register is set to 1;
SUBMASK (secondary mask register): If the corresponding bit of this register is 1, the interrupt is masked and no further submission is made;
SRCPND (source pending register): If the secondary interrupt source generates an interrupt, when SUBSRCPND and SUBMASK meet the conditions, the corresponding bit of this register is set to 1, or the corresponding bit of this register is set to 1 directly by the primary interrupt source;
MASK (first-level mask register): If the corresponding bit of this register is 1, the interrupt is masked and no further submission is made;
MODE (interrupt mode register): determines whether the interrupt is in FIQ mode or IRQ mode. There can only be one FIQ interrupt in the system. If the current interrupt is in FIQ mode, a FIQ exception is generated and the CPU enters the FIQ exception handler.
PRIORITY (priority control register): controls the priority of each interrupt source. When multiple interrupt sources send requests at the same time, the interrupt source with the highest priority will eventually generate an IRQ.
INTPND (interrupt pending register): When a bit in SRCPND is set to 1 and is not masked, the corresponding bit of the register is also set to 1, and an IRQ exception is generated, and the CPU enters the IRQ exception handler.
In the IRQ exception handler, SRCPND and INTPND need to be cleared. The method of clearing SRCPND and INTPND is special. Instead of writing 0 to the corresponding bit, you should write 1 to the corresponding bit. Generally, the value is read out and then written in to complete the work of clearing SRCPND and INTPND.
In addition to the above registers, 2410 also has an INTOFFSET register, which is used to indicate which interrupt request is currently being processed. The OEMInterruptHandler() function of WinCE determines which interrupt is currently making a request based on its value. This register is automatically reset when SRCPND and INTPND are cleared. Therefore, it does not need to be processed in the code.
If the interrupt source is EINT4-23, you also need to process several registers such as EXTINTn, EINTFLT, EINTMASK and EINTPEND. In addition, since the interrupt pins of 2410 are generally multiplexed with IO, before using a specific external interrupt, you need to set the corresponding GPIO to work in interrupt mode.
The interrupt handling process in WinCE6.0 is shown in the figure below:
As you can see, the entire processing process is divided into four layers, namely hardware, kernel, OAL and driver. The hardware generates an IRQ, the CPU enters the interrupt service routine, calls the OEMInterruptHandler() function in the OAL, and returns a SYSINTR based on the IRQ. The kernel sets an event based on the SYSINTR, and the driver captures the event and executes the corresponding handler. After the processing is completed, InterruptDone() is called to notify the CPU that the interrupt processing is completed.
Here we explain the concepts of SYSINTR and IRQ. IRQ is generally considered to be a physical interrupt number, which is determined by hardware. SYSINTR is a logical interrupt number, which generally corresponds to IRQ one by one. This correspondence can be established statically in OAL, generally through the function OALIntrStaticTranslate(). The statically mapped IRQ is generally the interrupt source inside the MCU, such as the USB Host. In order to improve the portability of the driver, dynamic mapping is usually adopted, such as the network card driver. Different hardware platforms may use different external interrupts for network cards. Through dynamic mapping, the driver can be transplanted by simply modifying the corresponding key value in the registry without modifying the code. The method of dynamically mapping IRQ in the driver is to call the function KernelIoControl(), the first parameter is IOCTL_HAL_REQUEST_SYSINTR, pass in the physical interrupt number IRQ, and after the correct return, a SYSINTR will be generated. The function OALIntrRequestSysIntr() finally completes the dynamic conversion. The mapping relationship between IRQ and SYSINTR is implemented in the file C:\WINCE600\PLATFORM\COMMON\SRC\COMMON\INTR\BASE\map.c.
The typical process of using interrupts in a driver is as follows:
1. Initialize GPIO and corresponding interrupt registers, and configure the interrupt working mode.
2. Create a SYSINTR corresponding to the IRQ and call the function KernelIoControl().
3. Create an event and associate it with SYSINTR by calling the function CreateEvent().
4. Create a thread, wait for the created event in the thread, and call the function WaitForSingleObject().
5. After the processing is completed, the kernel is notified that the interrupt processing is completed and the function InterruptDone() is called.
The OAL layer has the following functions related to interrupts:
OALIntrInit(): Initializes the interrupt register and the corresponding GPIO, and can establish a static mapping relationship from IRQ to SYSINTR.
OALIntrRequestIrqs(): Get the IRQ number of the device, such as getting the IRQ corresponding to the device through the IO Address.
OALIntrEnableIrqs(): Enables interrupt sources, mainly clearing interrupt mask registers and interrupt pending registers.
OALIntrDisableIrqs(): turns off the interrupt source and masks the interrupt source by setting the corresponding bit of the interrupt mask register.
OALIntrDoneIrqs(): Clears the interrupt mask register and interrupt pending register so that the MCU can handle the next interrupt.
OEMInterruptHandler(): Converts the IRQ number to SYSINTR, and the kernel's interrupt service routine will set a specific event based on this value.
The work related to interrupts in the kernel mainly includes the following parts:
1. Define the exception handling function, and its implementation file is C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\armtrap.s.
2. Create an interrupt vector table. The implementation file is C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\exvector.s
3. The initialization of the interrupt vector is actually in the file C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\mdarm.c. The code in it shows that the interrupt vector table of WinCE is at the high end (0xffff0000).
|