
The basic macro, the kernel consists of is _TASK_SWITCH(5).It is actually the dispatcher - the low level scheduler - which decides what is the next task in the system to run and then carries out the task switch to that task. Generally the selection of the task is done on a priority basis. The USER land code is separated into two levels at which the Task's code executes for this kernel implementation:
- PASSIVE LEVEL(7) - this is the usual level at which a normal user task executes. All CPU resources "belong" to the task during its time quantum. Make sure user level API is called in this level.
- DEVICE LEVEL(6) - the high level at which the deferred interrupt processing happens. A task could transition from PASSIVE to DEVICE and backwards as many times as it is needed in order to provide best real time processing conditions. It is the interrupt dispatcher which elevates the Tasks's level to DEVICE one as a result of a device interrupt.
Physically the dispatcher consists of the following:
- a macro which executes an implementation specific algorithm to decide what task will be the next to run when system control exits the kernel. It is activated on each tick of the scheduling timer or when a task relinguishes its time quantum.
- a collection of data structures which contain all the information that the kernel needs to know about a task (these structures are known as the task control blocks or the task descriptors).
- save the tasks context on its stack.This means that all CPU registers and current stack pointer are preserved.
- search the tasks marked as high priority tasks in a round robin fashion. Keep servicing high priority tasks until all go back to normal level
- search the next normal level task to execute if a higher priority task is not found. There is always one task that is elligable to execute - system zero task.
- restore the state of the selected task by localizing its stack.
Each task is given a small amount of time to execute its code called quantum. During that time it has all the resources at its disposal so a poorly designed task could crash the system.
- _REGISTER_TASK - task register macro. All tasks should be predefined! The size and starting position of the task stack is calculated.
- _YIELD_TASK - relinquish the task quantum by activating the dispatcher.
- _SLEEP_TASK - sleep the task for a certain period of time.
- _SUSPEND_TASK - make the task not scheduleable. The dispatcher completely ignores the task.
- _RESUME_TASK - make the task scheduleable.
- _START_EXECUTIVE_MODE - enter critical section implementation. The disabling of interrupts in the task will protect the shared resource from corruption but it leads to undesirable side effects, namely that interrupts can be disabled for considerable lengths of time depending on the nature of the manipulations on the shared data structure. In a real time system this could lead to performance problems due to the disruption of the precision of the timing. Use for a short amount of time.
- _END_EXECUTIVE_MODE - leave critical section - enable interrupts
- _EVENT_SET,_EVENT_CLEAR,_EVENT_WAIT - basic event structure. Used for inter-tasks event notification.
- _MUTEX_WAIT,_MUTEX_RELEASE - basic mutex structure. Used for resource integrity protection. Only one task can access certain resources.
- _BARRIER_WAIT - basic barrier.A barrier is a coordination mechanism that forces chosen tasks to wait until each one of them has reached a certain point in its task code. Simple application of the barrier is setting one at the end of each Acorn kernel task initialization segment thus garanteeing no task will proceed until all of the tasks has processed the initialization segment.
- _START_EXECUTIVE_MODE - enter critical section implementation. The disabling of interrupts in the task will protect the shared resource from corruption but it leads to undesirable side effects, namely that interrupts can be disabled for considerable lengths of time depending on the nature of the manipulations on the shared data structure. In a real time system this could lead to performance problems due to the disruption of the precision of the timing. Use for a short amount of time.
- PRE_INTERRUPT,POST_INTERRUPT - wrap each interrupt handler with this code. It preserves the CPU STATUS register.
- _INTERRUPT_DISPATCH - interrupt dispatch is used to implement the so called differed interrupt processing. It is desirable to spend as little time in interrupt handler as possible so the very interrupt processing is left for a user task that will execute at a high privilege level.
- _INTERRUPT_WAIT,_INTERRUPT_END - user task marked as interrupt processing task.
- _DISPATCH_TO_EXTENTION - the interrupt processing code is injected into the interrupted task by the interrupt.
There is one TCB(task control block) per task which consists of 4 bytes
- 2 bytes - keeps task stack pointer(LSB,MSB).
- 1 byte - task status byte.Task priority bit,schedulability bit ...
- 1 byte - sleep time out in units.
First solution
By Sergei on Wed Jan 19 08:31:15 UTC 2011
Actually there is a solution if i properly understood what you want.
Right after you send a character invoke SLEEP_TASK.You can tweak the Timer1 interval which is responsible for SLEEP_TASK calculations.Choose an interrupt close to 50ms and call SLEEP_TASK 1.
Now when the sleep interval is over you can check a global variable if the receive interrupt was invoked.
If you can't solve your problem please Contact me(see the contact area for my email).
We may eventually design a wait event with timeout macro!
We my also publish the solution or a snipet of it in the Application area
timer
By Anonymous on Tue Jan 18 22:47:57 UTC 2011
i am doing some serial programming using acorn kernel.
The program is interrupt driven and written in asm.
I would like to have a time out function so if the return data is not received in 50ms
i can try to resend or cause an error, and if the data is received bypass the 50ms timer wait.
since there it no timer
function in acorn i am not sure how to do this can you please help.