Summary of Commonly Used uC/OS-II Functions and Data Structures

Data Structures

    OS_EVENT:

This structure is used in the following functions: OSQCreate(), OSQPend(), OSQPost(), OSSemCreate(), OSSemPend(),OSSemPost().  All of these functions make use of queues to either protect resources or pass messages between tasks. A pointer to the created structure is returned by the two create functions. Once these queues have been created treat the returned pointers as  the head of the queue and always pass the pointer to this structure to the Pend and Post functions as the pevent argument. Traversal is not necessary.

See below for further information regarding the individual functions. Data structure located in file src/uC/ucos_ii.h
typedef struct {
INT8U OSEventType; /* Type of event control block (see OS_EVENT_TYPE_???) */
INT8U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
INT16U OSEventCnt; /* Semaphore Count (not used if other EVENT type) */
void *OSEventPtr; /* Pointer to message or queue structure */
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */
char OSEventName[OS_EVENT_NAME_SIZE]; /* Compile time directive currently has OS_EVENT_NAME_SIZE = 32 */
} OS_EVENT;


#define OS_EVENT_TYPE_UNUSED 0 /* All possible values for OSEventType in OS_EVENT struct */
#define OS_EVENT_TYPE_MBOX 1
#define OS_EVENT_TYPE_Q 2
#define OS_EVENT_TYPE_SEM 3
#define OS_EVENT_TYPE_MUTEX 4
#define OS_EVENT_TYPE_FLAG 5

    OS_STK:

Each task has stack entries of this type. The data structure is located in file src/uC/os_cpu.h

typedef unsigned short OS_STK;                   /* Each stack entry is 16-bit wide                    */

    OS_STK_DATA:

A variable of type OS_STK_DATA is filled in when calling OSTaskStkChk() to get the statistics about the stack of each task. Further information regarding the OSTaskChkTask function is located below. The OS_STK_DATA data structure is located in file src/uC/ucos_ii.h

typedef struct {
INT32U OSFree; /* Number of free bytes on the stack for a specific task */
INT32U OSUsed; /* Number of bytes used on the stack for a specific task*/
} OS_STK_DATA;


   OS_TCB:

A variable of type OS_TCB is filled in when calling OSTaskQuery() to get information about a task. Further information regarding OSTaskQuery is located below. The OS_TCB data structure is located in file src/uC/ucos_ii.h

typedef struct os_tcb{
OS_STK *OSTCBStkPtr; //Stack Pointer void *OSTCBExtPtr; //TCB extension pointer OS_STK *OSTCBStkBottom; //Ptr to bottom of stack INT32U OSTCBStkSize; //Size of task stack (#elements) INT16U OSTCPOpt; //Task options struct os_tcb *OSTCBNext; //Pointer to next TCB struct os_tcb *OSTCBPrev; //Pointer to previous TCB OS_EVENT *OSTCBEventPtr; //Pointer to ECB void *OSTCBMsg; //Message received OS_FLAG_NODE *OSTCBFlagNode; //Pointer to event flag node OS_FLAGS OSTCBFlagsRdy //Event flags that made task ready INT16U OSTCBDly; //Nbr ticks to delay task or, timeout INT8U OSTCBStat; //Task Status INT8U OSTCBPrio; //Task Priority (0 = highest) INT8U OSTCBX; INT8U OSTCBY; INT8U OSTCBBitX; INT8U OSTCBBitY; BOOLEAN OSTCBDelReq; //Flag to tell task to delete itself }OS_TCB;

Global Variables

Most of the global variables for uC/OS-II are located in file src/uC/ucos_ii.h. Do not modify these globals. Reading from them is necessary for some exercises in the labs.

OS_EXT  INT8S             OSCPUUsage;               /* Percentage of CPU used                          */

Vector Table Entries

Initialize vector table entry #0 with the pointer of the context switching function. This function will be called on every context switch. Initialize the table before doing anything else. Without the context switching vector (TRAP # 0) pointing to the correct function uC/OS-II will not function correctly. The context switching function OSCtxSw() is located in file src/uC/os_cpu_a.s  This is given to you. DO NOT modify the code that moves the Trap location into the vector table.



*((int *)0x80) = (int)OSCtxSw; /* set up vector to Context Switch (TRAP #0) */

Initialization Functions

    OSInit()

Function Prototype
Arguments
Returns
Notes
void OSInit(void);

Location:
src/uC/os_core.c
none
nothing
Call this function first inside your begin() function. Initializes uC/OS-II and must be called before calling OSStart()

Example:
   
begin (void)    			/* SYSTEM ENTRY POINT */
{
    *((int *)0x80) = (int)OSCtxSw;	/* set up vector to Context Switch (TRAP #0) */
OSInit();
.
.
OSStart(); /* away we go ! */
}

       
    OSStart()

Function Prototype
Arguments
Returns
Notes
void OSStart(void);

Location:
src/uC/os_core.c
none
nothing
OSStart begins the multitasking. Call this as a part of your initialization function but make sure that you have called OSInit() first.

Example:
   
begin (void)    			/* SYSTEM ENTRY POINT */
{
    *((int *)0x80) = (int)OSCtxSw;	/* set up vector to Context Switch (TRAP #0) */
OSInit();
.
.
OSStart(); /* away we go ! */
}


    OSStatInit()

Function Prototype
Arguments
Returns
Notes
void OSStatInit(void);

Location:
src/uC/os_core.c
none
nothing
If CPU stats are required, this function must be called. It must be called from the first and only task created. This first and only task may,in turn, create other tasks once OSStatInit has been called.

Example:

begin (void)    			/* SYSTEM ENTRY POINT */
{
*((int *)0x80) = (int)OSCtxSw; /* set up vector to Context Switch (TRAP #0) */
OSInit();
TaskCreate("StartTask",StartTask,StartTask_ID);
OSStart(); /* away we go ! */
}

void StartTask(void *data)
{
ScopeInit(); /* Initialize oscilloscope triggering routine */
TickInit(); /* Start OS ticker, see os/os_cpu_a.s */
OSStatInit(); /* Initialize statistics task */
OSTaskCreateExt(...); /* all clear to call tasks now */
OSTaskCreateExt(...);
.
.
.
OSTaskDel(OS_PRIO_SELF); /* This task only runs once */
}


Task Functions

    OSTaskCreateExt()

Function Prototype
Arguments
Returns
Notes
INT8U
OSTaskCreateExt
(void(*task)(void*pd),
void *pdata,
OS_STK *ptos,
INT8U prio,
INT16U id,
OS_STK *pbos,
INT32U stk_size,
void *pext,
INT16U opt ) ;

Location:
src/uC/os_task.c
task
Pointer to task's code that must be declared as void Task (void *)

pdata
Pointer to data that is passed to task when it is created

ptos
Pointer to the top of the task's stack. For stacks that grow down in memory ptos needs to point to the highest valid memory location on the stack.

prio
Unique priority to assign to this task. The lower the number the higher the priority.

id
Task's ID number which is not currently used. Set this to the priority of the task.

pbos
Pointer to the bottom of the task's stack. For stacks that grow downward in memory pbos must point to the lowest valid stack location.

stk_size
Number of 16 bit entries available on the stack. See typedef of OS_STK  in src/uC/os_cpu.h and above.

pext
Pointer to a user supplied memory location used as TCP extension. User defined location or data structure.

opt
Options for the task created. Lower 8 bits are reserved for uC/OS-II but applications may use the upper 8 bits for application specific options. Possible uC/OS-II predefined options are:
OS_TASK_OPT_STK_CHK
Specifies whether stack checking is allowed for the task
OS_TASK_OPT_STK_CLR
Specifies whether the stack need to be cleared
OS_TASK_OPT_SAVE_FP
N/A we have no floating point registers on our CPU32
One of the following error codes:

OS_NO_ERR
Function was successful in creating the task

OS_PRIO_EXIST
A task already exists with that priority. In uC each task must have a unique priority

OS_PRIO_INVALID
prio is higher than OS_LOWEST_PRIO, currently set to 63

OS_NO_MORE_TCB
uC has run out of OS_TCBs to assign
Stack must be declared as type OS_STK

At some point during the execution of the task one of the services offered by uC/OS-II must be called to wait for time to expire, suspend the task or wait for an event like a mailbox or semaphore. Otherwise the task may never cede the processeor and other tasks with lower priorities may never get a time slice. uC/OS-II is not a round robin OS. Consequently, all task must eventually cede for all task to get servicing.

Don't assign user tasks priorities 0, 1, 2, 3, OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2, OS_LOWEST_PRIO-1, or OS_LOWEST_PRIO. These are reserved by uC/OS-II. The other 56 application tasks are therefore available.

Example:

	#define TASK_OPT	OS_TASK_OPT_STK_CHK + OS_TASK_OPT_STK_CLR

	void TaskCreate(char *TaskDesc, void *TaskFunc, INT8U TaskID)
{
INT8U err;
err=OSTaskCreateExt(TaskFunc,
(void *)0,
&TaskStack[TaskID][TASK_STACK_SIZE-1],
TaskID+5,
TaskID,
&TaskStack[TaskID][0],
TASK_STACK_SIZE,
&TaskData[TaskID],
TASK_OPT);

if (!err)
strcpy(TaskData[TaskID].TaskName, TaskDesc);
else
disp_err(err);
}


    OSTaskDel()

Function Prototype
Arguments
Returns
Notes
INT8U OSTaskDel
(INT8U prio) ;

Location:
src/uC/os_task.c
prio
priority number of the task to be deleted.
OS_NO_ERR
Call was successful

OS_TASK_DEL_IDLE
This value is returned if you attempt to delete the idle task, this is not permitted

OS_TASK_DEL_ERR
Task to be deleted does not exist.

OS_PRIO_INVALID
prio is higher than OS_LOWEST_PRIO.

OS_TASK_DEL_ISR
This value is returned if you attempt to delete a task from an ISR.

Specify  the priority of the task to be deleted or pass in OS_PRIO_SELF if priority of task is unknown. This task's code is not actually removed but the task is placed in the dormant state and can be recreated and made active by calling OSTaskCreate or OSTaskCreateExt.

Be careful when deleting a task that owns associated resources.  If a task owns resources like mailboxes, semaphores etc. call OSTaskDelReq() instead to deal with those issues safely.

Example:

	void StartTask(void *data)
{
ScopeInit(); /* Initialize oscilloscope triggering routine */
TickInit(); /* Start OS ticker, see src/uC/os_cpu_a.s */
OSStatInit(); /* Initialize statistics task */
LEDQueue = OSQCreate (LEDQueueTbl, 10);
.
.
.
OSTaskDel(OS_PRIO_SELF); /* We don't want the Start ask to run more than once */
}


    OSTaskStkChk()

Function Prototype
Arguments
Returns
Notes
INT8U
OSTaskStkChk (INT8U prio, OS_STK_DATA *pdata);

Location:
src/uC/os_task.c
prio
priority number of the task about which you want stack information. If the value OS_PRIO_SELF is passed then the stack of the calling task is checked.

pdata
pointer to a variable of type OS_STK_DATA that is used by the function
OS_NO_ERR
Call was successful

OS_PRIO_INVALID
prio is higher than OS_LOWEST_PRIO or not equal to OS_PRIO_SELF

OS_TASK_NOT_EXIST
Specified task does not exist

OS_TASK_OPT_ERR
this value is returned if the task was created by OSTaskCreate or if OS_TASK_OPT_STK_CHK was not specified when the OSTaskCreateExt call was used.
Execution time for this task depends on the size of the stack for each task and is, therefore, nondeterministic.

To calculate the total stack size used add .OSFree and .OSUsed together. Currently, all of the stacks in the labs are the same size (= 512 bytes).

Don't call this function inside an ISR due to its nondeterministic nature and possible length of time for completion.

Example:

    	OS_STK_DATA   StackData;    	
INT8U         err;
	err = OSTaskStkChk(OS_PRIO_SELF,&StackData);
   
OSTaskQuery()
Function Prototype
Arguments
Returns
Notes
INT8U
OSTaskQuery
(INT8U prio, OS_TCB *pdata);

Location:
src/uC/os_q.c
prio
priority number of the task about which you want task information. If the value OS_PRIO_SELF is passed then the stack of the calling task is checked.

pdata
pointer to a structure of type OS_TCB, which contains a copy of the task's control block
OS_NO_ERR
Call was successful

OS_PRIO_ERR
Attempt to obtain information from an invalid task

OS_PRIO_INVALID
prio is higher than OS_LOWEST_PRIO or not equal to OS_PRIO_SELF

You must allocate an OS_TCB structure before calling this function, and passing the pointer in as a parameter. Your copy obtains a snapshot of the desired task's control block.

DO NOT modify any of the fields in the OS_TCB control blocks. Reading them is sufficient for the labs in CMPE401.

Example:

    	OS_TCB    task_data;    	
INT8U     err;
	err = OSTaskQuery(OS_PRIO_SELF,&task_data);

Queue Functions

    OSQCreate()

Function Prototype
Arguments
Returns
Notes
OS_EVENT *
OSQCreate
(void **start, INT16U size);

Location:
src/uC/os_q.c
start
base address of storage area

size
number of elements in the storage area
A pointer to the event control block allocated to the queue is returned if the call succeeds. If it fails a NULL pointer is returned.
Always create queues before using them.

Generally, queues are created for intertask communication. One task posts a message and another task retrieves it. Otherwise race conditions could result and cause many potential problems if tasks attempt to simultaneously access common resources.

Example:

	begin (void)
{
*((int *)0x80) = (int)OSCtxSw; /* set up vector to Context Switch (TRAP #0) */
OSInit();
TaskCreate("StartTask",StartTask,StartTask_ID);
OSStart();
}

void StartTask(void *data)
{
ScopeInit();
TickInit();
.
.
TxQueueA = OSQCreate (TxQueueTblA, FIFO_SIZE);
TxQueueB = OSQCreate (TxQueueTblB, FIFO_SIZE);

.
.
OSTaskDel(OS_PRIO_SELF); /* This task only runs once */
}


    OSQPend()

Function Prototype
Arguments Returns Notes
void *
OSQPend
(OS_EVENT *pevent, INT16U timeout, INT8U * err) ;

Location:
src/uC/os_q.c
pevent
Pointer to queue from which the message is to be recieved.  This is the same pointer that was returned when the queue was created using OSQCreate()

timeout
Pass in 0 if you want to wait forever for a message. Pass a value in ticks (0 - 65535) to give up on receiving the message after the period has lapsed. The function will return and the task will resume once the number of ticks has expired.

err
OS_NO_ERR
Message was received

OS_TIMEOUT
Message was not received withing the specified timeout.

OS_ERR_EVENT_TYPE
pevent is not pointing to a message queue

OS_ERR_PEVENT_NULL
pevent is a NULL pointer

OS_ERR_PEND_ISR
This function was called from an ISR and uC/OS-II must suspend the task. To avoid this don't call this function from an ISR.
If successful OSQPend returns a message sent by a task and *err contains OS_NO_ERR. If unsuccessful a NULL pointer is returned and *err contains one of the error codes as specified in the arguments field.
Always create queues before using them and don't call this function from inside an ISR

Messages are placed in the queue by one task and retreived by another.

Call this function to retrieve possible messages.

If multiple tasks are waiting for a message the highest priority task is resumed.

Example:

	LedQueueData = *(LED_DATA *)OSQPend(LEDQueue, 0, &err);  /* this will block until a queue entry is available */
if (err)
disp_err(err);


    OSQPost()

Function Prototype
Arguments
Returns
Notes
INT8U
OSQPost
(OS_EVENT *pevent, void *msg) ;

Location:
src/uC/os_q.c
pevent
Pointer to the queue into which the message is deposited. Use the pointer that was returned when the queue was created using OSQCreate()

msg
Pointer- sized variable that is user defined. Don't post a NULL pointer.
OS_NO_ERR
Message was deposited in the queue.

OS_Q_FULL
No room in the queue.

OS_ERR_EVENT_TYPE
pevent is not pointing to a message queue.

OS_ERR_PEVENT_NULL
pevent is a NULL pointer.

OS_ERR_POST_NULL_PTR
msg is a NULL pointer.

Always create Queues before using them and never pass in NULL pointers as arguments.

Use this function to send a message to another task via a previously created queue.

If multiple tasks are waiting for a message the highest priority task is resumed.

Example:

	void LedBufferPost(char num, char state)
{
INT8U err;
if (LedBufferIndex >=10)
LedBufferIndex=0;
LedBuffer[LedBufferIndex].LedNum = num;
LedBuffer[LedBufferIndex].State = state;
err = OSQPost(LEDQueue, (void *)&LedBuffer[LedBufferIndex++]);
}

Semaphore Functions

    OSSemCreate()

Function Prototype
Arguments Returns Notes
OS_EVENT* OSSemCreate
(INT16U value);

Location:
src/uC/os_sem.c
value
Initial value of the semaphore that can be from 0 - 65536. Pass in 0 to indicate that the resource is not available.
OSSemCreate returns the created event control block if the function succeeds. If it fails OSSemCreate returns a NULL pointer
Always create semaphores before using them.

When creating semaphores the value indicates how many tasks can obtain the semaphore concurrently. Pass in 1 if the semaphore is protecting a single resource (ie. a memory location). If there is more than one resource available (ie. a block of structures that can be assigned) then pass in that number.

Example:

	OS_EVENT *TxSemA, *TxSemB, *TxBufferLock;

void StartTask(void *data)
{
ScopeInit();
TickInit();
TxSemA = OSSemCreate(0);
TxSemB = OSSemCreate(0);
TxBufferLock = OSSemCreate(1);

.
.
DuartInit();
OSTaskDel(OS_PRIO_SELF); /* This task only runs once */
}


    OSSemPend()

Function Prototype
Arguments Returns Notes
void
OSSemPend
(OS_EVENT *pevent,
INT16U timeout,
INT8U *err)

Location:
src/uC/os_sem.c
pevent
Pointer to the semaphore. This was returned when the semaphore was created with OSSemCreate()

timeout
Pass in 0 if you want to wait forever for a message. Pass a value in ticks (0 - 65535) to give up on receiving the message after the period has lapsed. The function will return and the task will resume once the number of ticks has expired.

err
OS_NO_ERR
Semaphore is available

OS_TIMEOUT
Semaphore was not obtained withing the specified timeout.

OS_ERR_EVENT_TYPE
pevent is not pointing to a semaphore

OS_ERR_PEVENT_NULL
pevent is a NULL pointer

OS_ERR_PEND_ISR
This function was called from an ISR and uC/OS-II must suspend the task. To avoid this don't call this function from an ISR.
nothing
Always create semaphores before using them.

Call this function when a task needs to use a shared resource safely, is waiting for an event,or needs to synchronize its activities with an ISR or a task.

Note that this call blocks while waiting for the semaphore to be free. Don't use this function from an ISR use the non-blocking OSSemAccept instead()

Example:
	void TxTask1 (void *data)	/* send the uppercase alphabet to TxA */
	{
char byte;
char err;
while(1)
{
byte=0x41;
OSSemPend(TxBufferLock, 0, &err);
while (byte <= 0x5A)
TxBufferPost(0, byte++);
TxBufferPost(0, CR);
TxBufferPost(0, LF);
OSSemPost(TxBufferLock);
OSTimeDly(64);
}
}



    OSSemPost()

Function Prototype
Arguments
Returns
Notes
INT8U
OSSemPost
(OS_EVENT *pevent);

Location:
src/uC/os_sem.c
pevent
Pointer to the semaphore. This was returned when the semaphore was created with OSSemCreate()

OS_NO_ERR
Semaphore has been signalled or released.

OS_SEM_OVF
Semaphore counts has overflowed (> 65535).

OS_ERR_EVENT_TYPE
pevent is not pointing to a semaphore

OS_ERR_PEVENT_NULL
pevent is a NULL pointer
Always create semaphores before using them.

Calling this function will signal, or release the semaphore so that another task can obtain it. If the value is 0 or greater the value is incremented and the function returns to the caller.



Example:

	void TxTask1 (void *data)	/* send the uppercase alphabet to TxA */
	{
char byte;
char err;
while(1)
{
byte=0x41;
OSSemPend(TxBufferLock, 0, &err);
while (byte <= 0x5A)
TxBufferPost(0, byte++);
TxBufferPost(0, CR);
TxBufferPost(0, LF);
OSSemPost(TxBufferLock);
OSTimeDly(64);
}
}

Time Functions

    OSTimeDly()

Function Prototype Arguments Returns
Notes
void OSTimeDly
(INT16U ticks) ;

Location:
src/uC/os_time.c
ticks
Number of clock ticks to delay the current task. (0 - 65,535)  (see OS_TICKS_PER_SEC in configuration file src/uC/os_cfg.h)
nothing
Use this function to reschedule a task for a later time. Calling the function with all parameters set to zero simply returns to the caller immediately.

Example:

	while(1)
{
/* One second = 64 ticks*/
OSTimeDly(64);
}


    OSTimeDlyHMSM()

Function Prototype Arguments Returns
Notes
void
OSTimeDlyHMSM
(INT8U hours,
INT8U minutes,
INT8U seconds, INT8U milli) ;


Location:
src/uC/os_time.c
hours  
Number of hours of delay (0 - 255)

minutes  
Number of minutes of delay (0 - 59)

seconds
Number of seconds of delay (0 - 59)

milli
Number of milliseconds of delay (0 - 999).  milliseconds are rounded to nearest number of ticks so be careful. Be aware of tick rate when only using milliseconds. If the number of milliseconds passed in is smaller that one tick the delay may not occur at all.
OS_NO_ERR
Call was successful

OS_TIME_INVALID_MINUTES
Minutes argument is greater than 59

OS_TIME_INVALID_SECONDS
Seconds argument is greater than 59

OS_TIME_INVALID_MILLI
Milliseconds argument is greater than  999

OS_TIME_ZERO_DLY
All arguments are given as zero
Use this function to reschedule the task for a later time. Calling the function with all parameters set to zero simply returns to the caller immediately.

Example:

	while(1)
{
LEDValue = *(char *)OSQPend(LEDQueue, 0, &err);
if (err)
disp_err(err);
led_current |= LEDValue;
*LED = led_current;
OSTimeDlyHMSM(0,0,0,50);
led_current &= ~LEDValue;
*LED = led_current;
}


References:

Last Modified by Nancy Minderman September 13, 2004