Sender: gdtyy (gdtyy), email area: embedded
Subject: Part 3: Operation interruption of eCos
Mailing station: shuimu community (Mon Jun 25 23:30:25 2007), within the station
***********************
* 3. Interrupt operations on ECOs *
***********************
Asdjf@163.com www.armecos.com
In the end, what is better than what we write about ECOs Interrupt Processing?
If we write our own interrupt processing program, we recommend that you use the hard
Each film must be rewritten with ISR. For different architectures (such as arm, MIPS, x86, PowerPC ......),
Variants (different models of the same architecture) and hardware platforms (Development Boards of different companies) have different interrupt mechanisms.
It takes a lot of time to get entangled in subtle differences. The mood is not pleasant, and the code reuse is not strong.
ECos adopts a general Interrupt Processing Mechanism to abstract the essential features of interrupt, and uses the Hardware Abstraction Layer HAL
Smooth the implementation details of various interrupt hardware systems. Programmers only need to program General virtual interrupt systems abstracted from ECOs.
You can.
So how does ECOs "abstract" interruptions? For the moment, we will talk about the interrupt response time.
If you have written an assembly interrupt handler or used UCOS, you will not be unfamiliar with the ISR implementation method.
, First fill in the interrupt vector table, and then write the ISR processing program. Once the interrupt occurs, find the ISR function address through the vector table and jump
Where to execute.
The virtual interrupt System of eCos is ISR + DSR, and of course Linux is ISR + tasklet. Obviously, the interruption is divided
Two parts, one is to interrupt the service program ISR, Guanzhong interrupted execution, as short as possible, many kernel functions are not used; the other
One part is the delay service program DSR, which is not interrupted and can be processed in a relatively time-consuming manner. It can use more kernel letters than ISR.
Number.
Why? What are the benefits?
As we know, interruptions may occur asynchronously at any time. The Interrupt Processing Program and the "concurrent" execution of the interrupted program
This will cause many problems, such as re-entry, synchronization, critical resource protection, and so on. The site will be saved when the interruption occurs, and the site will be restored when the return result is returned,
Therefore, it will not affect the Application threads that are interrupted without critical resources. However, if the interrupted thread is executing the kernel call
The kernel data may be damaged because kernel functions require atomic operations and cannot be interrupted. How to avoid this problem
One is to disable interruption in kernel functions in the critical section. For example, UCOS kernel functions are often interrupted. However
This atomic operation may take quite a long time and has a negative impact on the interrupt response time. Performance Improvement
Instead of using the switch interrupt method to avoid conflicts, we use locks, semaphores, and other methods to implement kernel data protection. This
In this example, we agree to limit the use of the vast majority of insecure kernel APIs in ISR, and the kernel APIs will not be frequently switched or interrupted.
To lock and semaphores. When our ISR can be written very short and the kernel API will not be disconnected, the response time will be interrupted.
It will become smaller, and RTOS's real-time indicators will be better viewed. Therefore, the ECOS interrupt response using ISR + DSR is faster than that of UCOS.
Maybe you are not quite familiar with this method of dividing ISR into two halves. It doesn't matter. We will provide 10 thousand interruptions below.
Process the template. You only need to apply the template. Focus on handling interrupt events, so you don't have to worry about it.
Want to see how interruptions are abstracted? Let's take a look at and talk about it with a single question.
The general idea is: Create an interrupt handle, hook interruption, enable interruption, and call
ISR, and then call the DSR (optional ). It involves interrupt response, interrupt clearing, External Interrupt clearing, and interrupt trigger mode configuration.
Concepts such as disable/enable, create/delete, and disconnect/unmount.
Question: Use the key1 button to control the buzzer. Effective at the low level, press the voice, then press stop, then press and voice,
Cycle. (Don't forget to install the jumper before trying again)
The source code is as follows. Multi-task Programming I/O register read/write I/O registers
Now let's take a look at interrupt programming.
When creating the TASKA thread, I passed a parameter cygnum_hal_interrupt_ext3, which is the external parameter of key1.
Interrupt number, no special purpose, just want to use thread parameters to store my private data (priv_data), always find
Let's put my own things here. Cygnum_hal_interrupt_ext3 indicates that
Cyg's standard number is located at the hardware abstraction layer-interrupt purpose-External Interrupt 3.
In thread TASKA, the pin is first set. Although ECOs abstracts the interrupt, the interrupt is closely related to the hardware after all,
For pin multiplexing or low power consumption, multiple functions correspond to the same pin/multiple pins correspond to the same
A function must be selected as needed. For example, key1 on the smartarm2200 platform uses eint3.
Disconnected. This interrupt is reused by listen 9, listen 20, and interrupt 30. You need to shield listen 9 (NIC 8019 interrupted) and listen 30 (zlg7290 interrupted)
) To avoid conflicts. If you are interested, you can try to allow the eint3 corresponding to limit 9 and Limit 30. (Low Level
When triggered, the phase of the interrupt signal line and the phase or of the interrupt signal line when the high level is triggered .)
Set the beep control pin direction to the output to prevent beep sound from the beginning. The default output for power-on is low.
Start with a tweet, and the voice is clearly turned off here.
There are four types of Interrupt triggering Methods: high level, low level, rising edge, and falling edge. Use ECOs
The cyg_interrupt_configure function sets the interrupt trigger mode.
Cyg_interrupt_configure (Interrupt number, level/edge selection, Upper/lower selection)
Where:
Level/edge selection: 0 --- level; 1 --- edge
Upper/lower options: 0 --- lower; 1 --- higher
Set this parameter to (priv_data,), that is, the low-level trigger mode. Priv_data is passed by thread parameters.
The eint3 interrupt number.
It is much easier to trigger the configuration function with interruption than to directly write The Emode!
Edge-triggered interruptions do not need to clear the interrupt source, but may cause loss of interruptions. Level-triggered interruptions need to clear the external interrupt source.
, The interrupt indication is not lost, and the same root disconnection can be shared.
Clear the priv_data (eint3) interrupt flag, equivalent to 1 <3. Put this sentence
After cyg_interrupt_configure, it seems that changing Emode and epolar will affect Eint. It is best to make it clear before use interruption
It is a good habit to clear previous interrupt instructions to avoid Unexpected random events.
The virtual interrupt System of eCos requires that the necessary interrupt processing functions be mounted to the corresponding interrupt number, without having to worry about
Hardware ing details. Multiple interrupt handles can be created, but only one of them can be attached.
Cyg_interrupt_create (
Interrupt number,
Interrupt priority,
Passed interrupt parameters,
ISR function,
DSR function,
Returned interrupt handle,
Variable space for storing kernel data related to the interrupt );
Cyg_interrupt_attach (interrupt handle );
After an interrupt handle is created and mounted, the interrupt service program establishes a connection with the interrupt vector.
Execute the vector service program VSR, then call the registered interrupt service program ISR, and then execute the delay service program DSR. To
Now, the interrupt is ready.
The newly attached interrupt is blocked. You need to call the unblocking function to start the operation. In this case
After the registration is interrupted, you can continue to prepare other tasks that need to be done.
Disturbance. If they are all ready, they can be unblocked to make the interruption work normally.
Cyg_interrupt_unmask (Interrupt number); // enable interruption
"While (1);" is to avoid exiting the TASKA thread. You can try to remove this sentence.
ISR programs are very short and do not call most kernel functions. However, it is necessary to interrupt responses and return values.
Cyg_interrupt_acknowledge (Interrupt number );
An interrupt response should be executed at the end of ISR (the write value is generally 0) to update the priority hardware.
. If no response is received, the hardware does not work normally and must be answered in ISR.
If ISR returns cyg_isr_handled, DSR is no longer called. If cyg_isr_call_dsr is returned
Call the DSR.
The purpose of blocking interruption here is to avoid re-entry, because I don't want to interrupt nesting, it will mess up data. If no
If conflicting data is allowed to be nested, you do not need to use this statement to block interruptions. Do not use the printf function in ISR.
The DSR executes most of the processing work and can use more kernel functions. The main function of this program is
The anti-Beep control enables the buzzer to switch between audible and non-audible interruptions with key1 keys. Corresponding to the release of interruption shielding
Interrupt shielding in ISR. Now the interrupt has been executed and can cause a new interrupt.
It should be noted that the process of level interruption is slightly cumbersome. Undo the external interrupt source indication first (for example, wait
Key1 press the key to lift/read the blank 8019 Nic output buffer), and then cancel the internal Eint interrupt flag bit (corresponding bit write 1 can be
Clear ). If the internal flag is cleared without removing the external indication first/If the internal flag is not cleared, the internal flag will be in progress repeatedly.
Disconnected until an error occurs. Interested readers can try to comment out"
Hal_write_uint8 (lpc2xxx_syscon_eint, 1 <(priv_data-CYGNUM_HAL_INTERRUPT_EXT0 ));"
Check whether the interruption can be exited or not. Remove the key1 button in while and raise your judgment to see what happens when you press it.
What is the difference.
The above is an explanation of the ECOS virtual interrupt system programming. It can be seen that the ECOS interrupt is more abstract and no longer needed.
Concerning about what Vic, there are a lot of Interrupt registers, and you can apply this template.
If you want to switch to the key1 key for High-Level triggering, just write "cyg_interrupt_configure (priv_data, 0,
1. At this point, when the operation is complete, click stop, and then click again to tweet... the result is correct. Same as DSR
When a low-level trigger occurs, the system exits after the indication of an external interrupt source is invalid. If the signal remains high, the interrupt mark
Keep setting 1.
If you want to change to edge trigger, use the following statement:
Hal_read_uint8 (lpc2xxx_syscon_eint, flag );
While (flag & 1 <(priv_data-CYGNUM_HAL_INTERRUPT_EXT0 ))! = 0)
{
Hal_write_uint8 (lpc2xxx_syscon_eint,
1 <(priv_data-CYGNUM_HAL_INTERRUPT_EXT0 ));
Hal_read_uint8 (lpc2xxx_syscon_eint, flag );
}
Change to the following sentence:
Hal_write_uint8 (lpc2xxx_syscon_eint, 1 <(priv_data-CYGNUM_HAL_INTERRUPT_EXT0)
);
You no longer need to determine the external interrupt source. Edge triggers do not need to clear the external interrupt source, because Edge does not always
Hold. It is necessary to clear the Eint when writing "1". Otherwise, it will be interrupted again and again.
"Cyg_interrupt_configure (priv_data,);" is triggered by the descent edge. Press the key1 key
And then press stop ......
"Cyg_interrupt_configure (priv_data,);" is triggered by the rising edge.
Key1 key, it will ring, and then press lift to stop ......
Using this touch board, It is very convenient to write the interrupt-based 8019 NIC driver, and 8019 interrupt is also used in eint3,
High-level triggering. You can try it if you are interested. (Tip: Change PIN allocation to pinsel0 and pinsel1, which are in ECOs
Dp83902a reference source code)
A lot of people may not use arm or ECOs. It doesn't matter. Here we mainly introduce the programming idea and the essence of interruption.
Abstract, with an idea, the solution to the details is only a matter of time. You can use the interrupt handling ideas here in 2410,
X86, MIPS. If a beginner comes into contact with a large number of hardware details as soon as they come up, it will inevitably be dizzy, and only the trees will disappear.
The forest and ECOs value-added software packages allow you to focus on your ideas and spend the least time to achieve the best results.
The following is the interrupt program source code.
# Include <Cyg/kernel/KAPI. h>
# Include <Cyg/hal/hal_io.h>
# Include <Cyg/hal/plf_io.h>
# Define stack_size 4096
# Define beepcon 0x0000080
Char stack [2] [stack_size];
Static cyg_thread thread_data [2];
Static cyg_handle_t thread_handle [2];
// This ISR is called when the Ethernet interrupt occurs
Static cyg_uint32
Yy_isr (cyg_vector_t vector, cyg_addrword_t data)
{
Int priv_data = (INT) data;
Cyg_interrupt_mask (priv_data); // block the interrupt
Cyg_interrupt_acknowledge (priv_data); // interrupt the response. A write operation should be executed at the end of Isr.
Operation (the write value is generally 0) to update the priority hardware.
Return (cyg_isr_handled | cyg_isr_call_dsr); // run the DSR if ISR returns
If cyg_isr_handled is returned, the DSR is no longer called. If cyg_isr_call_dsr is returned, the DSR is also called.
}
Static void
Yy_dsr (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
Int priv_data = (INT) data;
Int I;
Unsigned char flag;
Hal_read_uint32 (lpc2xxx_gpio_io0set, I );
If (I & beepcon) = 0)
{
Hal_write_uint32 (lpc2xxx_gpio_io0set, beepcon );
}
Else
{
Hal_write_uint32 (lpc2xxx_gpio_io0clr, beepcon );
}
Hal_read_uint8 (lpc2xxx_syscon_eint, flag );
While (flag & 1 <(priv_data-CYGNUM_HAL_INTERRUPT_EXT0 ))! = 0)
{
Hal_write_uint8 (lpc2xxx_syscon_eint,
1 <(priv_data-CYGNUM_HAL_INTERRUPT_EXT0 ));
Hal_read_uint8 (lpc2xxx_syscon_eint, flag );
}
Cyg_interrupt_unmask (priv_data); // unblocks the interruption.
}
Void TASKA (cyg_addrword_t data)
{
Int priv_data = (INT) data;
Cyg_handle_t handle;
Cyg_interrupt intr;
Printf ("IRQ = % d/N", priv_data );
// Pin settings, key1 connected to eint3
Hal_write_uint32 (lpc2xxx_pin_sel0, 0x55500005 );
Hal_write_uint32 (lpc2xxx_pin_sel1, 0x00000300 );
// Set the output to beep
Hal_write_uint32 (lpc2xxx_gpio_io0dir, beepcon );
// Beep is disabled at the beginning, and the default output for power-on is low, resulting in a tweet at the beginning.
Hal_write_uint32 (lpc2xxx_gpio_io0set, beepcon );
// Configure the interrupt trigger mode and low-level trigger
Cyg_interrupt_configure (priv_data, 0, 0 );
// Clear the priv_data (eint3) interrupt flag, which is equivalent to 1 <3. Put this sentence
After cyg_interrupt_configure, it seems that changing Emode and epolar will affect Eint.
Hal_write_uint8 (lpc2xxx_syscon_eint, 1 <(priv_data-CYGNUM_HAL_INTERRUPT_EXT0)
);
// Create a handle
Cyg_interrupt_create (
Priv_data,
0, // priority-unused
(Cyg_addrword_t) priv_data, // data item passed to ISR & DSR
Yy_isr, // ISR
Yy_dsr, // DSR
& Handle, // handle to intr OBJ
& Intr); // space for int OBJ
// Link the interrupt to the interrupt handle
Cyg_interrupt_attach (handle );
// Enable interruption
Cyg_interrupt_unmask (priv_data );
Printf ("starting.../N ");
While (1 );
}
Void
Test (cyg_addrword_t data)
{
Printf ("/n ");
Printf ("/T ******************************/N ");
Printf ("/T * hello! The world. */N ");
Printf ("/T ******************************/n /n ");
Cyg_thread_create (10, // priority-just a number
TASKA, // entry
Cygnum_hal_interrupt_ext3, // entry Parameter
"TASKA", // name
& Stack [1], // Stack
Stack_size, // size
& Thread_handle [1], // handle
& Thread_data [1] // thread Data Structure
);
Cyg_thread_resume (thread_handle [1]); // start it
}
Void
Cyg_start (void)
{
Cyg_thread_create (10, // priority-just a number
Test, // entry
0, // entry Parameter
"Test", // name
& Stack [0], // Stack
Stack_size, // size
& Thread_handle [0], // handle
& Thread_data [0] // thread Data Structure
);
Cyg_thread_resume (thread_handle [0]); // start it
Cyg_scheduler_start ();
}
--
※Source: · Shui Mu community http://newsmth.net · [from: 61.149.56. *]