Summary of UCOS-II interrupt and clock problems (in the x86 example of ucos2.25)

Source: Internet
Author: User

In the past two days to see UCOS-II, UCOS interrupt and clock issues to make a summary, with the x86 ucos2.25 example, "embedded real-time operating system uCOS-II Principle and Application" as the basis, I believe it is helpful to netizens. If you do not understand it correctly, please correct it:

UCOS-II is a preemptible, real-time operating system, which is the core.

1. The UCOS system supports task-level task scheduling and interrupt-level task scheduling: task-level task scheduling is often called automatically in the following code,

Void main ()

{

Osinit ();

Ostaskcreate ();

Ostaskcreate ();

.......

Osstart ();


}

When ostaskcreate is executed, the queue with a higher priority is changed to the ready state. At the same time, the OS _core.c scheduler onsched () is used for Task Scheduling (on_task_sw macro is called internally, the macro is int 0x80 for software interruption and calls the osctxsw to be implemented in OS _cpu_a.asm (osctxsw is a macro call that usually contains Soft Interrupt commands and switching is completed by interrupt-level code )). Onsched only calls tasks with the highest priority. You can release CPU resources by using functions of the Process Synchronization class to achieve parallel task execution and communication, these functions include functions that change the task status and priority (ostasksuspend,
Ostaskresume, ostaskchangeprio, ostaskdel, ostimedly, ostimedlyhmsm. These functions involve task State migration, as shown in the figure below), semaphores, message queues, and mutex semaphores (used to prevent task priority inversion, it is very important to open another topic ).



Sleep state:In Rom or RAM, one of the following two functions must be called for UCOS: ostaskcreate or ostaskcreateext. After the call, the starting address of the UCOS task, priority, and stack space used.

 
Readiness:After a task is created, it enters the ready state. If a new task is created by the task and has a higher priority, the CPU usage right is immediately obtained for the new task. Use ostaskdel to return a task to the sleep state.

 
Running status:You can call osstart to start multiple tasks. This function runs the tasks with the highest priority in your initialization code.

 
Waiting state:A running task uses two functions to delay itself into the waiting state. Ostimedly or ostimedlyhmsm. These two functions will immediately execute a forced task switchover to run the next task with the highest priority and in the ready state. When the delay is reached, the system service function ostimetick will make the waiting task ready. If a running task does not take place when osflagpend, ossempend, osmutexpend, osmboxpend, or osqpend is called, the task enters the waiting state, and the highest priority ready state task enters the running state. When the waiting event occurs or the waiting time-out occurs, the task enters the ready state from the waiting state.

 
Service Interruption status:A running task can be interrupted. The interrupted task enters the interrupted service state. The task is suspended in response to the interruption. The interrupt service subprogram may report multiple events, so that the task with higher priority enters the ready state. When the interruption is returned, the priority is determined again, run the task with the highest priority. If a task with the highest priority is executed first, the task with the highest priority will be returned to the task with the suspension.


2. The following focuses on the scheduling of interrupted tasks:

When a task is running and the interrupted service program is executed, UCOS should look for ready tasks in the task list (these tasks may be called to wait for resources or to call functions such as ostimedly to enter the waiting status. When the resources already exist or the ostimedlg time has timed out ), find the task execution with the highest priority. Therefore, you need to add the corresponding code to the interrupt processing function. UCOS generally does not provide the interrupt registration function. The code to be implemented by the interrupt service program is described as follows:

Void isr_task ()

{

Save all CPU registers. (1)
Call osintenter or osintnesting to add 1 directly; (2)
Execute user code to interrupt the service; (3)
Call osintexit (); (4)

}

3. The principles and applications of the embedded real-time operating system uCOS-II contains a lot of such code as (1) (2) and (3) as seen elsewhere:


(1) pc_vectset (0x08, ostickisr); // install the clock service program to complete the time-out process for executing functions such as ostimedly in each task.

(2) pc_settickrate (OS _ticks_per_sec); // set the clock frequency. You need to write the assembler program based on the CPU to initialize the registers of the timer.

(3) pc_vectset (0x80, osctxsw); // The Task Switching during software interruption. Because osctxsw is an important operation to execute registers, it is often used to enter the privileged mode of the software interruption mode.


(1): I tracked pc_vectset (0x08, ostickisr) and found that this function is:

Void pc_vectset (int8u vect, void (* ISR) (void ))
{
# If OS _critical_method = 3/* allocate storage for CPU Status Register */
OS _cpu_sr cpu_sr;
# Endif
Int16u * pvect;


Pvect = (int16u *) mk_fp (0x0000, vect * 4);/* point into IVT at desired vector location */
OS _enter_critical ();
* Pvect ++ = (int16u) fp_off (ISR);/* store ISR offset */
* Pvect = (int16u) fp_seg (ISR);/* store ISR segment */
OS _exit_critical ();
}

After analysis, this function is only applicable to 80x86 CPUs, because 8*4 = 32, which is exactly the interrupt vector entry address of 80x86 timer 0, different from arm, after the arm jump, the command is executed here, while x86 is the command that executes the 32-bit value pointing to the address. Therefore, this function is not suitable for other CPUs and needs to be changed if it is to be used.

In addition, during the migration of ostickisr, it is generally required to use assembly in OS _cpu_a.asm based on different CPUs. The main functions of ostickisr are as follows:

Void ostickisr (void)

{

Save all CPU registers. (1)
Call osintenter or osintnesting to add 1 directly; (2)

If (osintnesting = 1)

{

Ostcbcur-> osstkptr = sp; // Save the stack pointer in task TCB (3)

}

Call ontimetick (); call the beat processing function. This function has been implemented in OS _core.c and does not need to be implemented by yourself (Note: all source programs in the same level directory as OS _core.c are irrelevant to the CPU ), the cycle processing function automatically completes (1) ostime ++; (2) traversing all the control blocks in the task control block linked list, reducing ostcbdly used to store the task Latency by 1 If ostcbdly
= 0 wake up waiting threads such as suspend and convert them to ready state (4)
Call osintexit (); (4)
Recover all CPU registers. (5)
Execution of the interrupted return command; (6)

}

In OS _core.c, The ontimetick function has the following code:


Void ostimetick (void)
{
# If OS _critical_method = 3/* allocate storage for CPU Status Register */
OS _cpu_sr cpu_sr;
# Endif
OS _tcb * ptcb;

Ostimetickhook (); // defined in OS _cpu_c.c. This file is not in the built-in directory of the source. You need to create a hook function by yourself.
....

}

You can define the hook function in the uCOS-II \ ix86l \ bc45 \ OS _cpu_s.c file as follows.

# If OS _cpu_hooks_en> 0
Void ostimetickhook (void)
{
}
# Endif

(2): pc_settickrate (OS _ticks_per_sec); the user sets the clock frequency and needs to write the assembler program based on the CPU to complete the register initialization of the timer.

(3): pc_vectset (0x80, osctxsw); register for task scheduling switching. 80 is the software interruption entry for x86 CPU. If it is arm, it needs to be changed accordingly, at the same time, osctxsw needs to be implemented in OS _cpu.a.asm according to the processor operation register. The tasks completed by osctxsw are ):

<1> Save the PC pointer and psw (program status word) before the current CPU software is interrupted to the stack of the current task control block, stack operation (corresponding to <6> );

<2> store the current CPU register pressure stacks to the stack of the current task control block, and perform stack pressure operations. (Corresponding to <5>)

<3> obtain the task control block with the highest priority in the task chain and copy it to ostcbcur;

<4> assign the task priority to ospriocur;

<5> obtain the CPU register data stored in the stack of ostcbcur during the previous Task switchover and restore it to the corresponding register. In this process, the stack data sequence is opposite to that in the 2>, and corresponds

<6> interrupt return: Read the PC pointer data stored in the stack of ostcbcur and the program status word psw. In this process, the stack data sequence is opposite to that of 1>.

4. in the UCOS interrupt processing program described in 2, osintexit (OS _core.c) calls will trigger osintctxsw () calls, we generally need to implement the assembly code for specific CPU in OS _cpu_a.asm to complete the following interruption task-level scheduling, which is similar to the above osctxsw, but less (1) (2) action, because the operation has been executed before the interruption.

5. to port a real-time operating system, the clock involved in pc_vectset (0x08, ostickisr) and pc_settickrate (OS _ticks_per_sec) described in 3 must be implemented based on the CPU, including the settings of the clock source and interrupt-related registers in pc_settickrate, pc_vectset is implemented in C language for different CPUs. Here we can create a general interrupt registration function, of course, to compile it in the pilot program. s can also be done, but it is quite troublesome. In addition, the specific implementation of ostickisr is described above. To complete task-level scheduling, you must implement the on_task_sw macro (defined in OS _cpu.h by default). Generally, the compilation code of osctxsw in OS _cpu_a.asm is implemented by means of software interruption. If not, get rid of the Code in the corresponding place. In order to implement hardware interrupt-level scheduling, all parts of the interrupt processing program must follow
Void isr_task (). At the same time, you need to add the common osintctwsw assembly code in OS _cpu.asm.

6. Therefore, to port a simple UCOS, You need to implement it in OS _cpu_a.asm:

<1> osctxsw ()


<2> osintctxsw ()


<3> ostickisr () and clock initialization for this function


<4> osstarthighrdy; This section is not introduced. It is mainly called in the osstart function and should implement the following functions:

(1): Disable IRQ and FIQ interruption.

(2): Call ostaskswhook (), which is a hook function and is generally empty. You can add content as needed.

(4): Set the osrunning flag to 1. Osrunning is an identifier that has been started by the UCOS system. It is set to 1 when osstart in UCOS is called.

(5): SP points to the stack of the highest priority task.

(6): Save the content of the top priority task stack to the Register.

(7): Start the task with the highest priority.

<4> in other places, such as OS _cpu_c.cOstaskstkinitFunction to complete the stack initialization function of the task; similar;

OS _stk * ostaskstkinit (void (* task) (void * PD), void * pdata, OS _stk * ptos, int16u OPT)
{
Int16u * STK;

Opt = OPT;/* 'opt' is not used, prevent warning */
STK = (int16u *) ptos;/* load Stack pointer */
* STK -- = (int16u) fp_seg (pdata);/* simulate call to function with argument */
* STK -- = (int16u) fp_off (pdata );
* STK -- = (int16u) fp_seg (task );
* STK -- = (int16u) fp_off (task );
* STK -- = (int16u) 0x0202;/* Sw = interrupts enabled */
* STK -- = (int16u) fp_seg (task);/* put pointer to task on top of stack */
* STK -- = (int16u) fp_off (task );
* STK -- = (int16u) 0 xaaaa;/* AX = 0 xaaaa */
* STK -- = (int16u) 0 xcccc;/* Cx = 0 xcccc */
* STK -- = (int16u) 0 xdddd;/* dx = 0 xdddd */
* STK -- = (int16u) 0 xbbbb;/* BX = 0 xbbbb */
* STK -- = (int16u) 0x0000;/* sp = 0x0000 */
* STK -- = (int16u) 0x1111;/* BP = 0x1111 */
* STK -- = (int16u) 0x2222;/* SI = 0x2222 */
* STK -- = (int16u) 0x3333;/* di = 0x3333 */
* STK -- = (int16u) 0x4444;/* elasticsearch = 0x4444 */
* STK = _ DS;/* DS = current value of DS */
Return (OS _stk *) STK );
}

7. The above mainly involves the interrupt part, and some functions need to be implemented, such as OS _enter_critical () in the x86 example ()

On_exit_critical () Implementation of open interruption and Guanzhong disconnection





Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.