- •Preface
- •Introduction
- •1.01 INCLUDES.H
- •1.02 Compiler Independent Data Types
- •1.03 Global Variables
- •1.04 OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL()
- •1.05 PC Based Services
- •1.05.01 PC Based Services, Character Based Display
- •1.05.02 PC Based Services, Elapsed Time Measurement
- •1.05.03 PC Based Services, Miscellaneous
- •1.07 Example #1
- •1.08 Example #2
- •1.09 Example #3
- •2.00 Foreground/Background Systems
- •2.01 Critical Section of Code
- •2.02 Resource
- •2.03 Shared Resource
- •2.04 Multitasking
- •2.05 Task
- •2.06 Context Switch (or Task Switch)
- •2.07 Kernel
- •2.08 Scheduler
- •2.09 Non-Preemptive Kernel
- •2.10 Preemptive Kernel
- •2.11 Reentrancy
- •2.12 Round Robin Scheduling
- •2.13 Task Priority
- •2.14 Static Priorities
- •2.15 Dynamic Priorities
- •2.16 Priority Inversions
- •2.17 Assigning Task Priorities
- •2.19 Mutual Exclusion
- •2.20 Deadlock (or Deadly Embrace)
- •2.21 Synchronization
- •2.22 Event Flags
- •2.23 Intertask Communication
- •2.24 Message Mailboxes
- •2.25 Message Queues
- •2.26 Interrupts
- •2.27 Interrupt Latency
- •2.28 Interrupt Response
- •2.29 Interrupt Recovery
- •2.30 Interrupt Latency, Response, and Recovery
- •2.31 ISR Processing Time
- •2.32 Non-Maskable Interrupts (NMIs)
- •2.33 Clock Tick
- •2.34 Memory Requirements
- •2.35 Advantages and Disadvantages of Real-Time Kernels
- •2.36 Real-Time Systems Summary
- •3.00 Critical Sections
- •3.01 Tasks
- •3.02 Task States
- •3.03 Task Control Blocks (OS_TCBs)
- •3.04 Ready List
- •3.05 Task Scheduling
- •3.06 Locking and Unlocking the Scheduler
- •3.07 Idle Task
- •3.08 Statistics Task
- •3.10 Clock Tick
- •3.14 OSEvent???() functions
- •4.00 Creating a Task, OSTaskCreate()
- •4.01 Creating a Task, OSTaskCreateExt()
- •4.02 Task Stacks
- •4.03 Stack Checking, OSTaskStkChk()
- •4.04 Deleting a Task, OSTaskDel()
- •4.05 Requesting to delete a task, OSTaskDelReq()
- •4.06 Changing a Task’s Priority, OSTaskChangePrio()
- •4.07 Suspending a Task, OSTaskSuspend()
- •4.08 Resuming a Task, OSTaskResume()
- •4.09 Getting Information about a Task, OSTaskQuery()
- •5.00 Delaying a task, OSTimeDly()
- •5.01 Delaying a task, OSTimeDlyHMSM()
- •5.02 Resuming a delayed task, OSTimeDlyResume()
- •5.03 System time, OSTimeGet() and OSTimeSet()
- •6.00 Event Control Blocks
- •6.01 Initializing an ECB, OSEventWaitListInit()
- •6.02 Making a task ready, OSEventTaskRdy()
- •6.03 Making a task wait for an event, OSEventTaskWait()
- •6.04 Making a task ready because of a timeout, OSEventTO()
- •6.05 Semaphores
- •6.06 Message Mailboxes
- •6.07 Message Queues
- •7.00 Memory Control Blocks
- •7.01 Creating a partition, OSMemCreate()
- •7.02 Obtaining a memory block, OSMemGet()
- •7.03 Returning a memory block, OSMemPut()
- •7.04 Obtaining status about memory partition, OSMemQuery()
- •7.05 Using memory partitions
- •7.06 Waiting for memory blocks from a partition
- •8.00 Development Tools
- •8.01 Directories and Files
- •8.02 INCLUDES.H
- •9.00 Development Tools
- •9.01 Directories and Files
- •9.02 INCLUDES.H
- •9.06 Memory requirements
- •9.07 Execution times
- •10.00 Directories and Files
- •10.01 INCLUDES.H
- •10.02.01 OS_CPU.H, Compiler specific data types
- •10.02.02 OS_CPU.H, OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL()
- •10.02.03 OS_CPU.H, OS_STK_GROWTH
- •10.02.04 OS_CPU.H, OS_TASK_SW()
- •10.03.01 OS_CPU_A.ASM, OSStartHighRdy()
- •10.03.02 OS_CPU_A.ASM, OSCtxSw()
- •10.03.03 OS_CPU_A.ASM, OSIntCtxSw()
- •10.03.04 OS_CPU_A.ASM, OSTickISR()
- •10.04.01 OS_CPU_C.C, OSTaskStkInit()
- •10.04.02 OS_CPU_C.C, OSTaskCreateHook()
- •10.04.03 OS_CPU_C.C, OSTaskDelHook()
- •10.04.04 OS_CPU_C.C, OSTaskSwHook()
- •10.04.05 OS_CPU_C.C, OSTaskStatHook()
- •10.04.06 OS_CPU_C.C, OSTimeTickHook()
- •10.05 Summary
- •OSInit()
- •OSIntEnter()
- •OSIntExit()
- •OSMboxAccept()
- •OSMboxCreate()
- •OSMboxPend()
- •OSMboxPost()
- •OSMboxQuery()
- •OSMemCreate()
- •OSMemGet()
- •OSMemPut()
- •OSMemQuery()
- •OSQAccept()
- •OSQCreate()
- •OSQFlush()
- •OSQPend()
- •OSQPost()
- •OSQPostFront()
- •OSQQuery()
- •OSSchedLock()
- •OSSchedUnlock()
- •OSSemAccept()
- •OSSemCreate()
- •OSSemPend()
- •OSSemPost()
- •OSSemQuery()
- •OSStart()
- •OSStatInit()
- •OSTaskChangePrio()
- •OSTaskCreate()
- •OSTaskCreateExt()
- •OSTaskDel()
- •OSTaskDelReq()
- •OSTaskResume()
- •OSTaskStkChk()
- •OSTaskSuspend()
- •OSTaskQuery()
- •OSTimeDly()
- •OSTimeDlyHMSM()
- •OSTimeDlyResume()
- •OSTimeGet()
- •OSTimeSet()
- •OSTimeTick()
- •OSVersion()
OSCtxSw: |
|
|
Save the |
stack pointer at OSTCBCur->OSTCBStkPtr; |
|
Call OSTaskSwHook(); |
(1) |
|
OSTCBCur |
= OSTCBHighRdy; |
|
OSPrioCur = OSPrioHighRdy; |
(2) |
|
Load the |
processor stack pointer with OSTCBHighRdy->OSTCBStkPtr; |
|
POP all the processor registers from the stack; |
|
|
Execute a Return from Interrupt instruction; |
|
|
Listing 10.8, Pseudo-code for OSIntCtxSw()
10.03.04 OS_CPU_A.ASM, OSTickISR()
The code for this function in µC/ OS-II is identical to µC/OS and thus shouldn’t be altered.
10.04OS_CPU_C.C
A µC/OS-II port requires that you write six fairly simple C functions:
OSTaskStkInit()
OSTaskCreateHook()
OSTaskDelHook()
OSTaskSwHook()
OSTaskStatHook()
OSTimeTickHook()
The o nly function that is actually necessary is OSTaskStkInit(). The other five functions MUST be declared but don’t need to contain any code inside them.
10.04.01 OS_CPU_C.C, OSTaskStkInit()
In µC/OS,OSTaskCreate() was considered a processor specific function. It turned out that only a portion of OSTaskCreate() was actually processor specific. This portion has been extracted out of OSTaskCreate() and placed in a new function called OSTaskStkInit().
OSTaskStkInit() is only responsible for setting up the task’s stack to look as if an interrupt just occurred and
all the processor registers were pushed onto the task’s stack. To give you an example, listing 10.9 shows the µC/OS code for OSTaskCreate() for the Intel 80x86 real-mode, large model. Listing 10.10 shows the code for OSTaskStkInit() for the same processor but for µC/OS-II. As you can see by comparing the two listings, lines L10.9(2) through L10.9(18) have basically been extracted from OSTaskCreate() and placed in OSTaskStkInit(). In other words, everything after OS_EXIT_CRITICAL() L10.9(1) and calling
OSTCBInit() L10.9(19) has been moved to OSTaskStkInit().
You will notice that the code for µC/OS-II uses the new data types (see section 10.02.01, OS_CPU.H, Compiler specific data types). Also, instead of initializing all the processor registers to0x0000, I decided to initialize them with a value
that would make debugging a little easier. You should note that the initial value of a register when a task is created is not critical.
UBYTE OSTaskCreate(void (*task)(void *pd), void *pdata, void *pstk, UBYTE p)
{
UWORD OS_FAR *stk; |
|
|
UBYTE |
err; |
|
OS_ENTER_CRITICAL(); |
|
|
if (OSTCBPrioTbl[p] == (OS_TCB *)0) { |
|
|
OSTCBPrioTbl[p] = (OS_TCB *)1; |
|
|
OS_EXIT_CRITICAL(); |
(1) |
|
stk |
= (UWORD OS_FAR *)pstk; |
(2) |
*--stk = (UWORD)FP_OFF(pdata); |
(3) |
|
*--stk = (UWORD)FP_SEG(task); |
(4) |
|
*--stk = (UWORD)FP_OFF(task); |
(5) |
|
*--stk = (UWORD)0x0202; |
(6) |
|
*--stk = (UWORD)FP_SEG(task); |
(7) |
|
*--stk = (UWORD)FP_OFF(task); |
(8) |
|
*--stk = (UWORD)0x0000; |
(9) |
|
*--stk = (UWORD)0x0000; |
(10) |
|
*--stk = (UWORD)0x0000; |
(11) |
|
*--stk = (UWORD)0x0000; |
(12) |
|
*--stk = (UWORD)0x0000; |
(13) |
|
*--stk = (UWORD)0x0000; |
(14) |
|
*--stk = (UWORD)0x0000; |
(15) |
|
*--stk = (UWORD)0x0000; |
(16) |
|
*--stk = (UWORD)0x0000; |
(17) |
|
*--stk = _DS; |
(18) |
|
err |
= OSTCBInit(p, (void far *)stk); (19) |
|
if (err == OS_NO_ERR) { if (OSRunning) {
OSSched();
}
} else {
OSTCBPrioTbl[p] = (OS_TCB *)0;
}
return (err); } else {
OS_EXIT_CRITICAL(); return (OS_PRIO_EXIST);
}
}
Listing 10.9, OSTaskCreate() for µC/OS
void *OSTaskStkInit (void (*task)(void *pd), void *pdata, void *ptos, INT16U opt)
{
INT16U *stk;
opt |
= opt; |
stk |
= (INT16U *)ptos; |
*stk-- = (INT16U)FP_SEG(pdata); |
|
*stk-- = (INT16U)FP_OFF(pdata); *stk-- = (INT16U)FP_SEG(task); *stk-- = (INT16U)FP_OFF(task); *stk-- = (INT16U)0x0202; *stk-- = (INT16U)FP_SEG(task); *stk-- = (INT16U)FP_OFF(task); *stk-- = (INT16U)0xAAAA; *stk-- = (INT16U)0xCCCC; *stk-- = (INT16U)0xDDDD; *stk-- = (INT16U)0xBBBB; *stk-- = (INT16U)0x0000; *stk-- = (INT16U)0x1111; *stk-- = (INT16U)0x2222; *stk-- = (INT16U)0x3333; *stk-- = (INT16U)0x4444;
*stk = _DS;
return ((void *)stk);
}
Listing 10.10, OSTaskStkInit() for µC/OS-II
10.04.02 OS_CPU_C.C, OSTaskCreateHook()
OSTaskCreateHook() is a function that did not exist in µC/OS. If you are simply migrating from µC/OS to µC/OS-II then you can simply declare an empty function as shown in listing 10.11. You should note that if I didn’t assign ptcb to ptcb then some compilers would generate a warning indicating that the argument ptcb is not used.
#if OS_CPU_HOOKS_EN OSTaskCreateHook(OS_TCB *ptcb)
{
ptcb = ptcb;
}
#endif
Listing 10.11, OSTaskCreateHook() for µC /OS-II
You should also wrap the function declaration with the conditional compilation directive. The code for
OSTaskCreateHook() is generated only if OS_CPU_HOOKS_EN is set to 1 in OS_CFG.H. This
allows the user of your port to redefine all the hook functions in a different file.
10.04.03 OS_CPU_C.C, OSTaskDelHook()
OSTaskDelHook() is a function that did not exist in µC/OS. Again, if you are migrating from µC/OS to µC/OS-II then you can simply declare an empty function as shown in listing 10.12. You should note that if I didn’t assign ptcb to ptcb then some compilers would generate a warning indicating that the argument ptcb is not used.
#if OS_CPU_HOOKS_EN OSTaskDelHook(OS_TCB *ptcb)
{
ptcb = ptcb;
}
#endif
Listing 10.12, OSTaskDelHook() for µC/OS-II
You should also wrap the function declaration with the conditional compilation directive. The code for
OSTaskDelHook() is generated only if OS_CPU_HOOKS_EN is set to 1 in OS_CFG.H. This allows
the user of your port to redefine all the hook functions in a different file.
10.04.04 OS_CPU_C.C, OSTaskSwHook()
OSTaskSwHook()is also function that did not exist in µC/OS. If you are migrating from µC/OS to µC/OS-II then you can simply declare an empty function as shown in listing 10.13.
#if OS_CPU_HOOKS_EN OSTaskSwHook(void)
{
}
#endif
Listing 10.13, OSTaskSwHook() for µC/OS-II
You should also wrap the function declaration with the conditional compilation directive. The code for
OSTaskSwHook() is generated only if OS_CPU_HOOKS_EN is set to 1 in OS_CFG.H.
10.04.05 OS_CPU_C.C, OSTaskStatHook()
OSTaskStatHook() is also function that did not exist in µC/OS. You can simply declare an empty function as shown in listing 10.14.
