- •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()
Once INSTALL.BAT has completed, your destination drive will contain the following subdirectories:
\SOFTWARE
The main directory from the root where all software-related files are placed.
\SOFTWARE\BLOCKS
The main directory where all ‘Building Blocks’are located. With µC/OS-II, I included a ‘building block’that handles DOS-type compatible functions that are used by the example code.
\SOFTWARE\BLOCKS\TO
This directory contains the files for the TO utility (see Appendix E, TO). The source file is TO.C and is found in the \SOFTWARE\TO\SOURCE directory. The DOS executable file (TO.EXE) is found in the \SOFTWARE\TO\EXE directory. Note that TO requires a file called TO.TBL which must reside on your root directory. An example of TO.TBL is also found in the \SOFTWARE\TO\EXE directory. You will need to move TO.TBL to the root directory if you are to use TO.EXE.
\SOFTWARE\uCOS-II
The main directory where all µC/OS-II files are located.
\SOFTWARE\uCOS-II\EX1_x86L
This directory contains the source code for EXAMPLE #1 (see section 1.07, Example #1) which is intended to run under DOS (or a DOS window under Windows 95).
\SOFTWARE\uCOS-II\EX2_x86L
This directory contains the source code for EXAMPLE #2 (see section 1.08, Example #2) which is intended to run under DOS (or a DOS window under Windows 95).
\SOFTWARE\uCOS-II\EX3_x86L
This directory contains the source code for EXAMPLE #3 (see section 1.09, Example #3) which is intended to run under DOS (or a DOS window under Windows 95).
\SOFTWARE\uCOS-II\Ix86L
This directory contains the source code for the processor dependent code (a.k.a. the port) of µC/OS-II for an 80x86 Real-Mode, Large Model processor.
\SOFTWARE\uCOS-II\SOURCE
This directory contains the source code for processor independent portion of µC/OS-II. This code is fully portable to other processor architectures.
1.01 INCLUDES.H
You will notice that every .C file in this book contains the following declaration:
#include "includes.h"
INCLUDES.H allows every .C file in your project to be written without concern about which header file will actually be included. In other words, INCLUDES.H is a Master include file. The only drawback is that INCLUDES.H includes header files that are not pertinent to some of the .C file being compiled. This means that each file will require extra time to compile. This inconvenience is offset by code portability. There is an INCLUDES.H for every example provided in this book. In other words, you will find a
different copy of INCLUDES.H in \SOFTWARE\uCOS-II\EX1_x86L, \SOFTWARE\uCOS-II\EX2_x86L and \SOFTWARE\uCOS-II\EX3_x86L. You
can certainly edit INCLUDES.H to add your own header files.
1.02 Compiler Independent Data Types
Because different microprocessors have different word length, the port of µC/OS-II includes a series of type definitions that ensures portability (see \SOFTWARE\uCOS-II\Ix86L\OS_CPU.H for the
80x86 real-mode, large model). Specifically, µC/OS-II’s code never makes use of C’s short, int and, long data types because they are inherently non-portable. Instead, I defined integer data types that are both portable and intuitive as shown in listing 1.1. Also, for convenience, I have included floating-point data types even though µC/OS-II doesn’t make use of floating-point.
typedef unsigned |
char |
BOOLEAN; |
typedef unsigned |
char |
INT8U; |
typedef signed |
char |
INT8S; |
typedef unsigned |
int |
INT16U; |
typedef signed |
int |
INT16S; |
typedef unsigned |
long |
INT32U; |
typedef signed |
long |
INT32S; |
typedef float |
|
FP32; |
typedef double |
|
FP64; |
#define BYTE |
|
INT8S |
#define UBYTE |
|
INT8U |
#define WORD |
|
INT16S |
#define UWORD |
|
INT16U |
#define LONG |
|
INT32S |
#define ULONG |
|
INT32U |
|
|
Listing 1.1, Portable data types. |
The INT16U data type, for example, always represents a 16-bit unsigned integer. µC/OS-II and your
application code can now assume that the range of values for variables declared with this type is from 0 to 65535. A µC/OS-II port to a 32-bit processor could mean that an INT16U would be declared as an
unsigned short instead of an unsigned int. Where µC/OS-II is concerned, however, it still deals with an INT16U. Listing 1.1 provides the declarations for the 80x86 and the Borland C/C++ compiler as an example.
For backward compatibility with µC/OS, I also defined the data types BYTE, WORD, LONG (and their
unsigned variations). This allows you to migrate µC/OS code to µC/OS-II without changing all instances of the old data types to the new data types. I decided to make this transition and break away from the old style data types because I believe that this new scheme makes more sense and is more obvious. A WORD to some people may mean a 32-bit value whereas I originally intended it to mean a 16-bit value. With the new data types, there should be no more confusion.
1.03 Global Variables
Following is a technique that I use to declare global variables. As you know, a global variable needs to be allocated storage space in RAM and must be referenced by other modules using the C keyword extern. Declarations must thus be placed in both the .C and the .H files. This duplication of declarations, however, can lead to mistakes. The technique described in this section only requires a single declaration in the header file, but is a little tricky to understand. However, once you know how this technique works you will apply it mechanically.
In all .H files that define global variables, you will find the following declaration:
#ifdef xxx_GLOBALS #define xxx_EXT #else
#define xxx_EXT extern #endif
Listing 1.2, Defining global macros.
Each variable that needs to be declared global will be prefixed with xxx_EXT represents a prefix identifying the module name. The module's .C file will contain the
in the .H file. ‘xxx’ following declaration:
#define xxx_GLOBALS #include "includes.h"
When the compiler processes the .C file it forces xxx_EXT (found in the corresponding .H file) to "nothing" (because XXX_GLOBALS is defined) and thus each global variable will be allocated storage space. When the compiler processes the other .C files, xxx_GLOBALS will not be defined and thus xxx_EXT will be set toextern, allowing you to reference the global variable. To illustrate the concept, let's look at uCOS_II.H which contains the following declarations:
#ifdef OS_GLOBALS #define OS_EXT #else
#define OS_EXT extern #endif
OS_EXT |
INT32U |
OSIdleCtr |
OS_EXT |
INT32U |
OSIdleCtrRun; |
OS_EXT |
INT32U |
OSIdleCtrMax; |
uCOS_II.c contains the following declarations:
#define OS_GLOBALS #include “includes.h”
When the compiler processes uCOS_II.C it makes the header file (uCOS_II.H) appear as shown below because OS_EXT is set to "nothing":